<?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>Tech</tabi:current_section>
    </tabi:metadata><title>Coded Chords - Tech</title>
        <subtitle>A personal blog</subtitle>
    <link href="https://codedchords.dev/tags/tech/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://codedchords.dev/tags/tech/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-09-08T00:00:00+00:00</updated><id>https://codedchords.dev/tags/tech/atom.xml</id><entry xml:lang="en">
        <title>ターミナルのフォントを整える(2026年版)</title>
        <published>2026-09-07T13:04:27+09:00</published>
        <updated>2026-09-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/09/berkeley-sarasa/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/09/berkeley-sarasa/</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;09&amp;#x2F;berkeley-sarasa&amp;#x2F;cover.avif?h=e6742ea80c429effb2d4&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;ターミナルの欧文フォントには、&lt;a href=&quot;&#x2F;blog&#x2F;2024&#x2F;12&#x2F;berkeley-mono&#x2F;&quot;&gt;以前の記事&lt;&#x2F;a&gt;で書いたとおり
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;Berkeley Mono&lt;&#x2F;a&gt; を使い続けています。
ただしBerkeley Monoは日本語のグリフを持たないため、日本語は別のフォントにフォールバックさせる必要があります。
このフォールバックの設定を、思いつきで書くのではなく実測して組み直しました。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;WezTerm_のフォント設定の最終構成&quot;&gt;WezTerm のフォント設定の最終構成&lt;&#x2F;h2&gt;
&lt;p&gt;結論を先に書くと、欧文がBerkeley Mono、全角が更紗ゴシック、アイコンがSymbols Nerd Font Monoという
3段構成に落ち着きました。全角文字がちょうど2セルに収まり、&lt;code&gt;①&lt;&#x2F;code&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;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;Berkeley Mono（静的版）&lt;&#x2F;td&gt;&lt;td&gt;セル幅 0.600 em&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;全角&lt;&#x2F;td&gt;&lt;td&gt;更紗ゴシック（Sarasa Term J）&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;scale = 1.2&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;Symbols Nerd Font Mono 3.5.1&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;font_size&lt;&#x2F;code&gt; は20.0です。ターミナルは文字を等幅のマス目に並べて表示します。
欧文1文字がマス目1つ、日本語1文字はマス目2つにちょうど収まらないと表示が崩れるため、
サイズは自由に選べません。20.0はその条件を満たす値です。詳しくは後述します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;文字の送り幅をどう測ったか&quot;&gt;文字の送り幅をどう測ったか&lt;&#x2F;h2&gt;
&lt;p&gt;ターミナルのフォント設定は、見た目で判断すると微妙なズレを見逃します。
そこで2つの道具で数値を取りました。測る対象は送り幅、
つまり1文字を描いたあと次の文字の位置までカーソルが進む距離です。&lt;&#x2F;p&gt;
&lt;p&gt;ひとつはfontToolsです。フォントファイルそのものを読み、&lt;code&gt;hmtx&lt;&#x2F;code&gt; テーブルから
送り幅を取り出します。フォントと文字を並べて一度に測りました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot; data-name=&quot;probe.py&quot;&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; fontTools&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;ttLib&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; TTFont&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; pathlib&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; Path&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;# ttc は fontNumber でフェイスを選ぶ。220 は Sarasa Term J Regular&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;FONTS&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&quot;&gt;    (&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Berkeley Mono Regular&amp;quot;&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;quot;BerkeleyMono-Regular.otf&amp;quot;&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;&#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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Sarasa Term J Regular&amp;quot;&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;quot;Sarasa-SuperTTC.ttc&amp;quot;&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; 220&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-source&quot;&gt;CHARS&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;quot;A&amp;quot;&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; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;41&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;quot;あ&amp;quot;&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; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3042&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;quot;①&amp;quot;&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; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2460&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-keyword z-control z-flow z-python&quot;&gt;for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; index&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; FONTS&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;    f&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; TTFont&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;Path&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;home&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; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Library&#x2F;Fonts&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; name&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; fontNumber&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-arguments z-python&quot;&gt;index&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; lazy&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    upem&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-indexed-name z-python&quot;&gt; f&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-string&quot;&gt;head&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-source&quot;&gt;unitsPerEm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cmap&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; f&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;getBestCmap&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;    cols&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-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; CHARS&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;        gid&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; cmap&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;get&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;cp&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;        adv&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 z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&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-indexed-name z-python&quot;&gt;f&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;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&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;gid&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-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; upem&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;:.3f&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; em&amp;quot;&lt;&#x2F;span&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; gid&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string 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-source&quot;&gt;        cols&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;append&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;&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;char&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;adv&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;:&amp;gt;8&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;    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;&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;label&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;:24&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-keyword z-operator&quot;&gt; +&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;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-meta z-function-call z-arguments z-python&quot;&gt;cols&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;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;Berkeley Mono Regular   A 0.600 em  あ        -  ①        -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sarasa Term J Regular   A 0.500 em  あ 1.000 em  ① 0.500 em&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;emは文字サイズを1とした単位なので、この値はフォントサイズに左右されない設計値です。
Berkeley Monoは &#x27;A&#x27; を0.600 emで送り、日本語のグリフは持ちません。
更紗ゴシックは半角が0.500 em、全角が1.000 emで、&lt;code&gt;①&lt;&#x2F;code&gt; は半角側です。
2つのフォントは幅の基準そのものが違う、というのがここで分かります。&lt;&#x2F;p&gt;
&lt;p&gt;もうひとつはWezTerm自身の &lt;code&gt;ls-fonts&lt;&#x2F;code&gt; です。こちらは「設定を与えたときに実際にどのファイルの
どのフェイスが選ばれ、送り幅がいくつになるか」を返します。&lt;code&gt;--codepoints&lt;&#x2F;code&gt; には
調べたい文字をUnicodeのコードポイントで渡します。&lt;code&gt;41&lt;&#x2F;code&gt; はU+0041の &#x27;A&#x27;、
&lt;code&gt;3042&lt;&#x2F;code&gt; はU+3042、ひらがなの「あ」です。ここで読み込む &lt;code&gt;test.lua&lt;&#x2F;code&gt; は、
Berkeley Monoと更紗ゴシックを並べただけの素の設定です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;check.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --config-file .&#x2F;test.lua ls-fonts --codepoints 41,3042&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&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;0 A  \u{41}   x_adv=12 cells=1 wezterm.font(&amp;quot;Berkeley Mono&amp;quot;, ...)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1 あ \u{3042} x_adv=20 cells=2 wezterm.font(&amp;quot;Sarasa Term J&amp;quot;, ...)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;上記の結果から次のことがわかります。&lt;&#x2F;p&gt;
&lt;p&gt;&#x27;A&#x27; はBerkeley Monoから取られ、送り幅を表す &lt;code&gt;x_adv&lt;&#x2F;code&gt; は12ピクセル、占める幅は &lt;code&gt;cells=1&lt;&#x2F;code&gt; で1セルです。ここから1セルの幅が12ピクセルだと実測で分かります。「あ」は更紗ゴシックから取られ、&lt;code&gt;cells=2&lt;&#x2F;code&gt; は2セルを占めるべき文字だというWezTermの判定です。2セルなら24ピクセル必要なのに、&lt;code&gt;x_adv&lt;&#x2F;code&gt; は20ピクセルしかありません。4ピクセル足りない状態です。この4ピクセルをどう埋めるかが次節の話になります。ここがズレたままだと日本語混じりの表や罫線が崩れます。&lt;&#x2F;p&gt;
&lt;p&gt;フォントファイルの設計値と、WezTermが実際に採用する値は一致しないことがあるため、
この2つを突き合わせる必要がありました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;全角を正確に2セルへ&quot;&gt;全角を正確に2セルへ&lt;&#x2F;h2&gt;
&lt;p&gt;更紗ゴシックは半角0.500 em、全角1.000 emという厳密なグリッドを持っています。
一方Berkeley Monoのセル幅は0.600 emです。セルの幅はBerkeley Monoに合わせるため、
全角が収まるべき2セルは1.200 emになります。更紗ゴシックの全角は1.000 emなので、
そのまま並べると0.200 em足りません。&lt;&#x2F;p&gt;
&lt;p&gt;WezTermの &lt;code&gt;scale&lt;&#x2F;code&gt; は、フォールバックさせるフォントを何倍で描くかを指定します。
0.500 × 1.2 = 0.600なので、&lt;code&gt;scale = 1.2&lt;&#x2F;code&gt; にすれば更紗ゴシックの半角がBerkeleyのセル幅と一致し、
全角はその2倍になります。総当たりで確認しました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;scale&lt;&#x2F;th&gt;&lt;th&gt;セル幅&lt;&#x2F;th&gt;&lt;th&gt;&lt;code&gt;あ&lt;&#x2F;code&gt;（要24）&lt;&#x2F;th&gt;&lt;th&gt;&lt;code&gt;①&lt;&#x2F;code&gt;（要12）&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1.1&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1.15&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;23&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1.2&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;24&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;12&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1.25&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ここで厄介なのが、WezTermがセル幅を整数に丸めることです。
&lt;code&gt;0.600 × font_size&lt;&#x2F;code&gt; が整数から離れると、丸めの誤差でグリッドが崩れます。
&lt;code&gt;font_size&lt;&#x2F;code&gt; を振って確かめたところ、成立するサイズは限られていました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;font_size&lt;&#x2F;th&gt;&lt;th&gt;セル幅&lt;&#x2F;th&gt;&lt;th&gt;&lt;code&gt;あ&lt;&#x2F;code&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;code&gt;①&lt;&#x2F;code&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;16.0&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;19&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;全角が1px不足&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;18.0&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;ぴったり&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;19.0&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;23&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;1px超過&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;20.0&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;24&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;ぴったり&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;21.0&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;全角が1px不足&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;22.0&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;26&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;ぴったり&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;24.0&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;29&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;1px超過&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;code&gt;font_size = 20.0&lt;&#x2F;code&gt; を選んでいるのはこのためです。18.0と22.0も使えますが、
21.0や24.0に動かすと桁がずれます。⌘+ と ⌘− でサイズを変える運用をしていると
崩れる場面があるので、この事情は設定ファイルにコメントとして残しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Ambiguous_幅と漢字カバレッジ&quot;&gt;Ambiguous 幅と漢字カバレッジ&lt;&#x2F;h2&gt;
&lt;p&gt;日本語フォントなら何でもよいわけではありません。決定的なのはEast Asian Ambiguous、
つまり半角と全角のどちらとも解釈しうる文字の扱いです。
&lt;code&gt;①②③&lt;&#x2F;code&gt;、&lt;code&gt;◆&lt;&#x2F;code&gt;、&lt;code&gt;※&lt;&#x2F;code&gt; あたりが該当します。&lt;&#x2F;p&gt;
&lt;p&gt;Ambiguousは、UnicodeのEast Asian Widthプロパティで &lt;code&gt;A&lt;&#x2F;code&gt; に分類される文字です。
狭幅と広幅のどちらにも解決されうる、という分類までがUnicodeの担当で、
どちらに倒すかを決めるのは端末です。WezTermには
&lt;code&gt;treat_east_asian_ambiguous_width_as_wide&lt;&#x2F;code&gt; という設定があります。既定は &lt;code&gt;false&lt;&#x2F;code&gt;、
つまり1セルとして数えます。したがって「半角が正しい」のではなく、
端末の数え方とフォントの字幅が一致していることが要件になります。
端末が1セルと数えているのに字が2セル分あると、隣にはみ出すだけでは済みません。
カーソルの桁数は1のまま進むので、以降の再描画で端末が消したつもりの位置と
実際に塗られた位置が1桁ずれ、消し残りや行の崩れになります。&lt;&#x2F;p&gt;
&lt;p&gt;では全角側に倒せばよいかというと、こちらも通りません。
Ambiguousに含まれるのは丸数字や記号だけではないからです。
罫線の &lt;code&gt;─│┌&lt;&#x2F;code&gt;、矢印の &lt;code&gt;→&lt;&#x2F;code&gt;、&lt;code&gt;°&lt;&#x2F;code&gt; や &lt;code&gt;±&lt;&#x2F;code&gt;、ギリシャ文字とキリル文字、
そしてNerd Fontのアイコンやpowerlineの区切りにも、ここに属するものが多くあります。
これらの多くがUnicodeの私用領域を使っており、私用領域は &lt;code&gt;E000..F8FF&lt;&#x2F;code&gt; が丸ごとAmbiguousだからです。
&lt;code&gt;treat_east_asian_ambiguous_width_as_wide = true&lt;&#x2F;code&gt; を指定すると、これらは一斉に2セル幅へ変わります。
プロンプトの区切りとアイコン、&lt;code&gt;tree&lt;&#x2F;code&gt; や &lt;code&gt;gh&lt;&#x2F;code&gt; の引く枠線まで、横幅は倍になります。
&lt;code&gt;①&lt;&#x2F;code&gt; を正しく出すためにプロンプトと罫線を組み直すのは割に合わないので、半角側に倒します。
コードポイント範囲ごとに幅を指定する &lt;code&gt;cell_widths&lt;&#x2F;code&gt; を使えば私用領域だけを全角へ固定できますが、
これはnightlyビルド限定の設定で、手元の安定版20240203-110809-5046fc22は受け付けませんでした。
Vimの &lt;code&gt;ambiwidth=double&lt;&#x2F;code&gt; に代表される全角前提の設定は、日本語環境では長く標準でした。
常時目に入る文字の中身がこれだけ変わった今は、半角側のほうが破綻は少なくなっています。&lt;&#x2F;p&gt;
&lt;p&gt;macOS標準のヒラギノ角ゴシックは、これらを全角で設計しています。
手元の構成で測ると、セル幅12に対して送り幅は13.75でした。
25パーセントはみ出して隣の文字と干渉します。しかもこれは &lt;code&gt;scale&lt;&#x2F;code&gt; を振っても変わりませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;更紗ゴシック（Sarasa Term J）は、Ambiguousを半角として設計した系統です。
&lt;code&gt;①&lt;&#x2F;code&gt; と &lt;code&gt;◆&lt;&#x2F;code&gt; はどちらも0.500 emで、&lt;code&gt;scale = 1.2&lt;&#x2F;code&gt; を掛けてちょうど1セルに収まります。
同じ更紗ゴシックでも &quot;Mono&quot; 系統はAmbiguousが全角なので、ターミナルには &quot;Term&quot; を選ぶ必要があります。&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;JIS X 0208&lt;&#x2F;th&gt;&lt;th&gt;JIS X 0213&lt;&#x2F;th&gt;&lt;th&gt;Unicode CJK統合漢字&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Sarasa Term J&lt;&#x2F;td&gt;&lt;td&gt;100 %&lt;&#x2F;td&gt;&lt;td&gt;100 %&lt;&#x2F;td&gt;&lt;td&gt;100 %&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ヒラギノ角ゴ Sans W3&lt;&#x2F;td&gt;&lt;td&gt;100 %&lt;&#x2F;td&gt;&lt;td&gt;85.3 %&lt;&#x2F;td&gt;&lt;td&gt;51.3 %&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ヒラギノの51.3パーセントという数字は一見すると低く見えますが、
UnicodeのCJK統合漢字ブロックは日本語・簡体字・繁体字・韓国・ベトナムの漢字を
すべて含む集合なので、日本語フォントの評価軸としては適切ではありません。
PythonのShift_JISコーデックで判定したところ、ヒラギノに無い1万225字のうち
JIS X 0208に含まれるものは0字でした。常用漢字と人名用漢字は完全にカバーしています。&lt;&#x2F;p&gt;
&lt;p&gt;なおmacOS全体では、標準フォントを合わせるとCJK統合漢字を100パーセント表示できます。
ただし日本語フォントに無い字はHiragino Sans GB（簡体字）やHeiti TC（繁体字）に落ちるため、
表示はされても字形が中国字体になります。更紗ゴシックを使うと、この落下自体が起きません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Nerd_Font_はシンボル専用フォントで足りる&quot;&gt;Nerd Font はシンボル専用フォントで足りる&lt;&#x2F;h2&gt;
&lt;p&gt;以前はNerd Fontのアイコンを、パッチ済みの日本語フォントから取っていました。
しかしアイコンのためだけに日本語フォントを1本抱えるのは無駄です。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ryanoasis&#x2F;nerd-fonts&quot;&gt;nerd-fonts&lt;&#x2F;a&gt; には
シンボルだけを収録したフォントがあり、Homebrewから入ります。&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 --cask font-symbols-only-nerd-font&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;実はWezTermにはSymbols Nerd Font Monoが同梱されていて、
何もしなくてもフォールバック連鎖の末尾に入っています。
アイコンの解決先を29点サンプリングしたところ、23点が内蔵フォントで解決し、
Powerlineの区切りはWezTerm自身が描画していました。
豆腐になったのは &lt;code&gt;U+E6B5&lt;&#x2F;code&gt; と &lt;code&gt;U+EC1E&lt;&#x2F;code&gt; の2点だけです。&lt;&#x2F;p&gt;
&lt;p&gt;つまり多くの場合は内蔵で足ります。それでも単体版を入れたのは、
内蔵版が古いビルドで上記2点が欠けていたためです。
インストール版がCoreText経由で優先されることと、欠けていた2字が埋まることは確認しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;更紗ゴシックとは&quot;&gt;更紗ゴシックとは&lt;&#x2F;h2&gt;
&lt;p&gt;更紗ゴシックはRenzhi Li（Belleve Invis）氏によるOFL-1.1のフォントです。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;typeof.net&#x2F;Iosevka&#x2F;&quot;&gt;Iosevka&lt;&#x2F;a&gt; の作者でもあります。&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;Copyright (c) 2015-2025, Renzhi Li (aka. Belleve Invis, belleve@typeof.net).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Portions Copyright (c) 2016 The Inter Project Authors.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Portions Copyright (c) 2014-2021 Adobe Systems Incorporated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Portions Copyright (c) 2012 Google Inc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Adobeが源ノ角ゴシック（Source Han Sans）、GoogleがNoto Sans CJKです。
つまり更紗ゴシックの漢字とかなは源ノ角ゴシックそのもので、
作者の仕事はIosevkaの欧文と合成し、半角と全角を厳密に1:2のグリッドへ再設計することでした。
今回の構成では欧文をBerkeley Monoが担当するので、更紗ゴシックは実質的に
「ターミナル用に幅を再設計した源ノ角ゴシック」として働いています。&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 style=&quot;text-align: right&quot;&gt;源ノ角ゴシック JP&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;更紗ゴシック Term J&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;①&lt;&#x2F;code&gt; &lt;code&gt;◆&lt;&#x2F;code&gt; &lt;code&gt;※&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;1.000 em&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.500 em&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;─&lt;&#x2F;code&gt; &lt;code&gt;→&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;1.000 em&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.500 em&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;°&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.370 em&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.500 em&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;α&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.625 em&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.500 em&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;あ&lt;&#x2F;code&gt; &lt;code&gt;漢&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;1.000 em&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;1.000 em&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;源ノ角ゴシックはAmbiguousを全角に置き、&lt;code&gt;°&lt;&#x2F;code&gt; や &lt;code&gt;α&lt;&#x2F;code&gt; は字ごとの固有幅を持ちます。
一般の文書組版としては妥当ですが、前述のAmbiguousの条件は満たしません。
更紗ゴシックのTerm系統はこれらをすべて0.500 emへ揃えています。
かなと漢字の字形が同じでも、ターミナルで使えるかどうかはこの一点で分かれます。&lt;&#x2F;p&gt;
&lt;p&gt;Iosevka自体もコード用のフォントとしては高く評価されています。文字幅が狭いので、老眼にはつらいのですが多くの情報を表示できるので好まれているようです。&lt;&#x2F;p&gt;
&lt;p&gt;&quot;J&quot; は日本語字形を意味します。同じ更紗ゴシックでもSCを選ぶと漢字が中国字形になるため、
日本語環境ではJを選ぶ必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;ウェイトは5段（200 &#x2F; 300 &#x2F; 400 &#x2F; 600 &#x2F; 700）で、それぞれにイタリックがあり、
合計10面すべてが実フェイスです。nameID 1では
&lt;code&gt;Sarasa Term J Light&lt;&#x2F;code&gt; のように枝番のファミリ名に分かれていますが、
nameID 16のタイポグラフィックファミリは10面とも &lt;code&gt;Sarasa Term J&lt;&#x2F;code&gt; で共通なので、
ファミリ名は変えずに &lt;code&gt;weight&lt;&#x2F;code&gt; を指定するだけで切り替わります。
日本語フォントにイタリックがあるのは珍しく、ヒラギノはW0からW9まで10段のウェイトを持ちながら
イタリックを1面も持ちません。ターミナルでは斜体をコメントの表示に使うので、ここは実用差になります。&lt;&#x2F;p&gt;
&lt;p&gt;供給元について書いておくと、フォントは実行ファイルではなく、
ネットワークアクセスとテレメトリのいずれも持ちません。理論上の懸念はTrueTypeのヒンティング命令ですが、
更紗ゴシックのヒンティングはttfautohintによる自動生成で、
macOSのCoreTextはフォント解析をサンドボックス下で行います。
GitHub Releasesから手動でダウンロードするとチェックサムの検証がないため、
Homebrewのcask経由に切り替えました。&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 --cask font-sarasa-gothic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ライセンスはOFL-1.1で、撤回できません。一度入手したものを後から使えなくされることは
原理的にないという点は、単一ベンダーの商用フォントより安心できる部分です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;WezTerm_の設定&quot;&gt;WezTerm の設定&lt;&#x2F;h2&gt;
&lt;p&gt;設定の該当部分です。&lt;code&gt;font_rules&lt;&#x2F;code&gt; は指定したフォントで丸ごと置き換わる仕様なので、
太字と斜体でも同じ3段を組み直す必要があります。ここを怠ると、
太字の日本語やアイコンがフォールバックから外れます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot; data-name=&quot;wezterm.lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; font_stack&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;weight&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; italic&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; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; wezterm.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;font_with_fallback&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-source&quot;&gt;  { family&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;quot;Berkeley Mono&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, weight&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; weight, style&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; italic&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; and&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Oblique&amp;quot; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;or&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Normal&amp;quot; &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 z-definition z-comment z-comment&quot;&gt;  -- Sarasa は Oblique を持たず Italic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  { family&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;quot;Sarasa Term J&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, weight&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; weight, style&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; italic&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; and&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Italic&amp;quot; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;or&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Normal&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, scale&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.2&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-source&quot;&gt;  { family&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;quot;Symbols Nerd Font Mono&amp;quot; &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-source&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;end&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;config.font&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&quot;&gt; font_stack&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;400&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;false&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;config.bold_brightens_ansi_colors&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&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;config.font_rules&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; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt; { intensity&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;quot;Bold&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, font&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&quot;&gt; font_stack&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;700&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;false&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-source&quot;&gt; { italic&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&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, font&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&quot;&gt; font_stack&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;400&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;true&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-source&quot;&gt; { italic&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&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, intensity&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;quot;Bold&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, font&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&quot;&gt; font_stack&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;700&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;true&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-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;font_size = 20.0&lt;&#x2F;code&gt; は別のテーブルで設定しています。
なぜこの値なのか、なぜ &lt;code&gt;scale&lt;&#x2F;code&gt; が1.2なのかは、忘れた頃に自分を助けるので
実測値ごとコメントとして設定ファイルに残しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&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;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A      x_adv=12  cells=1   1セルぴったり&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;あ 漢  x_adv=24  cells=2   2セルぴったり&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;① ◆   x_adv=12  cells=1   1セルぴったり&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;日本語混じりの表や罫線が崩れなくなり、&lt;code&gt;①&lt;&#x2F;code&gt; のような記号が隣の文字と重ならなくなりました。太字と斜体は、欧文がBerkeley Monoの設計どおりのOblique、和文が更紗ゴシックの実イタリックで描かれます。合成は発生していません。アイコンのために日本語フォントを抱える必要もなくなりました。&lt;&#x2F;p&gt;
&lt;p&gt;この記事の原稿をエディタで開いた画面です。日本語と欧文が混ざっても、文字がマス目からはみ出さずに並んでいます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;09&amp;#x2F;berkeley-sarasa&amp;#x2F;wezterm.webp?h=b065e8127975d7186bca&quot;
  alt=&quot;日本語と欧文が混在する原稿をWezTermで表示した画面&quot; width=&quot;1383&quot; height=&quot;1019&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;日本語と欧文が混在する原稿をWezTermで表示した画面&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;和文を1.2倍で描いているため日本語が欧文よりやや大きく見えますが、個人的にはこちらの方が読みやすく感じています。また欧文がまとまって見えるので、コード交じりの文章も見やすくなりました。&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;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;Berkeley Graphics&lt;&#x2F;a&gt;. &quot;Berkeley Mono Typeface&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;be5invis&#x2F;Sarasa-Gothic&quot;&gt;Sarasa Gothic&lt;&#x2F;a&gt;. 「更紗ゴシック」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ryanoasis&#x2F;nerd-fonts&quot;&gt;Nerd Fonts&lt;&#x2F;a&gt;. &quot;Iconic font aggregator&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wezterm.org&#x2F;config&#x2F;fonts.html&quot;&gt;WezTerm&lt;&#x2F;a&gt;. &quot;Font Configuration&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;adobe-fonts&#x2F;source-han-sans&quot;&gt;Adobe Type Tools&lt;&#x2F;a&gt;. &quot;Source Han Sans&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">WezTerm のフォント設定を、欧文 Berkeley Mono、全角 更紗ゴシック、アイコン Symbols Nerd Font Mono の3段構成に組み直しました。
セル幅を実測して scale を決め、全角が正確に2セルへ収まる状態にしています。
</summary>
        </entry><entry xml:lang="en">
        <title>Google Cloud Generative AI Leader（GAIL）認定を4時間の学習で取得する</title>
        <published>2026-09-01T14:32:10+09:00</published>
        <updated>2026-09-01T14:32:10+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/09/gail-certification/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/09/gail-certification/</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;09&amp;#x2F;gail-certification&amp;#x2F;cover.avif?h=7cc49233819782e77b05&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;!-- textlint-disable --&gt;
&lt;img src=&quot;badge.webp&quot; alt=&quot;Google Cloud Generative AI Leader（GAIL）認定&quot; style=&quot;float:left;width:25%;height:auto;margin:0 1.5rem 1rem 0;&quot; &#x2F;&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;2025年5月からGoogleが提供している &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cloud.google.com&#x2F;learn&#x2F;certification&#x2F;generative-ai-leader?hl=ja&quot;&gt;Google Cloud Generative AI Leader（GAIL）&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; (以下、GAILと記載)を受験し合格できました。
試験対策で資料をまとめたので、公開致します。&lt;&#x2F;p&gt;
&lt;p&gt;1週間ほど前にAWS Certified Generative AI Developer - Professional (AIP-C01)を取得した後、思いつきでGAILの受験を申込んだものです。学習時間は準備期間を含めて4時間程度でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;GAILとはどういう試験か&quot;&gt;GAILとはどういう試験か&lt;&#x2F;h2&gt;
&lt;p&gt;GAILは2025年5月14日に提供が始まった認定です。Google Cloudの認定体系ではCloud Digital Leaderと同じ基礎レベルに置かれていて、前提となる資格や実務経験は必要ありません。&lt;&#x2F;p&gt;
&lt;p&gt;問われるのは、生成AIをビジネスにどう使うかという戦略と判断です。設定手順やコードは出題されません。求められる製品知識も、要件に対してどの製品を選ぶかというビジネスレベルの深さにとどまります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&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 style=&quot;text-align: right&quot;&gt;50〜60問&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;出題形式&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;多肢選択式（択一のみ）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;試験時間&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;90分&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;受験料&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;99 USD（税別）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;提供言語&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;英語、日本語、スペイン語、ポルトガル語&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;実施形式&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;オンライン監督付き または テストセンター&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;前提条件&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;なし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;有効期間&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;3年&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;出題形式は択一選択問題だけです。正解を2つ以上すべて選ぶ複数選択問題はありません。並べ替えやマッチングの形式もないので、解答操作に慣れておく手間がかかりません。AIP-C01には複数選択問題がありましたから、この点はGAILのほうが素直です。&lt;&#x2F;p&gt;
&lt;p&gt;出題範囲は4つのセクションに分かれています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;セクション&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;配点&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1. 生成AIの基礎&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;約30%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;2. Google Cloud の生成AI製品&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;約35%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;3. 生成AIモデル出力を改善する手法&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;約20%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;4. 生成AIソリューションを成功に導くビジネス戦略&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;約15%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;基礎と生成AI製品で65%を占めます。生成AIの一般的な概念を押さえたうえで、要件からGoogle Cloudの製品を引けるかどうかが得点の中心です。&lt;&#x2F;p&gt;
&lt;p&gt;学習で一番戸惑ったのは製品名でした。例えば、Vertex AIはGemini Enterprise Agent Platformに、Vertex AI SearchはAgent Searchに改称され、試験ガイドは現行の名称で書かれています。一方で公式模擬試験はVertex AIのまま出題されていました。本番でどちらの名称が使われるか分からないので、一応両方を覚えておくようにしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;私のプロフィール&quot;&gt;私のプロフィール&lt;&#x2F;h2&gt;
&lt;p&gt;読者が自分との距離を測れるように、私の前提を書いておきます。&lt;&#x2F;p&gt;
&lt;p&gt;私は元AWSコンサルタントです。Associateレベルの3つの認定を持ち(内2つはExpireしています)、数年の実務経験があります。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIはClaude Codeを常用しており、Anthropic、OpenAI、Google Cloud、VoyageなどのAPIを使用するツールは書いています。
AWS Certified Generative AI Developer - Professional (AIP-C01)を取得したばかりです。&lt;&#x2F;p&gt;
&lt;p&gt;Google Cloudに関しては2024年にGoogle Cloud Digital Leaderを取得した程度で、AWSと比較するとほぼ使用していません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;使った教材と学習の進め方&quot;&gt;使った教材と学習の進め方&lt;&#x2F;h2&gt;
&lt;p&gt;教材は公式のものだけです。使ったのは次の3つでした。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;services.google.com&#x2F;fh&#x2F;files&#x2F;misc&#x2F;generative_ai_leader_exam_guide_english.pdf&quot;&gt;公式試験ガイド&lt;&#x2F;a&gt;（PDF、英語）&lt;&#x2F;li&gt;
&lt;li&gt;公式模擬試験（Googleフォームで提供される。日本語版もあり、認定ページからたどれる）&lt;&#x2F;li&gt;
&lt;li&gt;Google Cloudの製品ドキュメント&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;やったことは単純で、試験ガイドと模擬試験を通して引っかかった製品を公式ドキュメントで確認し、その内容をClaude Codeに渡してAsciiDocのノートに積み上げただけです。&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;08&#x2F;aip-c01&#x2F;&quot;&gt;AIP-C01のとき&lt;&#x2F;a&gt;と同じやり方です。&lt;&#x2F;p&gt;
&lt;p&gt;そこに、Google Cloudの製品とAWSのサービスの対応を追記しました。
下表のように並べておくと、AWS側の知識をそのまま流用できます。私のようにAWSから来る人にとっては、製品名を単体で覚えるより速い方法だと思います。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;09&amp;#x2F;gail-certification&amp;#x2F;gcp-aws-mapping.webp?h=3ef0c659f3c736b32c2d&quot;
  alt=&quot;GCPとAWSの対比表の一部&quot; width=&quot;765&quot; height=&quot;457&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;ノートの付録に置いたGCP↔AWS対比表（抜粋）&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;まとめたノートはGitHubで公開しています。PDFとHTMLをReleasesに置いてあります。&lt;&#x2F;p&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;gail-materials&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;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&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;私が自分の理解を整理するために書いたものであり、Google LLC が作成・監修・承認したものではありません。記載内容の正確性は保証しません。判断に使う前に、公式の試験ガイドと製品ドキュメントで一次情報を確認してください。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;学習時間はノートをまとめる時間を含めて4時間程度です。試験前に一度読み返しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;試験当日と結果&quot;&gt;試験当日と結果&lt;&#x2F;h2&gt;
&lt;p&gt;会場はテストセンターです。試験時間は90分で、私が受けた回の問題数は45問でした。公式には50〜60問と案内されているので、回によって振れ幅があるようです。実際にかかったのは見直しと終了後アンケートを含めて15分程度でした。&lt;&#x2F;p&gt;
&lt;p&gt;提出すると画面に暫定の合否が表示されるようです。
私はそれに気付かないまま終了操作を進めてしまいました。うっかり見過ごしやすいので、最後の画面は落ち着いて読んでください。正式な結果はGoogle Cloud側の確認を経て、7〜10日で確定します。&lt;&#x2F;p&gt;
&lt;p&gt;数日は待つものと諦めていたのですが、Credlyから試験終了の30分後にはバッジが確認できました。&lt;&#x2F;p&gt;
&lt;p&gt;出るのは合否だけで、AWSのようなスコアもセクション別の評価もありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;誰にとって価値のある認定か&quot;&gt;誰にとって価値のある認定か&lt;&#x2F;h2&gt;
&lt;p&gt;体感では、エンジニアであれば半日程度の学習で余裕を持って取れます。生成AIを日常的に触っている人なら、実質的に覚えるのはGoogle Cloudの製品名と、それぞれがどの要件に対応するかの対応表だけです。&lt;&#x2F;p&gt;
&lt;p&gt;そのうえで、この認定が向いているのは、生成AIの導入を企画したり予算を通したりする側の人です。技術者と会話するための共通語彙を短時間で揃えられます。逆に、実装する側のエンジニアがGoogle Cloudでの生成AI開発力を示す材料にはなりません。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIに特化したGoogle Cloudの認定は、これまでGAILだけでした。ここが2026年9月に変わります。&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cloud.google.com&#x2F;learn&#x2F;certification&#x2F;agentic-architect&quot;&gt;Professional Agentic Architect&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; のベータ登録が9月3日に始まります。Google Cloud上で自律的なエージェントのワークフローを設計・運用する技術者向けの認定で、Pearson配信の約80問・3時間の多肢選択試験に加えて、Google Skills上のハンズオンラボの両方に合格する必要があります。ベータの受験料は120 USD、提供言語は英語のみ、有効期間は1年です。&lt;&#x2F;p&gt;
&lt;p&gt;現役のエンジニアであれば、GAILではなくこちらを狙う価値があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;学習は、公式試験ガイド、公式模擬試験、製品ドキュメントで足りる&lt;&#x2F;li&gt;
&lt;li&gt;得点の中心は、要件からGoogle Cloudの製品を引けるかどうかである&lt;&#x2F;li&gt;
&lt;li&gt;製品名は改称の途上にある。新旧を対にして覚えておく&lt;&#x2F;li&gt;
&lt;li&gt;AWS経験者は、AWSのサービスとの対応表を作るのが速い&lt;&#x2F;li&gt;
&lt;li&gt;実装する側のエンジニアは、ベータ版でもProfessional Agentic Architectにチャレンジすべき。生成AIがあるいま、英語はハードルではない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;思いつきで申し込んだ試験でしたが、Google Cloudの生成AI製品を要件から引ける形で一度整理できたのは収穫です。AWSとGoogle Cloudで、同じ課題に対する解き方の並びがきれいに対応することも確認できます。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIの主導権を握っているのは米国のプラットフォーマーで、日本のベンダーにはありません。案件の基盤がAWSになるかGoogle Cloudになるか、あるいはOpenAIのAPIを直接叩くことになるかは、エンジニアの側では選べず、プロジェクトごとに変わります。ひとつを深く知っているだけでは足りません。どれが来ても要件から製品を引ける程度には、それぞれを知っておくことが、これからは効いてくると思います。&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;cloud.google.com&#x2F;learn&#x2F;certification&#x2F;generative-ai-leader?hl=ja&quot;&gt;Google Cloud&lt;&#x2F;a&gt;. 「Generative AI Leader 認定資格」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;services.google.com&#x2F;fh&#x2F;files&#x2F;misc&#x2F;generative_ai_leader_exam_guide_english.pdf&quot;&gt;Google Cloud&lt;&#x2F;a&gt;. 「Generative AI Leader Certification exam guide」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.skills.google&#x2F;paths&#x2F;1951&quot;&gt;Google Cloud&lt;&#x2F;a&gt;. 「Generative AI Leader Certification（学習パス）」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.google&#x2F;innovation-and-ai&#x2F;infrastructure-and-cloud&#x2F;google-cloud&#x2F;generative-ai-leader-certification&#x2F;&quot;&gt;Google&lt;&#x2F;a&gt;. 「Become a certified Generative AI Leader with a first-of-its-kind credential from Google Cloud」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.google.com&#x2F;cloud-certification&#x2F;answer&#x2F;9438208?hl=ja&quot;&gt;Google Cloud&lt;&#x2F;a&gt;. 「Google Cloud 認定資格に関するよくある質問」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cloud.google.com&#x2F;learn&#x2F;certification&#x2F;agentic-architect&quot;&gt;Google Cloud&lt;&#x2F;a&gt;. 「Professional Agentic Architect Certification」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">AWS Certified Generative AI Developer - Professional を取得した1週間後に、思いつきで Google Cloud Generative AI Leader（GAIL）を受験し、合格しました。どんな試験なのか、公式教材だけで足りた理由、AWS認定との違い、そして現役のエンジニアがいま狙うべき認定はどれかをまとめます。
</summary>
        </entry><entry xml:lang="en">
        <title>タグ付けは「分類させるな、幻覚させろ！」</title>
        <published>2026-09-01T09:16:50+09:00</published>
        <updated>2026-09-01T09:16:50+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/09/dont-classify-hallucinate/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/09/dont-classify-hallucinate/</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;09&amp;#x2F;dont-classify-hallucinate&amp;#x2F;cover.avif?h=ead0228173d70b67b32e&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Doug Turnbull氏の&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;softwaredoug.com&#x2F;blog&#x2F;2026&#x2F;08&#x2F;10&#x2F;hypothetical-classifications&quot;&gt;Don&#x27;t classify. Hallucinate!&lt;&#x2F;a&gt;&quot;という記事を読んで、
同じようにClaude Codeによるブログ記事のタグ提案を改善できないかと検討してみました。&lt;&#x2F;p&gt;
&lt;!-- author-approved: 元記事タイトルの原文表記のため感嘆符を残す --&gt;
&lt;!-- textlint-disable ja-technical-writing&#x2F;no-exclamation-question-mark --&gt;
&lt;h2 id=&quot;&amp;quot;Don&amp;#39;t_classify._Hallucinate!&amp;quot;の主旨&quot;&gt;&quot;Don&#x27;t classify. Hallucinate!&quot;の主旨&lt;&#x2F;h2&gt;
&lt;!-- textlint-enable ja-technical-writing&#x2F;no-exclamation-question-mark --&gt;
&lt;p&gt;この記事の主旨は、LLMに物事を特定のTaxonomyに分類させる際、
事前に用意した大量の選択肢をLLMに渡して直接選ばせるのではなく、
あえてLLMにカテゴリ名を自由に生成（ハルシネーション）させます。
それを埋め込み（Embedding）の類似度計算で正規カテゴリにマッピングする手法の提案です。&lt;&#x2F;p&gt;
&lt;p&gt;従来の「500個ある選択肢の中から選べ」という方式では、
選択肢の一覧を毎回プロンプトやスキーマに載せてモデルへ送る必要があり、
その分だけトークンを消費します。&lt;&#x2F;p&gt;
&lt;p&gt;この記事の方式では、次の2ステップを取ります。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;ステップ1（LLMに生成させる）&lt;&#x2F;dt&gt;
&lt;dd&gt;正規のカテゴリ一覧を渡さず、「このクエリに合いそうな分類名を自由に考えて作って」とLLMに頼む（例：「茶色のコーヒーテーブル」に対して、LLMが独自に &lt;code&gt;Furniture&lt;&#x2F;code&gt; &lt;code&gt;Living Room&lt;&#x2F;code&gt; &lt;code&gt;Tables&lt;&#x2F;code&gt; &lt;code&gt;Coffee&lt;&#x2F;code&gt; と回答）&lt;&#x2F;dd&gt;
&lt;dt&gt;ステップ2（ベクトルの類似度で変換する）&lt;&#x2F;dt&gt;
&lt;dd&gt;LLMが適当に作った分類名の埋め込み（Embedding）ベクトルと、あらかじめ計算しておいた「本物の正規カテゴリ一覧」のベクトルとの類似度（内積など）を計算し、最も近い正規カテゴリに割り当てる。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;メリットは、次の2点でしょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;低コスト・高速。毎回大量のカテゴリリストをプロンプトやスキーマに含めて送信する必要がない&lt;&#x2F;li&gt;
&lt;li&gt;安価な小型モデルの活用。高度で高価なモデルを使わずとも、軽量な小型LLMでも十分に機能する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;これまでのタグ提案ロジック&quot;&gt;これまでのタグ提案ロジック&lt;&#x2F;h2&gt;
&lt;p&gt;これまでは、このブログでは次のようなロジックでClaude Codeにタグを提案させていました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予めタグセットを作成し、各タグを持つ記事全てのベクター値を算出し正規化した値をそのタグのベクター値として保管する&lt;&#x2F;li&gt;
&lt;li&gt;提案時は記事内容からベクター値を算出し、タグセットのベクター値と最も近いタグを提案する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;このタグごとのベクター値は、そのタグが付いた記事すべての重心にあたります。「このブログで &lt;code&gt;Cloud&lt;&#x2F;code&gt; と呼んでいるのは、だいたいこういう内容の記事だ」という実績の平均です。&lt;&#x2F;p&gt;
&lt;p&gt;素直な作りですが、2つの制約がありました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;タグを1つ足すだけで、タグセット全体のベクター値を計算し直す必要がある
&lt;ul&gt;
&lt;li&gt;重心は記事から作るため、タグセットを編集するたびに全388記事を埋め込み直すことになる。1回あたり542Kトークン、7秒かかる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;記事が0件のタグを推薦できない
&lt;ul&gt;
&lt;li&gt;平均を取る相手がないので、ベクター値は空になる。そのタグが付くまで推薦されず、推薦されないから記事も付かない、という循環に陥る&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;Doug Turnbull氏の記事をヒントに以下のように変更しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;タグセットのベクター値の算出で全記事をインプットにすることは廃し、タグ名だけのベクター値を算出し保存する&lt;&#x2F;li&gt;
&lt;li&gt;提案時は記事内容からClaude Codeに自由に5つの単語を発想させ、連結したものでベクター値を算出する&lt;&#x2F;li&gt;
&lt;li&gt;算出したベクター値ともっとも近似のタグを提案する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;5語にしたのは、1語よりも記事の内容を的確に言い表せるためです。
5語はスペースで連結し、1本のベクターとして扱います。&lt;&#x2F;p&gt;
&lt;p&gt;タグセットは &lt;code&gt;data&#x2F;tagset.toml&lt;&#x2F;code&gt; で定義しています。
第1層と第2層、そして第2層がどの第1層に属するかを手で書きます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot; data-name=&quot;data&#x2F;tagset.toml&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;layer1&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;name&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 z-definition z-string z-string&quot;&gt; &amp;quot;Tech&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;description&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 z-definition z-string z-string&quot;&gt; &amp;quot;ソフトウェア、クラウド、AI、開発ツールなど技術全般。&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&quot;&gt;[[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;layer2&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;name&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 z-definition z-string z-string&quot;&gt; &amp;quot;Cloud&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;parent&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 z-definition z-string z-string&quot;&gt; &amp;quot;Tech&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;description&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 z-definition z-string z-string&quot;&gt; &amp;quot;クラウドコンピューティング全般。インフラとマネージドサービス。&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ベクター値は &lt;code&gt;data&#x2F;tag-vectors.json&lt;&#x2F;code&gt; に書き出します。
こちらはスクリプトが生成するので、手では編集しません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;data&#x2F;tag-vectors.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;schema_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;model&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;voyage-4&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;dim&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1024&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;input_type&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;document&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;vector_source&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;tag_name&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;normalized&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;updated&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;2026-08-31&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;tags&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;Cloud&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;article_count&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&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;&#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;vector&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.0185&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.0438&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.0912&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.0109&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;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;vector&lt;&#x2F;code&gt; は実際には1024個の要素を持つ配列です。上記は抜粋のため省略しています。
&lt;code&gt;article_count&lt;&#x2F;code&gt; は記事数を数えているだけで、ベクター値には使いません。
旧ロジックではこの記事群からベクター値を作っていましたが、
新ロジックでは &lt;code&gt;name&lt;&#x2F;code&gt; の &lt;code&gt;Cloud&lt;&#x2F;code&gt; という文字列だけを埋め込んでいます。&lt;&#x2F;p&gt;
&lt;p&gt;Claude自体はベクターの埋め込みに対応していないので、Voyage APIを使用しています。
Anthropicの公式ドキュメントにも
&quot;Anthropic does not offer its own embedding model&quot; と明記されており、
そこから案内されている事業者がVoyage AIです。&lt;&#x2F;p&gt;
&lt;p&gt;選定にあたっては、OpenAIとGoogleも含めて比較しました。
決め手になったのはコストです。
&lt;code&gt;voyage-4&lt;&#x2F;code&gt; の単価は1Mトークンあたり0.06ドルで、最安ではありません。
OpenAIの &lt;code&gt;text-embedding-3-small&lt;&#x2F;code&gt; は0.02ドルですから、単価だけ見れば3倍です。
それでもVoyageを選んだのは、全アカウントに200Mトークンの無料枠が付くためです。
個人ブログの規模では、この枠を使い切ることはまずありません。
単価差が実質的に効かないので、無料枠のある事業者が有利になります。&lt;&#x2F;p&gt;
&lt;p&gt;もう1つは、1024次元で精度が出ることです。
ベクターの一覧はリポジトリに置くため、次元数がそのままファイルサイズになります。&lt;&#x2F;p&gt;
&lt;p&gt;候補のモデルをこのブログの全記事で実際に動かして比較しました。
OpenAIの &lt;code&gt;text-embedding-3-large&lt;&#x2F;code&gt; は3072次元でなければ最高精度に届かず、
1024次元に落とすと精度が下がります。
ファイルを3倍に膨らませるか精度を落とすかの二択になるわけです。
Voyageは1024次元のままその水準を保つので、この二択を迫られずに済みます。&lt;&#x2F;p&gt;
&lt;p&gt;以上から、モデルは &lt;code&gt;voyage-4&lt;&#x2F;code&gt;、出力次元は1024としました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜタグ名だけで照合できるのか？&quot;&gt;なぜタグ名だけで照合できるのか？&lt;&#x2F;h2&gt;
&lt;p&gt;上記のロジックでは記事内容自体は全くベクター化に含まれていません。
なぜ、&lt;code&gt;Cloud&lt;&#x2F;code&gt; や &lt;code&gt;Security&lt;&#x2F;code&gt; といった数語の文字列に、
記事の内容と突き合わせられるだけの情報があるのでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;成立するのは、埋め込みモデルがモデル提供者による事前学習で一般的な言語知識を持っているからです。
モデルはWikipediaや書籍、Web上の膨大なテキストを読み込んで、
「どの語がどの語と、どういう文脈で一緒に使われやすいか」を学習しています。
その結果、モデルの内部には意味の近い語が近い座標に並ぶベクトル空間が予めできあがっています。
巨大な連想類語辞典を、モデル自身があらかじめ持っているようなものです。&lt;&#x2F;p&gt;
&lt;p&gt;たとえば &lt;code&gt;Cloud&lt;&#x2F;code&gt; という文字列を渡すだけで、モデルは
「空に浮かぶ雲」だけでなく「ITのクラウドインフラ」という意味合いを含む座標を返します。
記事から発想した &lt;code&gt;infrastructure&lt;&#x2F;code&gt; や &lt;code&gt;serverless&lt;&#x2F;code&gt; といった語も、同じ空間の近い位置に来ます。
このブログで &lt;code&gt;Cloud&lt;&#x2F;code&gt; タグが過去どう使われてきたかをモデルが知らなくても、
世間一般でそれらが近い概念であるという知識だけで照合できます。&lt;&#x2F;p&gt;
&lt;p&gt;裏を返せば、モデルが知っているのは世間一般の語義です。
旧ロジックのベクター値は、そのタグが付いた記事の重心でした。
「このブログで &lt;code&gt;Cloud&lt;&#x2F;code&gt; と呼んでいるのはこういう記事だ」という実績です。
タグの意味の拠り所を、このブログでの使われ方から世間一般の語義へ移したことになります。&lt;&#x2F;p&gt;
&lt;p&gt;旧ロジックでは、タグの使い方と一般的な語義が食い違ったまま補正されません。
新ロジックでは、タグが世間一般で指す意味に沿って提案されます。従って、タグから想定される記事の内容が読者と噛み合わないということが防げます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;新ロジックの精度検証&quot;&gt;新ロジックの精度検証&lt;&#x2F;h2&gt;
&lt;p&gt;3つの期間の記事で実測しました。精度は既存のタグと一致している率です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;期間&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;記事数&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;提案が1位&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;上位3位以内&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026年3〜5月&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;73&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;71.2%&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;89.0%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2026年4〜6月&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;61&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;75.4%&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;93.4%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;直近（5月末〜8月末）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;50&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;76.0%&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;88.0%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;既存タグは上記で説明したとおり独自にセットしていたので、読者から見て必ずしも適切であったとは限りません。
ただ、新ロジックでも7割以上は既存と同じタグが提案されます。タグ付けの振るまいは大きく変わらず、精度としては合格点としました。&lt;&#x2F;p&gt;
&lt;p&gt;この精度を保ったまま、旧ロジックの2つの制約が外れました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;タグセットのベクター値を計算し直すコストが消えた
&lt;ul&gt;
&lt;li&gt;記事を読まずタグ名だけを埋め込むため、36タグを配列で1リクエストに投入できる。16トークン、1秒未満で終わる。旧ロジックは388記事を9リクエストに分けて542Kトークン・7秒かかっていた&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;記事が0件のタグを推薦できるようになった
&lt;ul&gt;
&lt;li&gt;タグ名さえあればベクター値を持てるため、新しく作ったタグをその日から推薦候補にできる&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;「分類させるな、幻覚させろ」というタイトルには驚きました。
しかし中身は、仮想の回答文書（Hypothetical Document）を生成してベクトル検索するHyDE（Hypothetical Document Embeddings）を、分類タスクに応用したものです。
分類タスクで問題になるのは、雑多な対象の表現（今回は「記事」）とTaxonomy（今回はタグ一覧）の構造的なギャップです。記事本文とタグ名を直接ベクトル比較しても、きれいには重なりません。&lt;&#x2F;p&gt;
&lt;p&gt;以前はこのギャップをTaxonomy側で埋めていました。コストをかけてタグごとに記事をベクター化し、Taxonomyを記事の表現に寄せていたわけです。今回のアイデアは逆転の発想で、対象のほうをTaxonomyに合わせます。&lt;&#x2F;p&gt;
&lt;p&gt;新ロジックに変更してタグセットの維持が格段にやりやすくなりました。
また独自のタグ付けをしていた部分は、少し読者側に寄り添えたかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;タグ体系は注意深く練り直す必要がありました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;独自の使い分けは排除する。&lt;code&gt;Movie&lt;&#x2F;code&gt;（自身で制作した動画）と &lt;code&gt;Films&lt;&#x2F;code&gt;（観賞した映画）を使い分けていたが、一般には同義である&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Insight&lt;&#x2F;code&gt;（洞察）のような抽象的な概念は避ける。タグ付けが安定しない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;このロジックはタグ自動アサインではなく、あくまでタグ提案として扱っています。
そのまま使うか書き換えるかは、これまでどおり筆者の裁量で決めます。&lt;&#x2F;p&gt;
&lt;p&gt;原記事は小型で安価なモデルが使えるという利点も挙げていましたが、
今回はそこまで手を付けていません。
このスキルはメインセッションで動くため、そのセッションのモデルがそのまま使われます。
キーワードを選ぶ工程だけをサブエージェントに切り出し、
そのモデルをHaikuに指定すれば、この利点も取り込めるはずです。&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;softwaredoug.com&#x2F;blog&#x2F;2026&#x2F;08&#x2F;10&#x2F;hypothetical-classifications&quot;&gt;Doug&#x27;s search blog and newsletter&lt;&#x2F;a&gt;. 「Don&#x27;t classify. Hallucinate!」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;platform.claude.com&#x2F;docs&#x2F;en&#x2F;build-with-claude&#x2F;embeddings&quot;&gt;Anthropic&lt;&#x2F;a&gt;. 「Embeddings」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.voyageai.com&#x2F;docs&#x2F;embeddings&quot;&gt;Voyage AI&lt;&#x2F;a&gt;. 「Text Embeddings」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Doug Turnbull氏の「Don&#x27;t classify. Hallucinate!(分類させるな、幻覚させろ!)」という記事を参考に、Claude Codeによるブログ記事のタグ提案ロジックを変更しました。
記事本文をベクター化しないのに、なぜタグと照合できるのでしょうか。
</summary>
        </entry><entry xml:lang="en">
        <title>ブログの画像形式をAVIFに移行</title>
        <published>2026-08-29T17:07:36+09:00</published>
        <updated>2026-08-29T17:07:36+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/08/migrate-to-avif/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/08/migrate-to-avif/</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;08&amp;#x2F;migrate-to-avif&amp;#x2F;cover.avif?h=1aca7fea6ae273f5ac5f&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;このブログのカバー画像の出力をWebPからAVIFに切り替えました。
切り替えるにあたって、記事内の画像をすべて変換したらどれくらい軽くなるのかを実際に測り、
どの画像をどの形式で持つのかを決め直しています。その過程をまとめます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;画像フォーマット_AVIFとは&quot;&gt;画像フォーマット AVIFとは&lt;&#x2F;h2&gt;
&lt;p&gt;AVIFは、Alliance for Open Media（AOMedia）が策定した静止画フォーマットです。AOMediaは2015年9月1日に発足しました。設立メンバーはAmazon、Cisco、Google、Intel、Microsoft、Mozilla、Netflixの7社で、発足時のプレスリリースには「相互運用可能でオープン」「ロイヤリティフリー」「Web向けに最適化」といった目標が並んでいます。Googleは当時の状況を「web video innovation was too slow and too closed」と表現していました。&lt;&#x2F;p&gt;
&lt;p&gt;その成果が動画コーデックのAV1です。2018年3月28日にビットストリーム仕様が公開され、同年6月25日に検証済みの1.0.0が出ました。&lt;&#x2F;p&gt;
&lt;p&gt;静止画フォーマットには、動画コーデックのイントラフレーム符号化をそのまま流用するという系譜があります。WebPはVP8から、HEICはHEVCから作られました。AV1に同じことをしたのがAVIFです。仕様1.0.0は2019年2月19日に公開され、最新版は2025年10月16日の1.2.0です。&lt;&#x2F;p&gt;
&lt;p&gt;器にはHEIFを使います。HEICと同じISO Base Media File Format系のコンテナで、中身の符号化だけをHEVCからAV1に差し替えた格好です。HEICと決定的に違うのは、特許ライセンスの交渉なしで使える点です。&lt;&#x2F;p&gt;
&lt;p&gt;フォーマットとしての特徴は次のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;JPEGやWebPより高い圧縮効率を持つ&lt;&#x2F;li&gt;
&lt;li&gt;12bitまでの色深度、HDR、広色域を扱える&lt;&#x2F;li&gt;
&lt;li&gt;アルファチャンネル、可逆圧縮、アニメーション、プログレッシブデコードに対応する&lt;&#x2F;li&gt;
&lt;li&gt;仕様と実装がともにロイヤリティフリーである&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;Can I useはWeb技術のブラウザ対応状況をまとめたサイト&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;ブラウザ側の対応は、Chrome 85、Firefox 93、Safari 16（iOS）およびSafari 16.4（macOS）、Edge 121からです。最後発のEdgeが2024年1月に対応したことで主要ブラウザが出揃い、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;caniuse.com&#x2F;avif&quot;&gt;Can I use&lt;&#x2F;a&gt;の集計では対応率が約95%に達しています。個人ブログで使うぶんには、もう待つ理由はありません。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、使う前に知っておいたほうがよい癖もあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;エンコードが遅い。&lt;code&gt;avifenc&lt;&#x2F;code&gt;の&lt;code&gt;-s&lt;&#x2F;code&gt;（speed）は0が最も遅く、10に近づくほど速くなる&lt;&#x2F;li&gt;
&lt;li&gt;既定のクロマサブサンプリングは4:2:0で、細い色付きの線や文字が崩れる&lt;&#x2F;li&gt;
&lt;li&gt;可逆圧縮ではWebPに大きく負ける&lt;&#x2F;li&gt;
&lt;li&gt;ブラウザ以外の取得元、たとえばSNSのクローラーは対応状況が読めない&lt;&#x2F;li&gt;
&lt;li&gt;小さい画像ではヘッダの分が効いて、かえって大きくなることがある&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;後半の3つはこのブログの運用にそのまま効いてきました。以降の節で実測値とともに見ていきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AVIF移行の検証&quot;&gt;AVIF移行の検証&lt;&#x2F;h2&gt;
&lt;p&gt;確かめたいことは3つあります。ブログ全体を移行するとどれだけ軽くなるのか、写真をどの品質値で変換すればよいのか、そして図版にもAVIFを使ってよいのかです。このブログの実データで順に測っていきます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;検証の前提と対象&quot;&gt;検証の前提と対象&lt;&#x2F;h3&gt;
&lt;p&gt;一括変換の対象は、記事で使用している画像すべてです。&lt;code&gt;avifenc -q 60 -y 420 -s 6&lt;&#x2F;code&gt;で変換し、変換前後の合計バイト数を比べています。対象は678枚でしたが、このうち2枚は変換できていません。95フレームのアニメーションWebPが1枚と、697フレームのアニメーションGIFが1枚です。AVIF自体はアニメーションを表現できますが、&lt;code&gt;avifenc&lt;&#x2F;code&gt;が受け付けるのは静止画だけだからです。残る677枚が集計対象になります。&lt;&#x2F;p&gt;
&lt;p&gt;既存のWebPがすでに非可逆圧縮を通ったファイルである点には注意が必要です。今回はそれをPNGに展開してからAVIFに再エンコードしているので、原本から直接AVIFにする場合とは条件が違います。以降の数字は「いま置き換えたらどうなるか」の目安として見てください。&lt;&#x2F;p&gt;
&lt;p&gt;画質はSSIMULACRA2という知覚品質指標で測ります。CloudinaryのJon Sneyers氏が作った指標で、スコア90が「visually lossless」、70が「high quality（アーティファクトは知覚できるが不快ではない）」、50が「medium quality」という目安が示されています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ブログ全体でどれだけ削減できるか&quot;&gt;ブログ全体でどれだけ削減できるか&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;区分&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;枚数&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;変換前&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;AVIF (q=60)&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;削減率&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;本文画像&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;169&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;38.9 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;14.4 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;63.0%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;カバー画像&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;128&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;21.2 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;10.6 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;49.9%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;OGP画像&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;380&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;7.9 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;5.6 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;28.6%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;合計&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;677&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;68.0 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;30.6 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;54.9%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;全体では55%減という結果です。
OGP画像で削減率が低いのは文字中心のシンプルな画像であるためでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;元の形式ごとに分けると次のようになります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;元の形式&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;枚数&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;変換前&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;AVIF (q=60)&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;削減率&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;WebP&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;634&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;41.1 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;24.1 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;41.4%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;JPEG&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;36&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;24.4 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;6.3 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;74.1%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;PNG&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;7&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2.5 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.2 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;90.6%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;JPEGとPNGの削減率が高いのは、枚数が少ないうえに1枚あたりが大きいファイルに偏っているためです。すでにWebPになっている634枚での4割減が、実際の移行で期待できる水準に近い数字だと考えています。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、677枚のうち40枚はAVIFのほうが大きくなりました。最大で1.66倍です。内訳は本文画像が32枚、カバー画像が8枚で、本文画像の多くは図版やスクリーンショットでした。写真とそれ以外を同じ設定で扱うのは無理がある、ということがここに出ています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;写真をどの品質値で変換するか&quot;&gt;写真をどの品質値で変換するか&lt;&#x2F;h3&gt;
&lt;p&gt;このブログのAI生成カバー1枚と写真3枚を使い、品質値を振りながらスコアを測りました。比較対象は移行前まで使っていた&lt;code&gt;cwebp -q 80&lt;&#x2F;code&gt;です。写真3枚は保存済みのJPEGを基準画像にしているので、この表が見ているのはAVIFとWebPの再エンコード分だけです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;設定&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;AI生成カバー&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;写真A&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;写真B&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;写真C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=54&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;65.4&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;63.4&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;71.4&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;64.8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=56&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;67.9&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;67.0&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;73.6&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;66.8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=58&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;69.0&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;68.5&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;74.6&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;67.7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=60&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;71.5&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;71.5&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;76.2&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;69.5&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=62&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;72.6&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;72.9&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;76.9&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;70.3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;cwebp -q 80&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;74.4&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;77.1&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;72.3&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;69.2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;q=58以下では4枚とも70を割ります。q=60にすると3枚が70を超え、残る1枚も69.5とほぼ境界です。つまり60は、SSIMULACRA2の「高品質」の目安に乗る最小の設定ということになります。&lt;&#x2F;p&gt;
&lt;p&gt;同じ4枚のファイルサイズは次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;設定&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;AI生成カバー&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;写真A&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;写真B&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;写真C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=60&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;138.2 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;414.5 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;107.3 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;160.9 KB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;cwebp -q 80&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;181.3 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;618.5 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;132.8 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;199.0 KB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;削減率&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;23.8%&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;33.0%&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;19.2%&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;19.1%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;スコアは&lt;code&gt;cwebp -q 80&lt;&#x2F;code&gt;と同程度で、ファイルは2割から3割小さくなりました。見た目を落とさずに軽くするという目的には、これで足ります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;図版にAVIFを使えるか&quot;&gt;図版にAVIFを使えるか&lt;&#x2F;h3&gt;
&lt;p&gt;変換して大きくなった40枚の多くは図版やスクリーンショットでした。図版でAVIFがどう振る舞うのかを、2つの角度から測ります。&lt;&#x2F;p&gt;
&lt;p&gt;1つ目はクロマサブサンプリングです。AVIFの既定である4:2:0は色差の解像度を半分に落とすため、細い色付きの線が崩れます。1927×864の構成図で測ると次のようになりました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;設定&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;サイズ&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;SSIMULACRA2&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=60 (4:2:0)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;39.8 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;76.4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=90 (4:2:0)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;61.5 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;77.5&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF q=60 (4:4:4)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;40.3 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;87.7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;cwebp -q 90&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;122.5 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;76.2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;cwebp -lossless&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;42.1 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;劣化なし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;4:2:0のままだと、品質値を90まで上げてもスコアは77台で頭打ちになります。&lt;code&gt;-y 444&lt;&#x2F;code&gt;にすれば87.7まで戻りますが、それでも非可逆であることに変わりはありません。そして可逆WebPは42.1 KBで、AVIF q=60の39.8 KBとほとんど変わらないサイズに収まっています。同じ容量で劣化なしにできるのですから、図版で非可逆を選ぶ理由がありません。&lt;&#x2F;p&gt;
&lt;p&gt;2つ目は可逆圧縮どうしの比較です。図版やスクリーンショット6枚を&lt;code&gt;cwebp -lossless&lt;&#x2F;code&gt;と&lt;code&gt;avifenc --lossless&lt;&#x2F;code&gt;の両方で圧縮しました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;画像&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;内容&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;cwebp -lossless&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;avifenc --lossless&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;倍率&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;flow.png&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;構成図&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;42.1 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;222.0 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;5.27倍&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;covid19-graph1.png&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;グラフ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;10.0 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;36.4 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;3.64倍&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;covid19-graph2.png&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;グラフ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;11.0 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;48.7 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;4.44倍&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;badge.png&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;バッジ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;11.4 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;25.7 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2.26倍&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;decibel-spotify-preset.png&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;スクリーンショット&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;15.4 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;38.2 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2.48倍&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;postcard.png&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;イラスト&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;23.7 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;153.0 KB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;6.46倍&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;このブログの図版で試した範囲では、AVIFの可逆圧縮はWebPの2.3倍から6.5倍になりました。可逆で残したい画像にAVIFを使う意味はありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ：画像形式の使い分け方針&quot;&gt;まとめ：画像形式の使い分け方針&lt;&#x2F;h2&gt;
&lt;p&gt;検証の結果、このブログでは画像の性質で2つに分けると決めました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;写真やAI生成のイラストは非可逆のAVIFを使用&lt;&#x2F;li&gt;
&lt;li&gt;図版やスクリーンショットは可逆のWebPを使用&lt;&#x2F;li&gt;
&lt;li&gt;適用するのは新規記事のみ、既存記事のファイルは移行しない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;写真とAI生成のカバー画像は次のコマンドで変換します。&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;avifenc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -q&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 60&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -y&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 420&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --ignore-exif --ignore-xmp input.png output.avif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;-y 420&lt;&#x2F;code&gt;はクロマサブサンプリング、&lt;code&gt;-s 6&lt;&#x2F;code&gt;はエンコード速度の指定です。&lt;code&gt;--ignore-exif --ignore-xmp&lt;&#x2F;code&gt;はExifとXMPのメタデータを出力に含めません。&lt;&#x2F;p&gt;
&lt;p&gt;図版やスクリーンショットは、WebPの可逆圧縮を使います。&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;cwebp&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -lossless -z&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -exact input.png -o output.webp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;-z 9&lt;&#x2F;code&gt;は可逆プリセットの圧縮レベルを最大にする指定、&lt;code&gt;-exact&lt;&#x2F;code&gt;は透明部分のRGB値を保持する指定です。&lt;&#x2F;p&gt;
&lt;p&gt;OGP画像（&lt;code&gt;social_media_card&lt;&#x2F;code&gt;）はWebPのまま据え置きます。ブラウザではなくSNSのクローラーが取得する画像なので、対応状況が読めない形式に変えるリスクのほうが、数MBの節約より大きいと判断しました。&lt;code&gt;npm run ogp&lt;&#x2F;code&gt;で自動化しているので、出力は現状維持することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;まとめると、このブログの使い分けは次の3つになります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;用途&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;形式&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;コマンド&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;写真、AI生成のカバー画像&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AVIF（非可逆）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;avifenc -q 60 -y 420 -s 6 --ignore-exif --ignore-xmp in.png out.avif&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;図版、グラフ、スクリーンショット&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;WebP（可逆）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;cwebp -lossless -z 9 -exact in.png -o out.webp&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;OGP画像&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;WebP&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;npm run ogp&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;冒頭のカバー画像も、この方針で作った最初のAVIFです。1536×864で41.9 KBに収まりました。&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;aomedia.org&#x2F;press%20releases&#x2F;alliance-to-deliver-next-generation-open-media-formats&#x2F;&quot;&gt;Alliance for Open Media&lt;&#x2F;a&gt;. &quot;Alliance for Open Media Established to Deliver Next-Generation Open Media Formats&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aomediacodec.github.io&#x2F;av1-avif&#x2F;&quot;&gt;AOMediaCodec&lt;&#x2F;a&gt;. &quot;AV1 Image File Format (AVIF)&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;caniuse.com&#x2F;avif&quot;&gt;Can I use&lt;&#x2F;a&gt;. &quot;AVIF image format&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudinary&#x2F;ssimulacra2&quot;&gt;Cloudinary&lt;&#x2F;a&gt;. &quot;SSIMULACRA 2 - Structural SIMilarity Unveiling Local And Compression Related Artifacts&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">ブログで使用する画像形式をWebPからAVIFに切り替えることを検討しました。ただし、全ての画像がAVIFに向いているわけではありません。そこで実際にAVIFに変換してファイルサイズや画質を検証し、画像形式ごとの向き不向きから移行方針を立てました。</summary>
        </entry><entry xml:lang="en">
        <title>AWS Certified Generative AI Developer - Professional (AIP-C01) を3週間・20時間の学習で取得する</title>
        <published>2026-08-26T04:32:16+09:00</published>
        <updated>2026-08-26T04:32:16+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/08/aip-c01/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/08/aip-c01/</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;08&amp;#x2F;aip-c01&amp;#x2F;cover.webp?h=0b130f3e4f2bb463e72a&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;!-- textlint-disable --&gt;
&lt;img src=&quot;badge.webp&quot; alt=&quot;AWS Certified Generative AI Developer - Professional のデジタルバッジ&quot; style=&quot;float:left;width:25%;height:auto;margin:0 1.5rem 1rem 0;&quot; &#x2F;&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;2026年8月25日に &lt;strong&gt;AWS Certified Generative AI Developer - Professional (AIP-C01)&lt;&#x2F;strong&gt; を受験し、合格ライン750点のところ、辛くも779点で合格できました。&lt;&#x2F;p&gt;
&lt;p&gt;私は元AWSコンサルタントで、学習期間は8月3日から受験日までの3週間、学習時間は準備期間を含めて体感で20時間程度でした。準備ではClaude CodeとMulmoClaudeを活用しました。&lt;&#x2F;p&gt;
&lt;p&gt;この試験は2026年3月に始まったばかりで、日本語の受験記がほとんど見当たらないと思うのでこの記事をまとめました。
受験を迷っている人が知りたいであろう、次の3点を中心にまとめました。&lt;&#x2F;p&gt;
&lt;ol&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;h2 id=&quot;AIP-C01_とはどういう試験か&quot;&gt;AIP-C01 とはどういう試験か&lt;&#x2F;h2&gt;
&lt;p&gt;正式名称はAWS Certified Generative AI Developer - Professional(以下、AIP-C01と記載)、試験コードはAIP-C01です。基盤モデル（FM: Foundation Model）をアプリケーションや業務ワークフローに組み込む能力を問う、Professionalレベルの認定です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&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 style=&quot;text-align: right&quot;&gt;採点対象65問 ＋ 未採点10問 ＝ 75問&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;試験時間&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;180分&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;合格ライン&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;100〜1000点のスケールドスコアで750点&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;出題形式&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;択一選択問題、複数選択問題&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;受験料&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;44,000円（税込）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;提供言語&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;英語、日本語、韓国語、中国語（簡体字）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;受験料は44,000円（税込）です。AWSの受験料は認定レベルごとに決まっていて、AIP-C01はProfessionalレベルなので最も高い価格帯にあたります。
ただし、この試験を受けようと思う方は他のAWS認定を持っている方が多いと思います。
以前の受験で付与される50%の割引バウチャー特典を持っている場合があるので、
&lt;strong&gt;AWS 認定アカウントの「特典」ページを必ずチェック&lt;&#x2F;strong&gt;しましょう。&lt;&#x2F;p&gt;
&lt;p&gt;まず押さえておくべきは、&lt;strong&gt;出題形式が択一選択問題と複数選択問題の2種類しかない&lt;&#x2F;strong&gt;ことです。
択一選択問題は正解1つと誤答3つ、複数選択問題は5つ以上の選択肢から正解を2つ以上すべて選ぶ形式です。近年の他のAWS試験に見られる並べ替えやマッチングの形式はありません。解答操作そのものに慣れる必要がなく、対策は選択肢を読み比べる練習に集中できます。&lt;&#x2F;p&gt;
&lt;p&gt;次に、公式の試験ガイドで、次のものは&lt;strong&gt;試験では求められない領域&lt;&#x2F;strong&gt;として挙げられており、学習の必要はありません。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;モデルの開発と訓練&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;機械学習そのものの理解を問う試験ではありません。既存の基盤モデルをどう組み合わせ、どう本番環境に載せるかという開発者側の判断が問われます。&lt;&#x2F;p&gt;
&lt;p&gt;出題範囲は5つのコンテンツ分野に分かれています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;コンテンツ分野&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;配点&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1. 基盤モデルの統合、データ管理、コンプライアンス&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;31%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;2. 実装と統合&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;26%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;3. AI の安全性、セキュリティ、ガバナンス&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;20%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;4. GenAI アプリケーションの運用効率と最適化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;12%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;5. テスト、検証、トラブルシューティング&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;11%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;出題される75問のうち10問は採点されません。
これは今後の出題候補を評価するための問題で、試験中にどれが採点対象外なのかは分かりません。採点されるのは残る65問です。&lt;&#x2F;p&gt;
&lt;p&gt;65問で750&#x2F;1000点が合格ラインです。
配点は難易度の差を統計的に補正され算出されるので、「65問中これだけ正解すれば合格」という逆算はできません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;私のプロフィール&quot;&gt;私のプロフィール&lt;&#x2F;h2&gt;
&lt;p&gt;読者が自分との距離を測れるように、私の前提を書いておきます。&lt;&#x2F;p&gt;
&lt;p&gt;私は元AWSコンサルタントです。Associateレベルの3つの認定を持ち(内2つはExpireしています)、数年の実務経験があります。
AWSのサービス構成や、IAMやVPCといった土台の部分については、あらためて学び直す必要のない状態から始めています。&lt;&#x2F;p&gt;
&lt;p&gt;生成AI側については、Claude Codeを日常的に使っていて、Claude APIを使った小さなコードを今も書いています。APIの使い方やトークンの扱い、プロンプトの組み立てといった部分は、業務ではなく手元の道具として触ってきました。&lt;&#x2F;p&gt;
&lt;p&gt;Amazon Bedrockについては、現役時代にデモをいくつか作りました。ただし直近2年は必要性がなく、キャッチアップしていません。Bedrock Knowledge BasesやBedrock Agents、Guardrailsといった、この2年で増えた機能群は初見に近い状態でした。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、AWSの土台は持っているが、AWSの生成AI周辺のサービス知識は空白という状態からのスタートです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;使った教材とまとめ資料づくり&quot;&gt;使った教材とまとめ資料づくり&lt;&#x2F;h2&gt;
&lt;p&gt;最初に、 Whizlabsの「AWS Certified Generative AI Developer - Professional (AIP-C01) Certification Training」を購入しました。試験対策問題と、用意されたシナリオを実際のAWS環境で構築するLabsが含まれています。7,585円で購入しました。AIP-C01が始まった直後の2026年3月に購入しました。Whizlabsを選択したのはたまたまです。
現在はUdemyなど日本語で模擬試験を提供するサービスが多数あるので、そちらを推奨します。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、買っただけで満足し4ヶ月以上放置していました。&lt;&#x2F;p&gt;
&lt;p&gt;8月に入って学習を始めて最初に手を付けたのは、公式のサンプル問題です。
試験ガイドに付属する無料のサンプル問題と、AWS Skill Builderで提供されている公式模試の両方を解きました。試験の要点はサービスの機能でなく「要件に対して最適なサービス構成を選べる」ことが問われるというのが理解できます。&lt;&#x2F;p&gt;
&lt;p&gt;次に&lt;strong&gt;まとめ資料の作成&lt;&#x2F;strong&gt;です。
Whizlabsを進めながら、引っかかった箇所をAWSの公式ドキュメントで確認し、その内容をClaude Codeに渡してAsciiDocのドキュメントに積み上げていきました。最終的に約100ページになりました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;08&amp;#x2F;aip-c01&amp;#x2F;study-notes-toc.webp?h=75aa7ba6a7b4377f5e8c&quot;
  alt=&quot;まとめ資料の目次&quot; width=&quot;1174&quot; height=&quot;855&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;Claude Code に積み上げさせたまとめ資料の目次&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;やっていることは単純で、公式ドキュメントを読んで理解した内容を、自分が後で引ける形に整えているだけです。IAMの最小権限やクロスアカウント構成のように、AWSの一般知識とBedrock固有の事情が混ざる領域ではこの整理が効きました。&lt;&#x2F;p&gt;
&lt;p&gt;この資料作成でほぼ知識は整理できたので、資料自体は一読して読み返していません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MulmoClaude_に学習環境を作らせる&quot;&gt;MulmoClaude に学習環境を作らせる&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoClaudeで自分用の模擬問題集を作りました。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;receptron&#x2F;mulmoclaude&quot;&gt;MulmoClaude&lt;&#x2F;a&gt; はあの中島聡氏が開発しているClaude Codeのマルチモーダルクライアントです。
独自の模擬問題集を作った理由は、Whizlabsが英語ベースなので日本語版が欲しかったのと、独自にまとめたナレッジも折り込みたかったからです。&lt;&#x2F;p&gt;
&lt;p&gt;Whizlabsをベースにしていますが、まとめ資料や公式ドキュメントから解説を加えています。
設問は本番と同じシナリオ形式にして、選択肢もすべて技術的には成立するものを並べる形にしました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;08&amp;#x2F;aip-c01&amp;#x2F;quiz-practice.webp?h=865ec046d84768238c1b&quot;
  alt=&quot;模擬問題集の演習画面&quot; width=&quot;1360&quot; height=&quot;1097&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;自作した模擬問題集の演習画面&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;回答するごとに、その正誤を履歴を記録しています。&lt;&#x2F;p&gt;
&lt;p&gt;更にMulmoClaude上で進捗ダッシュボードを用意して、ドメイン別の進捗と、概念別にどこで落としているかを見えるようにしました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;08&amp;#x2F;aip-c01&amp;#x2F;progress-dashboard.webp?h=d987bc1da2506a8bcd43&quot;
  alt=&quot;進捗ダッシュボード&quot; width=&quot;1362&quot; height=&quot;1109&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;ドメイン別の習得状況と出題形式別の内訳を表示する進捗ダッシュボード&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;「直近2回連続で正解したら習得」としました。初見の設問に対する最初の解答は、当てずっぽうで当たっている可能性が排除できないからです。この定義にすると、まぐれ当たりの問題が習得済みに紛れ込まなくなり、繰り返すべき問題だけが残ります。
間違えた問題を中心に5周ほど回しました。&lt;&#x2F;p&gt;
&lt;p&gt;私の場合、MulmoClaudeで環境を作ること自体が学習のモチベーションになりました。ただし効率で言えば、既存の模擬試験を買ったほうがよいと思います。回答履歴の管理や弱点対応、メモの書き込み、AIによるその場での質疑応答などは、多くのサービスですでに備えています。&lt;&#x2F;p&gt;
&lt;p&gt;詰め方としては、弱点である問題に絞っていくアプローチが効きました。周回を重ねるほど残る問題が減り、後半ほど1周が短くなります。進んでいる実感が出るので、最後まで続けられました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AIP-C01の選択肢には癖がある&quot;&gt;AIP-C01の選択肢には癖がある&lt;&#x2F;h2&gt;
&lt;p&gt;学習する中で気付いた選択肢の癖をまとめておきます。誤答を消去していく手がかりとして個人的には役立ちました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&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;私が公式模試やWhizlabsから学習する中で気付いた傾向であって、本番の出題傾向ではありません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;ul&gt;
&lt;li&gt;リトライやスロットリング対策の文脈で「指数バックオフ（exponential backoff）」を含む選択肢が出てきたら、正解である確率が高い。AWSが公式に推奨するリトライ戦略であり、対比として置かれる固定間隔リトライや無制限リトライは設計として明確に劣るためだと理解している&lt;&#x2F;li&gt;
&lt;li&gt;Amazon Kendraは、誤答側の選択肢である可能性が高い。エンタープライズ検索のサービスであって、Bedrock Knowledge BasesでRAG（Retrieval-Augmented Generation）を組む構成が用意されている以上、生成AIアプリケーションの検索層としては選ばれにくい位置にある&lt;&#x2F;li&gt;
&lt;li&gt;ファインチューニングも、誤答側である可能性が高い。RAGやプロンプトエンジニアリングで満たせる要件に対して、過剰な手段として置かれることが多い。データ準備の重さと運用コストが、要件に見合わない形で設問に埋め込まれている&lt;&#x2F;li&gt;
&lt;li&gt;固定長チャンキング（fixed-size chunking）は、常に品質劣化の原因側として扱われていた。意味の切れ目を無視して機械的に区切るため、検索の精度が落ちる側の選択肢になる&lt;&#x2F;li&gt;
&lt;li&gt;最も多く登場したサービスはAWS Step Functionsである。生成AIのアプリケーションでも、複数ステップのオーケストレーションや人間の承認を挟むワークフローの受け皿として顔を出す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらを暗記のリストとして使うでなく、なぜその選択肢が誤答側に置かれるのかを言語化しておくことに意味があります。
初見の設問でも同じ判断ができるようになります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;試験当日とスコア&quot;&gt;試験当日とスコア&lt;&#x2F;h2&gt;
&lt;p&gt;会場はテストセンターです。試験時間は180分ですが、実際にかかったのは見直しと終了後アンケートを含めて60分程度でした。分からない問題を粘っても答えが出るわけではないので、決めたら次に進むという解き方をしています。&lt;&#x2F;p&gt;
&lt;p&gt;体感の内訳を正直に書きます。模擬問題で身に付けた知識をそのまま応用できたのが約4割。自分の知識も使って論理的に導き出せたが確信は持てなかったのが約2割。残る約4割は、ほぼ勘です。&lt;&#x2F;p&gt;
&lt;p&gt;結果は合格、スコアは779点でした。合格ラインの750点から29点差です。4割を勘で答えたという体感と、この点差は整合していると思います。&lt;&#x2F;p&gt;
&lt;p&gt;セクション別の評価は次のとおりでした。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;合否は合計スコアだけで決まり、セクションごとの合格ラインは存在しません。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;コンテンツ分野&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&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 style=&quot;text-align: left&quot;&gt;1. 基盤モデルの統合、データ管理、コンプライアンス&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;31%&lt;&#x2F;td&gt;&lt;td&gt;コンピテンシーを満たしている&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;2. 実装と統合&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;26%&lt;&#x2F;td&gt;&lt;td&gt;コンピテンシーを満たしている&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;3. AI の安全性、セキュリティ、ガバナンス&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;20%&lt;&#x2F;td&gt;&lt;td&gt;コンピテンシーを満たしている&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;4. GenAI アプリケーションの運用効率と最適化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;12%&lt;&#x2F;td&gt;&lt;td&gt;改善が必要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;5. テスト、検証、トラブルシューティング&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;11%&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;学習期間が短かったので配点の多い上位3つドメインにフォーカスしたので、ある意味狙い通りでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;8月3日から受験日までの3週間、集中して取り組んだように見えるかもしれませんが、実際には大半の時間が
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.nintendo.com&#x2F;jp&#x2F;games&#x2F;switch2&#x2F;aadla&#x2F;index.html&quot;&gt;スプラトゥーン レイダース&lt;&#x2F;a&gt;
の無限食堂に溶けていました。勉強そのものに充てたのは、体感で20時間程度です。&lt;&#x2F;p&gt;
&lt;p&gt;試験対策の要点をまとめると、次の5点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;割引バウチャー特典は必ずチェック&lt;&#x2F;li&gt;
&lt;li&gt;AWSの基本的な知識(AWS Certified Solutions Architect – Associateレベル)は前提として必要&lt;&#x2F;li&gt;
&lt;li&gt;知識の整理にはLLMを活用&lt;&#x2F;li&gt;
&lt;li&gt;模擬試験で知識を整理し、試験形式に馴れておく&lt;&#x2F;li&gt;
&lt;li&gt;上位3コンテンツ分野にフォーカスして学習&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;AWSを離れたたった2年の期間で生成AIを活用したシステムの典型的なアーキテクチャーがここまで整理され、クラウドプラットフォームではそれを支えるサービスラインナップがここまで充実し具現化していることが、個人的には驚きでした。
AWS自身が、生成AIを活用したアーキテクチャーのベストプラクティスを説明するものとして
&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;ja_jp&#x2F;wellarchitected&#x2F;latest&#x2F;generative-ai-lens&#x2F;generative-ai-lens.html&quot;&gt;AWS Well-Architected Generative AI Lens&lt;&#x2F;a&gt;&quot;と言うドキュメントを公開しています。試験には必須ではありませんが、現役の方はぜひ目を通しましょう。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIをどうやってシステムに組み込むのかと悩んでいた時代は過去のものですね。&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;docs.aws.amazon.com&#x2F;ja_jp&#x2F;aws-certification&#x2F;latest&#x2F;ai-professional-01&#x2F;ai-professional-01.html&quot;&gt;AWS&lt;&#x2F;a&gt;. 「AWS Certified Generative AI Developer - Professional (AIP-C01) 試験ガイド」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;jp&#x2F;certification&#x2F;certified-generative-ai-developer-professional&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;. 「AWS Certified Generative AI Developer - Professional」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;skillbuilder.aws&#x2F;&quot;&gt;AWS Skill Builder&lt;&#x2F;a&gt;. 「AWS Certified Generative AI Developer - Professional Official Practice Question Set」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.credly.com&#x2F;badges&#x2F;aa2ad3fb-8d51-4b81-9387-2c826e0f83ca&#x2F;public_url&quot;&gt;Credly&lt;&#x2F;a&gt;. 「AWS Certified Generative AI Developer - Professional（デジタルバッジ）」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.whizlabs.com&#x2F;aws-certified-generative-ai-developer-professional&#x2F;&quot;&gt;Whizlabs&lt;&#x2F;a&gt;. 「AWS Certified Generative AI Developer - Professional (AIP-C01) Certification Training」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">2026年3月に始まったばかりの AWS Certified Generative AI Developer - Professional (AIP-C01) を受験し、779点で合格しました。日本語の受験記があまりないと思いますから、どんな試験か、何をどれだけやれば届くか、教材に何が使えるかを、スコアと学習ログを添えて残します。
</summary>
        </entry><entry xml:lang="en">
        <title>Cloudflare OS - OSでなく生成AIエージェントで実現するLong-Tail業務アプリ基盤</title>
        <published>2026-08-19T00:00:00+00:00</published>
        <updated>2026-08-19T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/08/cloudflare-os/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/08/cloudflare-os/</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;08&amp;#x2F;cloudflare-os&amp;#x2F;cover.webp?h=aa7b6b5cdb806d78e4d9&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;2026年8月5日、CloudflareがAIワークスペース「Cloudflare OS」をApache-2.0ライセンスで公開しました。翌日にはHacker Newsのフロントページに載り、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;cloudflare-os&quot;&gt;GitHubのリポジトリ&lt;&#x2F;a&gt;のスターは公開初日に3,900、8月19日時点では8,500を超えています。&lt;&#x2F;p&gt;
&lt;p&gt;&quot;OS&quot;という名前を見て、私はまずLinuxやWindowsの系譜を想像しました。しかし発表内容を読むと、これは伝統的な意味でのOSではありません。Cloudflareが自社の全社員向けに作って運用してきた社内AIワークスペースを、丸ごと公開したものです。名前の大きさと中身のあいだにある落差が、この製品を考える上での出発点になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflare_OSとは何か？&quot;&gt;Cloudflare OSとは何か？&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflare OSが何かを語る前に、まず下回りから見ていきましょう。この製品を実装しているのは、既存のCloudflare製品の束ね直しです。Workers、Durable Objects、Access、AI Gateway、R2に、ツール接続のMCPとRPCのCap&#x27;n Webが加わります。新しいインフラを作ったわけではありません。&lt;&#x2F;p&gt;
&lt;p&gt;役割で並べ替えると、計算資源、状態の保持、認証、AIモデルへの接続、ストレージ、そしてツール接続という並びになります。これは2026年にエージェント基盤を名乗る製品であればどこも持っている組み合わせで、この層に「OS」と名乗る根拠はありません。インフラとして見る限り、ここにあるのは典型的な&lt;strong&gt;生成AIエージェント基盤&lt;&#x2F;strong&gt;です。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflareは、生成AIエージェント基盤としての機能を3つに分けて説明しています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;構成要素&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;内容&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Agent Workspace&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ブラウザのチャットUI。非エンジニアの利用も想定している&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;セキュリティとガバナンスの層&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;外部へはGatekeeper経由でしか届かない。権限はcapabilityで渡し、アクセスは記録する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Gadget&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;成果物1つごとに、エージェントが専用のソフトウェアを書いて動かす&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Gadgetは一から作らせるほかに、既存のGadgetのコードを雛形にして作れます。この雛形はBlueprintと呼ばれ、標準では3つが同梱されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;workspace-docs: ドキュメント&lt;&#x2F;li&gt;
&lt;li&gt;workspace-sheets: スプレッドシート&lt;&#x2F;li&gt;
&lt;li&gt;workspace-slides: スライド&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;事務作業の最低限だけが置かれていて、あとは各自で増やす、という構えです。自作したGadgetも、中身のデータは渡さずコードだけをBlueprintにして配れます。&lt;&#x2F;p&gt;
&lt;p&gt;ここで各自が増やすものとして想定されているのが、long-tailの業務です。1件あたりの規模は小さいものの種類がとにかく多く、IT部門に頼むほどではないけれど手元では面倒、という類の作業を指します。特定のチームだけが使う集計表、月に数回しか動かさない進捗の一覧、部署内で回している申請の受付といったものです。数が多すぎて基幹システムには載らず、これまでExcelやAccessが引き受けてきた領域でもあります。&lt;&#x2F;p&gt;
&lt;p&gt;まとめると、Cloudflare OSは、利用社員が自らチャットで指示して成果物と個々の成果物専用のGadgetを構築できる生成AIエージェント基盤です。アプリごとに資源を割り当てて互いに隔離し、外部との入出力を仲介するという役回りを見れば、比喩として「OS」は的外れとも言い切れませんが、基本的には各社のエージェント基盤と大きく変わりません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ドキュメント単位に閉じるという設計&quot;&gt;ドキュメント単位に閉じるという設計&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;ドキュメント単位の隔離&lt;&#x2F;strong&gt;が、設計方針の中でもっとも目を引く部分です。アプリの実体であるGadgetは、ドキュメント1つにつきDurable Objectのインスタンスが1つ割り当てられ、専用のWorkerとSQLiteストレージを持ちます。ブラウザ側ではiframeに閉じ込められ、CSPの&lt;code&gt;connect-src &#x27;none&#x27;&lt;&#x2F;code&gt;によってネットワークへの到達そのものが断たれます。外に出たければGatekeeperを通すしかなく、そのGatekeeperが認証情報を握ってスコープを絞った操作だけを許す、という構造です。&lt;&#x2F;p&gt;
&lt;p&gt;この作りが効くのは、中身が検証されていないコードを前提にできるからです。Gadgetを書くのはエンジニアではなく、非エンジニアの指示を受けたAIで、レビューやテストは通っていません。不具合があっても、そのGadgetは外部へ接続する手段を持たず、隣のドキュメントのデータにも手が届きません。悪意のある指示が埋め込まれたファイルを読んでしまった場合も同じです。社内システムに届くのは、Gatekeeperを通ったあらかじめ絞られた操作だけです。さらに生成物を他人へ共有する段になると、元になったデータへの権限を相手が持っているかどうかが、あらためて確認されます。Cloudflare自身、非エンジニアが安心して好きに触れることを設計目標として挙げています。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflare OSを主導したKenton Vardaは公開時に、これは10年前の自分のスタートアップSandstorm.ioのリメイクだと述べています。10年前この構想が広まらなかった理由は2つあります。対応アプリが足りなかったことと、インスタンスごとにコンテナを立てる実行基盤が重すぎたことでした。10年を経て、ミリ秒起動するWorkersが前者の重さを解き、生成AIが「対応アプリを人が移植する」という前提そのものを消しました。エージェントがその場でアプリを書くのであれば、アプリストアを埋める必要はありません。&lt;&#x2F;p&gt;
&lt;p&gt;つまりCloudflare OSの中核にある思想は、生成AIブームの産物ではなく、条件が揃うのを10年待っていた設計です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OSSだがCloudflare前提&quot;&gt;OSSだがCloudflare前提&lt;&#x2F;h2&gt;
&lt;p&gt;「OSSで公開」「セルフホスト可能」と聞くと、自社データセンターに閉じた運用を思い浮かべるかもしれません。しかしCloudflare OSのセルフホストとは、Cloudflareのネットワーク上にある自社アカウントへデプロイすることを指します。&lt;strong&gt;実行基盤は必ずCloudflare&lt;&#x2F;strong&gt;です。OSSであることは、中身が透明で、自由に改変でき、UIに縛られないという意味です。インフラからの独立を意味するわけではありません。&lt;&#x2F;p&gt;
&lt;p&gt;これがOSSであるCloudflare OSのマネタイズの源泉だと考えています。Cloudflare自身が明言しているわけではありませんが、razor-and-blades、つまり本体を無料で配りそれが消費する下回りで課金する構図です。課金ポイントは、Workersの実行、Durable Objects、Workers AIとAI Gateway、R2、そしてAccessやZero Trustのシートに分散しています。
OSSは自社クラウドの消費を増やすための入口だという見立てです。ダッシュボードに統合されたマネージド版も予告されています。&lt;&#x2F;p&gt;
&lt;p&gt;この構造は、AWS上に同じものを自作した場合と経済モデルとしては変わりません。自分のアプリを他社クラウドに載せて従量課金される、ロックインの形も同じです。ただし専有リソースをあらかじめ確保する方式とは違い、Cloudflareはサーバーレスのマルチテナントです。もっとも、完全に使った分だけというわけでもありません。Gadgetの実体であるDurable Objectsは、メモリ上で起きているあいだwall-clockで課金され、リクエストが来ていなくても料金が発生します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2026年は「エージェント基盤に名前を付ける」年だった&quot;&gt;2026年は「エージェント基盤に名前を付ける」年だった&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflare OSを「生成AIエージェント基盤」とすると、この分野ではCloudflareはむしろ後発です。
ハイパースケーラー3社は数か月から半年先行して、同種の基盤を投入しています。&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;th&gt;性格&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;AWS&lt;&#x2F;td&gt;&lt;td&gt;Bedrock AgentCore&lt;&#x2F;td&gt;&lt;td&gt;2025年10月13日 GA&lt;&#x2F;td&gt;&lt;td&gt;Runtime、Gateway、Memory、Identity、Observabilityの部品群&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Google&lt;&#x2F;td&gt;&lt;td&gt;Gemini Enterprise Agent Platform&lt;&#x2F;td&gt;&lt;td&gt;2026年4月22日 Next &#x27;26&lt;&#x2F;td&gt;&lt;td&gt;Vertex AIの後継。Workspaceと密結合し、サンドボックス実行とA2A&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Microsoft&lt;&#x2F;td&gt;&lt;td&gt;Microsoft IQとFoundry Agent Service&lt;&#x2F;td&gt;&lt;td&gt;2026年6月2日 Build 2026&lt;&#x2F;td&gt;&lt;td&gt;Work IQなど4層のコンテキスト層。M365エコシステムに密結合&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Cloudflare&lt;&#x2F;td&gt;&lt;td&gt;Cloudflare OS&lt;&#x2F;td&gt;&lt;td&gt;2026年8月5日 OSS公開&lt;&#x2F;td&gt;&lt;td&gt;社内で運用済みの完成ツールをApache-2.0で配布&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;p&gt;Cloudflare OSが他社と違うのは2点です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;非エンジニアによるエージェント利用が前提:&lt;&#x2F;strong&gt; 他社の基盤は、エージェントを組むのがエンジニアであることを暗黙の前提にしている。Cloudflare OSは逆で、レビューやテストを通っていないコードが動く前提に立つ。成果物1つごとに隔離し、ネットワークを最初から断ち、認証情報をコードに渡さないのは、そのためである&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;企業での提供方法:&lt;&#x2F;strong&gt; 他社が出しているのはIT部門が組み合わせてエージェントを作るための構成要素だが、Cloudflare OSは自社の全社員が数か月使ってきた完成品がそのまま、しかもApache-2.0で出てくる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;機能として「AWSでは同じことができない」わけではありません。IAMとAgentCoreのIdentityやGatewayを組み合わせれば、同等のことは実現できます。違うのは、それを誰かが組み上げなくても最初からそうなっている点です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;これは&amp;quot;OS&amp;quot;ではなく、業務アプリの器である&quot;&gt;これは&quot;OS&quot;ではなく、業務アプリの器である&lt;&#x2F;h2&gt;
&lt;p&gt;では、Cloudflare OSで実際に何が作られているのか。ドキュメント、スライド、スプレッドシート、ちょっとした集計、小さな社内アプリ、定型作業のワークフローです。&lt;&#x2F;p&gt;
&lt;p&gt;エンタープライズITで「アプリケーション」と言えば、通常は基幹系を指します。ERP、会計、受発注、在庫、勘定系。トランザクションの整合性が求められ、可用性のSLAがあり、監査に耐える必要があります。壊れれば業務が止まるもの、いわゆるsystems of recordです。Cloudflare OSが生成するものは、そこには届きません。OA用途、systems of engagement、long-tailのシャドーITといった領域です。&lt;&#x2F;p&gt;
&lt;p&gt;つまり本物の業務システムはGatekeeperの向こう側にあり、Cloudflare OS自身はその前段に立つフロントであり糊の層です。&quot;an open platform for agents, apps, and work&quot;という名乗り、とりわけ&quot;OS&quot;と&quot;apps&quot;という語の選び方は、実態より大きく見せています。&lt;&#x2F;p&gt;
&lt;p&gt;もっとも、名前が大げさであることと、カテゴリとして無価値であることは別の話です。ここからが本題になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;KintoneとMulmoClaudeと同じ家系&quot;&gt;KintoneとMulmoClaudeと同じ家系&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflare OSを理解するのに一番近い補助線は、他社のエージェント基盤よりもKintoneではないかと思いました。軽量な業務アプリを部品から組む、という核心が一致しています。部品のライブラリがあり、アプリの器があり、そこに近年は生成AIによるアプリ生成が加わる。この構図は両者で同じです。&lt;&#x2F;p&gt;
&lt;p&gt;そして&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;07&#x2F;building-contacts-database-mulmoclaude&#x2F;&quot;&gt;私が愛用している&lt;&#x2F;a&gt;MulmoClaudeも非常に近い系統にあると思います。&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;th&gt;中心にあるもの&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Kintone&lt;&#x2F;td&gt;&lt;td&gt;人間がノーコードで組む&lt;&#x2F;td&gt;&lt;td&gt;チーム、構造化DB、ワークフロー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Cloudflare OS&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;MulmoClaude&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;long-tailやengagementの層に向けたAIアプリ基盤は、どこも同じ形に収束しつつあります。Cloudflare OSが特別なのではなく、ノーコードによる市民開発が生成AIを得たときに行き着く先が、たまたまこの形だったということでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;この見立ては、&quot;OS&quot;という名前への違和感を少し和らげてもくれます。Kintoneは基幹系ではありませんが、正当な業務アプリのカテゴリとして市民権を得ています。&lt;&#x2F;p&gt;
&lt;p&gt;ただし過大評価は禁物です。できるのは軽いlong-tailだけで、複雑な業務ロジックや厳密な整合性が要る場面では手が止まります。生成AIのアプリ生成も同じで、動く小物はすぐ出てきますが、保守、データの一貫性、権限設計、エッジケースの処理には結局人手が要ります。「作れる」と「運用に耐える」のあいだは、思っているより広いままです。&lt;&#x2F;p&gt;
&lt;p&gt;本質は「IT部門に頼むほどでもない雑務を、その場で楽にする」道具であって、革命ではなく時短だと捉えるのが妥当だと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;EUCの亡霊、あるいは誰がこれを維持するのか&quot;&gt;EUCの亡霊、あるいは誰がこれを維持するのか&lt;&#x2F;h2&gt;
&lt;p&gt;そして、この家系のツールには必ず突き当たる問題があります。作った業務アプリを、誰がどう維持するのかという問題です。&lt;&#x2F;p&gt;
&lt;p&gt;かつてエンドユーザーコンピューティング(EUC)が抱えた病理は、よく知られています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;病理&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&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 style=&quot;text-align: left&quot;&gt;作った本人しか仕様を知らない。ドキュメントはなく、異動や退職でブラックボックスになる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;野良アプリの増殖&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;IT部門が把握しないアプリが社内に散らばり、棚卸しも統制も効かなくなる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;塩漬けとデータの人質化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;改修できないまま動かし続け、データが特定のアプリに囲い込まれる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;構造的な皮肉は、ノーコードが「作る敷居」を下げても「保守する敷居」は下げないことです。素人が速く大量に、保守できないものを量産できるぶん、事態はむしろ悪化しえます。1990年代から2000年代の「Excelマクロ地獄」「Accessデータベース地獄」が語られたときと、道具が変わっただけで病理は変わっていません。&lt;&#x2F;p&gt;
&lt;p&gt;Kintoneには監査ログや、管理者が1人しかいないアプリを洗い出すガバナンス機能があり、統制の側には手が打たれています。しかし棚卸しができることと、そのアプリを引き継げることは別です。作った人が異動すれば、なぜその形にしたのかは失われます。作る敷居を下げた分だけ、この保守の問題はより広く組織に行き渡ります。
MulmoClaudeはそもそも個人利用を想定しており、使い捨て前提なので、この病理は当てはまりません。&lt;&#x2F;p&gt;
&lt;p&gt;では、Cloudflare OSはこの病理にどのように手を当てているのでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;先に見たドキュメント単位の隔離とGatekeeperは、セキュリティの話であると同時に、EUCの統制のメカニズムでもあります。&lt;&#x2F;p&gt;
&lt;p&gt;Excelマクロが厄介だったのは、そのファイルが誰のPCにあるのか誰も知らず、埋め込まれた接続情報が作者の退職後も生き続け、データそのものがファイルの中に囲い込まれていたからでした。Cloudflare OSでは、アプリはGadgetとして基盤の上に載り、社内システムへの経路はGatekeeperに一本化され、どのアプリがどのデータを見たかは記録に残ります。少なくともIT部門が棚卸しをする手段はある、という点で、ファイルサーバーに散らばったマクロとは事情が違います。&lt;&#x2F;p&gt;
&lt;p&gt;認証情報をアプリに持たせない設計も、ここで効いてきます。作った本人の権限が失効すればアプリの持つcapabilityも一緒に失効するので、退職者の作ったものが基幹システムを叩き続ける事態は起きにくくなります。放置されたGadgetは、危険なまま動き続けるのではなく、単に無力になるわけです。データが元のシステム側に残り、アプリはその上に載る窓でしかない点も、人質化を弱めます。かつてのEUCで実際に事故になったのは、この「勝手に外へ手を伸ばす」部分でした。そこは確かに塞がっています。&lt;&#x2F;p&gt;
&lt;p&gt;手当てが届いているのは、統制と被害半径の側です。残るもう半分、つまり中身を誰が理解しているのかという問題には、この設計は何もしません。そして生成AIが加わると、ここはもう一段悪くなりかねません。Cloudflare OSのように非エンジニアが使うことを前提にした設計では、そもそもコードを読む人がいません。属人化を通り越して無人化です。保守の観点だけを見れば、これは退化とも言えます。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflare OSがこの点をどう設計しているのでしょうか。
GatekeeperとcapabilityはCloudflare OSが既存の社内システムとどう連携するかをよく統制します。しかし、生まれたアプリを3年後に誰が直すのかは統制してくれません。&lt;&#x2F;p&gt;
&lt;p&gt;答えは設計そのものに書かれています。成果物1つごとに独立したGadgetを与えるということは、共通のコードベースが存在しないということです。Blueprintから作ったGadgetにも、後から元の修正を反映する仕組みはありません。これらを維持する前提は置かれていません。MulmoClaude同様、個人の中で完結し使い捨てるものとして設計されていると考えます。&lt;&#x2F;p&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;blog.cloudflare.com&#x2F;cloudflare-os&#x2F;&quot;&gt;Cloudflare Blog&lt;&#x2F;a&gt;. &quot;Cloudflare OS: an open platform for agents, apps, and work&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;press&#x2F;press-releases&#x2F;2026&#x2F;cloudflare-os-is-the-first-ai-workspace-built-around-how-companies-actually-work&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Cloudflare OS Is the First AI Workspace Built Around How Companies Actually Work&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;cloudflare-os&quot;&gt;GitHub&lt;&#x2F;a&gt;. &quot;cloudflare&#x2F;cloudflare-os&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;about-aws&#x2F;whats-new&#x2F;2025&#x2F;10&#x2F;amazon-bedrock-agentcore-available&quot;&gt;AWS&lt;&#x2F;a&gt;. &quot;Amazon Bedrock AgentCore is now generally available&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cloud.google.com&#x2F;blog&#x2F;products&#x2F;ai-machine-learning&#x2F;the-new-gemini-enterprise-one-platform-for-agent-development&quot;&gt;Google Cloud Blog&lt;&#x2F;a&gt;. &quot;The new Gemini Enterprise: one platform for agent development&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;azure.microsoft.com&#x2F;en-us&#x2F;blog&#x2F;microsoft-build-2026-building-agentic-apps-with-microsoft-fabric-and-microsoft-databases&#x2F;&quot;&gt;Microsoft Azure Blog&lt;&#x2F;a&gt;. &quot;Microsoft Build 2026: Building agentic apps with Microsoft Fabric and Microsoft Databases&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;KentonVarda&#x2F;status&#x2F;2084990137180590572&quot;&gt;Kenton Varda (X)&lt;&#x2F;a&gt;. &quot;This is a remake of Sandstorm.io, my startup from 10 years ago&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">2026年8月、CloudflareがAIワークスペース「Cloudflare OS」をApache-2.0で公開しました。名前は大きいものの、従来のオペレーティングシステムではありません。Kintoneに近い業務アプリの器として捉え直すと、成果物ごとに使い捨てることを前提にした設計だと見えてきます。</summary>
        </entry><entry xml:lang="en">
        <title>MulmoTerminalのような通知をWezTermとClaude Codeで実現する</title>
        <published>2026-08-12T07:48:08+09:00</published>
        <updated>2026-08-12T07:48:08+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/08/claude-code-status-in-wezterm/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/08/claude-code-status-in-wezterm/</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;08&amp;#x2F;claude-code-status-in-wezterm&amp;#x2F;cover.webp?h=ec68c24fccffb4ff7b6a&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;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;中島聡氏らが開発している&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;receptron&#x2F;mulmoterminal&quot;&gt;MulmoTerminal&lt;&#x2F;a&gt;を少し使ってみました。複数のAIエージェントをブラウザ上のターミナルに並べ、各エージェントの状態を一目で分かるようにしたツールです。私はClaude Codeしか使っていないので全体としてはピンと来ませんでしたが、この状態表示の部分だけは便利だと感じました。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、私が普段使用しているWezTermの画面分割とClaude Codeで同じような通知を可能とする仕組みを作ってみました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;08&amp;#x2F;claude-code-status-in-wezterm&amp;#x2F;claude-state.webp?h=4ee2b300a5e83109c4df&quot;
  alt=&quot;タブラインに表示されたClaude Codeの状態&quot; width=&quot;1000&quot; height=&quot;27&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;タブラインに表示されたClaude Codeの状態&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;WezTermのタブラインの先頭にClaude Codeのステータス表示を追加し、入力待ちやタスクが完了した場合にClaude Codeのペインが明滅するようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;この仕組みを &lt;strong&gt;claude-state&lt;&#x2F;strong&gt; と名付けました。以降はこの呼び名で説明します。スクリプトやキャッシュディレクトリは &lt;code&gt;wezterm-claude-state&lt;&#x2F;code&gt; という名前で置いているため、本文に出てくるパスはその形になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;claude-stateの仕組み&quot;&gt;claude-stateの仕組み&lt;&#x2F;h2&gt;
&lt;p&gt;claude-stateは、Claude CodeとWezTermの間に状態ファイルを1枚挟んだだけの単純な仕組みです。Claude Code側のフックが現在の状態を書き込み、WezTerm側のLuaがそれを読んでタブラインに表示します。&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 hooks[&quot;Claude Codeのフック&quot;]
A[&quot;UserPromptSubmit&quot;]
B[&quot;PostToolUse&quot;]
C[&quot;Notification&quot;]
D[&quot;Stop&quot;]
end
A --&gt;|running| S
B --&gt;|running| S
C --&gt;|waiting| S
D --&gt;|done| S
S[&quot;wezterm-claude-state.sh&quot;]
S --&gt; F[&quot;状態ファイル&lt;br&#x2F;&gt;~&#x2F;.cache&#x2F;wezterm-claude-state&#x2F;&quot;]
S -. BEL .-&gt; P[&quot;ペインの明滅&quot;]
F --&gt; W[&quot;wezterm.lua&quot;]
W --&gt; T[&quot;タブライン&quot;]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;状態はrunning（実行中）、waiting（入力待ち）、done（完了）の3つだけで、フックが呼ばれるたびに上書きされます。セッションが終わるときは&lt;code&gt;SessionEnd&lt;&#x2F;code&gt;で状態ファイルごと削除します。&lt;&#x2F;p&gt;
&lt;p&gt;ファイル名にはWezTermが各ペインに割り当てる&lt;code&gt;$WEZTERM_PANE&lt;&#x2F;code&gt;をそのまま使います。どのペインの状態かが一意に決まるので、ペインをいくつ開いても取り違えることがありません。&lt;&#x2F;p&gt;
&lt;p&gt;ペインの明滅だけは別経路です。フックがBEL文字を書き込み、WezTermの&lt;code&gt;visual_bell&lt;&#x2F;code&gt;を発火させています。人がClaude Codeの後を引き継いで対応が必要な「入力待ち」と「完了」の場合のみペインが点滅します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件&quot;&gt;前提条件&lt;&#x2F;h2&gt;
&lt;p&gt;次の環境で動かしています。以降のコードやパスはこれを前提にしています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;項目&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;用途と補足&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;WezTerm&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;20240203-110809-5046fc22で確認&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Claude Code&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;フックから状態を書き出す&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;michaelbrusegard&#x2F;tabline.wez&quot;&gt;tabline.wez&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;タブラインの描画に使うプラグイン&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;jq&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;状態ファイルの掃除で&lt;code&gt;wezterm cli list&lt;&#x2F;code&gt;の出力を読む&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;OS&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;macOSで確認。Linux&#x2F;Windowsは未検証&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Nerd Font（任意）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;状態を示すアイコン。絵文字でも代用可&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;私は設定ファイルをchezmoiで管理していますが、記事中のパスはすべて展開後の実ファイルのものです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Code側の設定&quot;&gt;Claude Code側の設定&lt;&#x2F;h2&gt;
&lt;p&gt;フックは&lt;code&gt;~&#x2F;.claude&#x2F;settings.json&lt;&#x2F;code&gt;に登録します。5つのイベントから同じスクリプトを呼び、書き込む状態を引数で渡すだけの構成です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;~&#x2F;.claude&#x2F;settings.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;hooks&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;UserPromptSubmit&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;hooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [ { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;type&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;command&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-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;[ -n &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$WEZTERM_PANE&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ] &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$HOME&#x2F;.claude&#x2F;hooks&#x2F;wezterm-claude-state.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; running prune; exit 0&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-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;PostToolUse&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;hooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [ { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;type&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;command&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-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;[ -n &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$WEZTERM_PANE&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ] &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$HOME&#x2F;.claude&#x2F;hooks&#x2F;wezterm-claude-state.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; running; exit 0&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-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;Notification&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;hooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [ { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;type&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;command&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-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;[ -n &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$WEZTERM_PANE&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ] &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$HOME&#x2F;.claude&#x2F;hooks&#x2F;wezterm-claude-state.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; waiting; exit 0&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-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;Stop&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;hooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [ { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;type&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;command&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-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;[ -n &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$WEZTERM_PANE&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ] &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$HOME&#x2F;.claude&#x2F;hooks&#x2F;wezterm-claude-state.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; done; exit 0&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-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;SessionEnd&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;hooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [ { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;type&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;command&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-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;[ -n &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$WEZTERM_PANE&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ] &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$HOME&#x2F;.claude&#x2F;hooks&#x2F;wezterm-claude-state.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; clear; exit 0&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-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;exit 0&lt;&#x2F;code&gt;で閉じているのは、フックが失敗してもClaude Code本体の動作を妨げないためです。&lt;code&gt;UserPromptSubmit&lt;&#x2F;code&gt;にだけ付いている&lt;code&gt;prune&lt;&#x2F;code&gt;は、生きているペインの一覧と突き合わせて不要になった状態ファイルを削除する指示です。毎回走らせると重いので、ターンの開始時だけに限っています。&lt;&#x2F;p&gt;
&lt;p&gt;呼ばれるスクリプトの中身を見ていきます。最初に&lt;code&gt;$WEZTERM_PANE&lt;&#x2F;code&gt;の有無を調べ、無ければ何もせずに終了します。WezTerm以外のターミナルでClaude Codeを起動したときに、余計な副作用を出さないためです。あとはこの変数をファイル名にして状態を書き込むだけです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;~&#x2F;.claude&#x2F;hooks&#x2F;wezterm-claude-state.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# WezTerm 以外のターミナルでは何もしない&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 z-operator&quot;&gt; -n&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;${WEZTERM_PANE&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-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 z-operator&quot;&gt; ||&lt;&#x2F;span&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;dir&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;${XDG_CACHE_HOME&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-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell z-punctuation z-definition z-variable&quot;&gt;cache}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;wezterm-claude-state&amp;quot;&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;mkdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -p &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$dir&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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;dev&#x2F;null&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; 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-source&quot;&gt;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-other z-normal z-shell&quot;&gt;$dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$WEZTERM_PANE&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-keyword&quot;&gt;case&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;$state&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&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;clear&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;&amp;quot;&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-entity z-name z-function&quot;&gt; rm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -f &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$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-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-support z-function z-builtin&quot;&gt; printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;%s&amp;#39; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$state&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; &amp;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;$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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;dev&#x2F;null&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;残りはペインを明滅させる部分です。WezTermの&lt;code&gt;visual_bell&lt;&#x2F;code&gt;はBEL文字の受信で発火するので、ペインの端末にBELを書き込みます。ここが少しだけ厄介でした。フックは制御端末を持たない子プロセスとして起動されるため、&lt;code&gt;&#x2F;dev&#x2F;tty&lt;&#x2F;code&gt;を開こうとしても&lt;code&gt;device not configured&lt;&#x2F;code&gt;で失敗します。&lt;&#x2F;p&gt;
&lt;p&gt;一方、Claude Code本体はペインのptyを制御端末として持っています。そこで&lt;code&gt;ps&lt;&#x2F;code&gt;で親プロセスを遡り、最初に見つかった端末へBELを書き込みます。直近の親はフックを起動したシェルで端末を持たないため、見つかるまで数段たどります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;~&#x2F;.claude&#x2F;hooks&#x2F;wezterm-claude-state.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;find_tty&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; pid&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;$PPID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-string&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; 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-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$i&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&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ] &amp;amp;&amp;amp; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -n&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;$pid&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; ] &amp;amp;&amp;amp; [&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;$pid&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ] &amp;amp;&amp;amp; [&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;$pid&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;1&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; do&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;  set&lt;&#x2F;span&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-entity z-name z-function&quot;&gt;ps&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -o tty=,ppid= -p &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$pid&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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;dev&#x2F;null&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-punctuation z-definition z-variable z-source&quot;&gt; $#&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -ge&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&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-keyword&quot;&gt; return&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;  case&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;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-punctuation z-definition z-string z-string&quot;&gt;  &amp;quot;?&amp;quot;&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;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-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-support z-function z-builtin&quot;&gt;   printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&#x2F;dev&#x2F;%s\n&amp;#39; &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-keyword&quot;&gt;   return&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-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-source&quot;&gt;  pid&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-parameter&quot;&gt;$2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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;span class=&quot;z-entity z-name z-function&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&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;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;span class=&quot;z-keyword&quot;&gt; return&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;&#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-keyword&quot;&gt;case&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;$state&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&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;waiting&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; done&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; dev&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;find_tty&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt; printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;\a&amp;#39;&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-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;$dev&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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;dev&#x2F;null&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Code本体にも&lt;code&gt;preferredNotifChannel&lt;&#x2F;code&gt;を&lt;code&gt;terminal_bell&lt;&#x2F;code&gt;にすればベルを鳴らす機能がありますが、こちらは通知イベントでしか鳴りません。完了時にも光らせたかったので、フック側で鳴らすことにしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;WezTerm側の設定&quot;&gt;WezTerm側の設定&lt;&#x2F;h2&gt;
&lt;p&gt;WezTerm側がやることは、開いているペインを順に見て状態ファイルを読み、アイコンとペインIDを並べた文字列を組み立てることだけです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot; data-name=&quot;~&#x2F;.config&#x2F;wezterm&#x2F;wezterm.lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; CLAUDE_STATE_DIR&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; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;os.getenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;XDG_CACHE_HOME&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;or&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;os.getenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;HOME&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string z-string&quot;&gt; &amp;quot;&#x2F;.cache&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string z-string&quot;&gt; &amp;quot;&#x2F;wezterm-claude-state&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;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; CLAUDE_ICON&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; wezterm.nerdfonts.md_robot_outline&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;local function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; read_state_file&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;pane_id&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; local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; f&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&quot;&gt; io.open&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(CLAUDE_STATE_DIR&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;quot;&#x2F;&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-source&quot;&gt; pane_id, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;r&amp;quot;&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-keyword&quot;&gt; if&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; f&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-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt; end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt; local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; st&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-class&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;read&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;*l&amp;quot;&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-entity z-name z-class&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;close&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-keyword&quot;&gt; if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; st&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&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; or&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; st&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;&amp;quot; &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-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt; end&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; st&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&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;local function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; collect_claude_states&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;window&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; local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; icons&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; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  waiting&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; wezterm.nerdfonts.md_bell_ring_outline,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  running&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; wezterm.nerdfonts.md_progress_clock,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  done&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; wezterm.nerdfonts.md_check_circle_outline,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-keyword&quot;&gt; local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; marks&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; {}&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; _, tab&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;mux_window&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;():&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;tabs&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _, p&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;tab&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;panes_with_info&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;   local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; st&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&quot;&gt; read_state_file&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(p.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;pane&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;pane_id&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-keyword&quot;&gt;   if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; st&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; and&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; icons[st] &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;    -- グリフは幅が広く数字と詰まるので間に空白を入れる&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    marks[&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;marks&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-source&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-source&quot;&gt; icons[st] &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; &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-source&quot;&gt; p.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;pane&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;pane_id&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-keyword&quot;&gt;   end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt; end&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-keyword z-operator&quot;&gt; #&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;marks&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-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-keyword&quot;&gt;  return&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;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-keyword&quot;&gt; end&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-punctuation z-definition z-string&quot;&gt; &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-source&quot;&gt; CLAUDE_ICON&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; &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&quot;&gt; table.concat&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(marks, &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;span class=&quot;z-source&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-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-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;読むのは開いているペインの分だけなので、Claude Codeが異常終了して残った状態ファイルは表示に出てきません。ペインIDを&lt;code&gt;p.pane:pane_id()&lt;&#x2F;code&gt;とメソッドで取っているのは、WezTerm 20240203では&lt;code&gt;panes_with_info()&lt;&#x2F;code&gt;が返す値から&lt;code&gt;pane_id&lt;&#x2F;code&gt;をフィールドとして取り出せず、nilになるためです。&lt;&#x2F;p&gt;
&lt;p&gt;この関数は&lt;code&gt;pcall&lt;&#x2F;code&gt;で包んでから登録します。例外を投げるとタブライン全体が更新されなくなるためです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot; data-name=&quot;~&#x2F;.config&#x2F;wezterm&#x2F;wezterm.lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; claude_states&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;window&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; local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ok, result&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&quot;&gt; pcall&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(collect_claude_states, window)&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-keyword z-operator&quot;&gt; not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ok&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;  wezterm.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;log_error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;claude_states: &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&quot;&gt; tostring&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(result))&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-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-keyword&quot;&gt; end&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; result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&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;tabline.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setup&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-source&quot;&gt; sections&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; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  tabline_x&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; { claude_states, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;ram&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;cpu&amp;quot; &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-source&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;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ペインの明滅は&lt;code&gt;visual_bell&lt;&#x2F;code&gt;の設定です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot; data-name=&quot;~&#x2F;.config&#x2F;wezterm&#x2F;wezterm.lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;config.audible_bell&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;quot;Disabled&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;config.visual_bell&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; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt; fade_in_duration_ms&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; 200&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-source&quot;&gt; fade_in_function&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;quot;EaseIn&amp;quot;&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-source&quot;&gt; fade_out_duration_ms&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; 200&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-source&quot;&gt; fade_out_function&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;quot;EaseOut&amp;quot;&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-source&quot;&gt; target&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;quot;BackgroundColor&amp;quot;&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-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後に、入力待ちのペインへ移動するキーバインドです。CMD-SHIFT-jで入力待ちのペインにジャンプできます。ペインを探す手間がなく非常に便利です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot; data-name=&quot;~&#x2F;.config&#x2F;wezterm&#x2F;wezterm.lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;table.insert&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(config.keys, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt; key&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;quot;j&amp;quot;&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-source&quot;&gt; mods&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;quot;CMD|SHIFT&amp;quot;&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-source&quot;&gt; action&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; wezterm.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;action_callback&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&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;window&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;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _, tab&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;window&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;mux_window&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;():&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;tabs&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;   for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _, p&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;tab&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;panes_with_info&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; read_state_file&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(p.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;pane&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;pane_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string z-string&quot;&gt; &amp;quot;waiting&amp;quot; &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;     p.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;pane&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;activate&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-keyword&quot;&gt;     return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;   end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt; end&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-source&quot;&gt;})&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;claude-stateを入れてから、画面を見張る作業が通知を待つ作業に変わりました。Claude Codeが考えている間に別のペインへ移って手を動かせるようになったのが、一番の変化です。&lt;&#x2F;p&gt;
&lt;p&gt;MulmoTerminalは複数のエージェントを並べて動かすことを前提にしたツールなので、そこまでの使い方をするなら素直に導入した方が早いと思います。今回作ったのは、WezTerm上で「どのペインが人間のレスを待っているか」だけを知りたい、という限られた用途のものです。なお、tmuxを挟んだ場合の動作は試していません。&lt;&#x2F;p&gt;
&lt;p&gt;開発や日常の作業にClaude Codeを適用し始めると、あっという間に並行して複数のClaude Codeを稼働させる状況になります。
Claude Codeを1本しか動かさないのであれば目の前の画面を見ていれば済む話ですが、
それ以上に増えた瞬間から自身も効率的に作業しClaude Codeのレス待ちにタイムリーに反応していく必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;これは、せっかく生成AIを使用しているのに、自分自身がボトルネックにならないための仕組みです。&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;MulmoTerminal. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;receptron&#x2F;mulmoterminal&quot;&gt;GitHub - receptron&#x2F;mulmoterminal&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;tabline.wez. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;michaelbrusegard&#x2F;tabline.wez&quot;&gt;GitHub - michaelbrusegard&#x2F;tabline.wez&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;WezTerm. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wezterm.org&#x2F;&quot;&gt;公式ドキュメント&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Claude Code. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.claude.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;hooks&quot;&gt;Hooks reference&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">MulmoTerminalで感心したのは、どのエージェントが人間を待っているか一目で分かる点でした。同じ仕掛けをターミナルの乗り換えなしにWezTermとClaude Codeだけで作りました。タブラインに実行中・入力待ち・完了を並べ、応答が要るペインは明滅します。</summary>
        </entry><entry xml:lang="en">
        <title>住所録をMulmoClaudeでさくっと作る</title>
        <published>2026-07-28T05:10:06+09:00</published>
        <updated>2026-07-28T05:10:06+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/building-contacts-database-mulmoclaude/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/building-contacts-database-mulmoclaude/</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;07&amp;#x2F;building-contacts-database-mulmoclaude&amp;#x2F;cover.webp?h=bc0a257921f64a6115bd&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;h2 id=&quot;愛用した住所録アプリ_PowerAddressが動かなくなる&quot;&gt;愛用した住所録アプリ PowerAddressが動かなくなる&lt;&#x2F;h2&gt;
&lt;p&gt;わが家では、20年に渡って年賀状の住所録管理をPowerAddressを使用して管理しています。&lt;&#x2F;p&gt;
&lt;p&gt;毎年のようにアップグレードが必要な一般的な宛名書きアプリと比べると、
住所録管理に特化しているため、機能的に見劣りする部分はありました。
しかし、郵便番号から住所補完や年賀状の履歴管理、宛名の印字など基本的な機能は
揃っており、私には十分でした。
何より、アップグレード料金が発生することなく長年使えている点が気に入っていました。&lt;&#x2F;p&gt;
&lt;p&gt;ところが、2026年5月に「v5.1が最後のバージョン、Macアプリ版は注意が必要」というアナウンスがPowerAdress
の公式サイトでなされています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;FileMakerは、Apple傘下のClaris社が開発するデータベース構築ツール&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;PowerAddressはFileMakerで作成され、FileMakerのランタイム作成機能(アプリ版を作成する機能)を利用して、
Windows版とMac版がリリースされています。&lt;&#x2F;p&gt;
&lt;p&gt;ところが、FileMakerは2020年のFileMaker 19からランタイム作成機能を完全に削除しました。
このため、アプリ版のPowerAddressの開発が不可能となり、2020年にリリースされたPowerAddress v5.1が最後のバージョンとアナウンスされました。&lt;&#x2F;p&gt;
&lt;p&gt;さらにPowerAddress Mac 5.1のランタイムはIntelベースです。AppleはIntelアプリを動かすRosetta 2
2027年リリース予定のmacOS 28からは未サポートになるとアナウンスしており、そうなると、PowerAddress Mac版は起動すらできなくなります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;住所録の移行先の検討&quot;&gt;住所録の移行先の検討&lt;&#x2F;h2&gt;
&lt;p&gt;もう来年に迫っているので、移行先を検討してみました。&lt;&#x2F;p&gt;
&lt;p&gt;PowerAddressの公式アナウンスではFileMaker版やFileMakerテンプレート版への移行も案内されていました。
いずれもFileMaker本体の購入が必要です。
現在のFileMakerはサブスクリプションモデルで月額2,000円以上かかり、年賀状シーズンくらいしか使わない住所録管理としてはコストが見合いません。
更にPowerAddressの開発自体は終了するようなので、移行したところで将来はありません。&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;receptron&#x2F;mulmoclaude&quot;&gt;MulmoClaude&lt;&#x2F;a&gt;へ移行することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;receptron&#x2F;mulmoclaude&quot;&gt;MulmoClaude&lt;&#x2F;a&gt;は、マイクロソフトでWindows 95、Windows 98、
Internet Explorer 3.0&#x2F;4.0のチーフアーキテクトを勤めた中島聡氏がオープンソースで開発するAIアシスタントです。
最近私もほぼ日々の生活で全面的に利用するようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;このMulmoClaudeにスキーマ駆動のコレクションを管理する機能があるため、住所録程度であれば十分対応できます。
MulmoClaudeはClaude Code CLIをバックエンドに利用するため、多少の準備は必要です。
とはいえ、以前に比べれば非エンジニアでも十分に扱えるところまでハードルは下がっていると感じています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MulmoClaudeで住所録を作る&quot;&gt;MulmoClaudeで住所録を作る&lt;&#x2F;h2&gt;
&lt;p&gt;実施したことは、PowerAddressから出力したCSV形式の住所録を読み込ませて、
「これを取り込む為のスキーマを定義して取り込んで」と依頼しただけです。&lt;&#x2F;p&gt;
&lt;p&gt;取り込まれたデータの不要な項目を削除したり、属性をtextからenumに変更したりして調整しました。
これだけで、後述のフィルタリングやカンバン表示にも対応する、使いやすいコレクションへと仕上がりました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;building-contacts-database-mulmoclaude&amp;#x2F;table.webp?h=d7beb3a2556f553c8364&quot;
  alt=&quot;住所録テーブル表示&quot; width=&quot;1906&quot; height=&quot;1184&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;住所録テーブル表示&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;MulmoClaudeでは属性がenumのフィールドがあればカンバン方式で表示可能なので、
これを利用して50音でフィルタリングするPowerAddressの機能を疑似的に再現できました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;building-contacts-database-mulmoclaude&amp;#x2F;kanban.webp?h=3f8064150a27807ecc58&quot;
  alt=&quot;住所録カンバン表示&quot; width=&quot;1913&quot; height=&quot;1125&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;住所録カンバン表示&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;各レコードは、郵便番号データベースからの住所補完や連名管理も可能です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;building-contacts-database-mulmoclaude&amp;#x2F;record.webp?h=bd719cb8231509cc1cde&quot;
  alt=&quot;住所録レコード表示&quot; width=&quot;726&quot; height=&quot;712&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;住所録レコード表示&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;自動化についても「郵便番号データベースを月次で自動更新して、レコードの不整合があればチェックしてほしい」と要件を伝えただけで、
必要なスケジュール設定やスクリプトはMulmoClaudeが自分で作成してくれました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;20年使い続けたPowerAddressの終了は残念でしたが、住所録という個人情報は手元で管理し続けるという方針は変えずに済みました。
私がCSVを読み込ませて要件を伝えただけで、スキーマ定義からカンバン表示、月次の自動更新まで一通りMulmoClaudeが作ってくれたのは想像以上でした。&lt;&#x2F;p&gt;
&lt;p&gt;現在はFastmailカレンダーと連動したスケジュール管理やTODO管理、資産ダッシュボード、趣味の音楽ノウハウのWiki管理などもMulmoClaudeで行なっています。
個人レベルのちょっとしたデータ管理であれば、専用アプリを探さなくてもAIアシスタントに任せられる場面は今後も増えていきそうです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">20年使ってきた住所録アプリPowerAddressが、FileMakerの仕様変更とmacOSの対応終了が重なって使えなくなろうとしています。CSVを読み込ませて要件を伝えるだけで、スキーマ定義からカンバン表示まで住所録を作ってくれたAIアシスタントMulmoClaudeへの移行を紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>AWSにクレジットカードが登録できない場合(三井住友カード)</title>
        <published>2026-07-24T11:55:34+09:00</published>
        <updated>2026-07-24T11:55:34+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/aws-card-registration-3ds-authentication-declined/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/aws-card-registration-3ds-authentication-declined/</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;07&amp;#x2F;aws-card-registration-3ds-authentication-declined&amp;#x2F;cover.webp?h=830e6921033350fde452&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;よくある話だと思いますが、AWSでクレジットカードを変更する際にハマったので、その対処法をまとめておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWSにクレジットカードが登録できない状況&quot;&gt;AWSにクレジットカードが登録できない状況&lt;&#x2F;h2&gt;
&lt;p&gt;AWSの管理アカウントで、新しいクレジットカードを支払い方法として登録しようとしたところ、
&lt;q&gt;Your authentication was declined.&lt;&#x2F;q&gt; というエラーが出て登録できませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;最初はカード会社側の問題を疑い、以下を確認しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;カード自体は問題ない(別のオンラインサービスには問題なく登録できた)&lt;&#x2F;li&gt;
&lt;li&gt;カードの利用明細アプリを見ても、AWSからの少額認証(オーソリ)の記録が一切ない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;AWSサポートに問い合わせたところ、AIでの回答は次のようなものでした。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;AWS Japanのアカウントは2025年3月以降、新規クレジットカード登録時に3Dセキュア(3DS)による本人認証が必須になっている。「Your authentication was declined」は、この3DS認証ステップが完了しなかったことを示している。&lt;br &#x2F;&gt;
(英語だったため、要約して意訳しています)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;つまり単なるカードの与信エラーではなく、3Dセキュア連携がどこかで途切れていることが原因だという説明でした。&lt;&#x2F;p&gt;
&lt;p&gt;ただし実際には、AWS側が案内するような「銀行の3DS認証ページへのリダイレクト」や「認証用のポップアップ」自体が一度も表示されません。
Chromeの通常ウィンドウ、拡張機能をすべて無効にしたシークレットウィンドウのどちらで試しても結果は同じで、画面遷移なしにいきなり&quot;declined&quot;のメッセージが表示されます。&lt;&#x2F;p&gt;
&lt;p&gt;ブラウザ側の問題は考えにくく、3DS認証のリクエストがそもそもカード発行会社(三井住友カード)まで届いていないか、届く前にどこかで弾かれている可能性が高い、と推定しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;解決策&quot;&gt;解決策&lt;&#x2F;h2&gt;
&lt;p&gt;結局のところ、根本原因(AWSとカード会社のどちらの連携不具合か)を完全に特定できません。
ここは先人たちの対応方法に倣いました。&lt;&#x2F;p&gt;
&lt;p&gt;「AWSクレジットカード登録できない」などと検索すると、同じような状況に至った記事がたくさん
でてきます。
そこで上がっている解決策は、解決自体は驚くほどシンプルです。&lt;&#x2F;p&gt;
&lt;p&gt;カード会社に連絡し「3Dセキュアのセキュリティ解除を一時的にしてくれ」と依頼するだけです。&lt;&#x2F;p&gt;
&lt;p&gt;具体的には私が使っている三井住友カードのサポートに電話し、「AWSにこのカードを登録しようとすると3Dセキュアの連携がうまくいかない」とだけ伝えたところ、オペレーターは即座に対応し、次のような処置を提案しくれました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;カードのセキュリティ設定を15分後に解除&lt;&#x2F;li&gt;
&lt;li&gt;24時間後に自動的に元の設定へ戻す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この対応の直後にAWS側でカード登録を再試行したところ、あっさり成功しました。&lt;&#x2F;p&gt;
&lt;p&gt;つまり実態としては、カード発行会社側のオンライン決済向けセキュリティ機構(3DS絡みの何らかの防御設定)が、AWSからの認証リクエストを何らかの理由で処理できませんでした。カード会社側で一時的にこの認証というゲートを外してもらうだけで解決するという、拍子抜けするほどシンプルな結末でした。&lt;&#x2F;p&gt;
&lt;p&gt;AWS Japanの3DS必須化以降、同様の「認証拒否」報告はコミュニティ上でも複数見かけたので、同じ現象に遭遇している人は少なくないと思います。&lt;&#x2F;p&gt;
&lt;p&gt;仕組みとしては、AWSは入力されたカード番号全体を決済代行システム（アクワイアラ／決済プロバイダ）に送り、そこから国際ブランドのネットワーク（Visa Secure &#x2F; Mastercard Identity Check等）を経由して三井住友カード（イシュア）へ認証リクエストが飛びます。&lt;&#x2F;p&gt;
&lt;p&gt;この時、三井住友カード側のイシュア認証サーバー（ACS）が受信し、内蔵するリスク判定エンジンが高リスクトランザクションと判断して自動ブロック(silent reject)しているのでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;直接ブロックしているのは三井住友カード側ですが、他のサービスでは発生しないことから&lt;strong&gt;AWS側（またはその決済プロバイダ）に問題があるのではないか&lt;&#x2F;strong&gt;と考えています。以下
のいずれかでしょう。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;リスクスコアが高くなりやすいデータを送っている&lt;&#x2F;dt&gt;
&lt;dd&gt;AWSが3DSリクエストを送る際、端末情報・ブラウザ情報・加盟店データなどの「リスク判定に必要なコンテキスト情報」を十分にイシュア（三井住友カード）へ渡せていない、または渡しているデータの形式がカード会社の判定基準と噛み合っていない可能性がある。&lt;&#x2F;dd&gt;
&lt;dt&gt;判定をフリクションレス（画面なし）で通そうとしすぎる&lt;&#x2F;dt&gt;
&lt;dd&gt;本来リスクが疑わしいなら「ワンタイムパスワード画面（チャレンジ認証）を出す」という選択肢をカード会社に取らせるべきだが、AWSのリクエストの作法がチャレンジ認証へ遷移せず、そのままSilent Reject（即時拒否）となる仕様・データ構造という可能性がある。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;めったに行なわないオペレーションですが、改善してほしいものです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;(余談)_カード会社AI音声との格闘&quot;&gt;(余談) カード会社AI音声との格闘&lt;&#x2F;h2&gt;
&lt;p&gt;三井住友カードのサポート窓口は、まず全面的にAI音声応対していました。&lt;&#x2F;p&gt;
&lt;p&gt;問い合わせと最初に本人確認のために生年月日を聞かれます。
私の発話が明瞭でないのか、これがなかなか正しく聞き取ってもらえません。
「19XX年XX月2日」のように答えても認識されず、「5日」と認識されてします。
最終的に西暦・月・日をすべて数字だけの8桁の羅列(19XXXX02)として一気に読み上げたところ、ようやく認識さました。&lt;&#x2F;p&gt;
&lt;p&gt;さらに厄介なのは、今回のような「3Dセキュアの連携不具合」のような込み入った相談内容はAI音声だけでは解決できないという点です。
AIが想定しているFAQの選定フローのための一連のやりとりをして、
FAQになくAIで対応不能と結論付けさせオペレーターに繋ぐフローをうまく起動する必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;これが地味に面倒でした。定型的な用件(残高照会や紛失連絡など)であればAI音声で完結するのだろうが、少しでもイレギュラーな相談だと、まず「これは人に相談すべき内容だ」とAIに判断させるところから上手く落としてあげる必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;結果的に、技術的な不具合そのものよりも、電話サポートのAI(音声認識+フロー分岐)を突破する方に時間がかかった、というのがやるせない気持ちに
なります。&lt;&#x2F;p&gt;
</content>
        <summary type="html">AWSに新しいクレジットカードを登録しようとしたら「Your authentication was declined」の一言で弾かれ続けました。3Dセキュアの認証画面もポップアップも一度も出ないまま拒否され続けるこの症状でした。
</summary>
        </entry><entry xml:lang="en">
        <title>AWS障害でPayPayが利用不可に フランクフルトの一AZが世界に波及</title>
        <published>2026-07-16T00:00:00+00:00</published>
        <updated>2026-07-16T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/aws-cloudfront-outage-paypay/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/aws-cloudfront-outage-paypay/</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;07&amp;#x2F;aws-cloudfront-outage-paypay&amp;#x2F;cover.webp?h=74290d2761d8a8cd538e&quot;
  alt=&quot;Cover&quot; width=&quot;1376&quot; height=&quot;768&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;2026年7月16日17時40分頃、Amazon Web Services(AWS)のCDNサービス「Amazon CloudFront」で大規模な障害が発生しました。日本の決済サービス「PayPay」をはじめ、ニコニコ生放送、はてなブログ、noteなど多数のサービスに影響が出ています。PayPayではアプリの読み込みや決済処理ができなくなり、公式サイトや障害情報ページ自体にもアクセスできない状態に陥りました。障害発生後、PayPay側は決済手段として「オフライン支払いモード」への切り替えを利用者に案内しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;障害詳細&quot;&gt;障害詳細&lt;&#x2F;h2&gt;
&lt;p&gt;発生時刻は日本時間で2026年7月16日17時40分頃(AWS公式の調査開始は現地時間1:44 AM PDT)です。症状としては、CloudFront経由のアクセスで504 Gateway Timeoutなどの5xxエラーが多発しました。日本国内ではPayPay、ニコニコ生放送、はてなブログ、noteなどが影響を受けたほか、日本、スペイン、ドイツ、オーストラリア、スウェーデン、フランス、米国、英国など世界9か国39都市以上で障害が報告されています。&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;PayPay&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;&#x2F;tr&gt;
&lt;tr&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;note&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;AWSのステータスサイトによると、障害の直接的な引き金はCloudFrontの「VPC Origins」機能でした。VPC Originsは、CloudFrontから顧客のプライベートVPC内にあるバックエンドリソースへ安全に接続するための機能で、これを利用している顧客側でエラーが多発しました。一方、標準的なS3オリジンなど、VPC Originsを使わない構成は影響を受けていません。AWSは応急的な回避策として、VPC Originsを使わない構成に切り替えることでエラーを回避できるとアナウンスしています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;一地域の障害が世界規模に広がった理由&quot;&gt;一地域の障害が世界規模に広がった理由&lt;&#x2F;h2&gt;
&lt;p&gt;今回の障害で興味深いのは、技術的な発生源が非常に局所的だった点です。障害の起点は、EU-CENTRAL-1(フランクフルト)リージョンの単一アベイラビリティゾーン「euc1-az2」に限定されていました。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、物理的な不具合はドイツの1つのデータセンター群(AZ)内で起きたものにすぎません。しかし、CloudFrontはグローバルに分散した単一のCDNネットワークとしてVPC Origins接続を提供する仕組みになっているため、フランクフルトの一部で生じた問題が、世界中のエッジロケーション経由で各国のサービスへ波及する結果となりました。&lt;&#x2F;p&gt;
&lt;p&gt;これは、CDNのようにグローバルに一体運用されるインフラでは、1つのリージョンやAZの障害が地理的に無関係な地域にまで影響しうることを示す典型例といえます。東京リージョン自体には障害の原因はなく、あくまでフランクフルト発、世界巻き込み型の障害でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;障害を事前に防げたか&quot;&gt;障害を事前に防げたか&lt;&#x2F;h2&gt;
&lt;p&gt;クラウドを利用したシステム設計では、どのような機能であっても一時的に利用できなくなる可能性を前提に、二重化やフェイルオーバーの仕組みを組み込むのが一般的な考え方です。&lt;&#x2F;p&gt;
&lt;p&gt;今回の件で言えば、CDNをCloudFrontという単一のサービスに依存し、単一障害点になっていたことが技術的な問題点だったと考えられます。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、CloudFrontは多くの技術者にとって自システムの外側に当たり前に存在するインフラという感覚に近く、これ自体が障害点になり得るという認識を持てていなかったのではないかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;仮にその認識を持てていたとしても、実際に設計へ組み込むにはマルチCDN構成、例えばCloudflareなど別系統のCDNとの併用が必要になります。これはコストとのバランスから、多くの企業にとって現実的な選択肢とは言いにくいのが実情です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回のPayPay障害は、PayPay自体のシステム不具合ではなく、利用しているAWS CloudFrontの障害が波及したものです。直接の原因はCloudFrontの「VPC Origins」機能における不具合で、発生源はフランクフルト(EU-CENTRAL-1)の単一AZでしたが、CloudFrontのグローバル構成により世界規模で影響が拡大しました。東京リージョン固有の問題ではなく、VPC Originsを使わないオリジン構成(S3など)は影響を受けていません。&lt;&#x2F;p&gt;
&lt;p&gt;大規模なグローバルCDNに依存するサービスが増える中、一地域の局所的な障害が世界中の決済・コンテンツサービスに連鎖する構造的リスクを改めて浮き彫りにした事例といえます。&lt;&#x2F;p&gt;
&lt;p&gt;このブログも以前は&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;01&#x2F;blog-to-zola-aws-cleanup&#x2F;&quot;&gt;Amazon Amplify + CloudFrontで運用していました&lt;&#x2F;a&gt;が、現在はCloudflareに移行しているため今回の障害の影響は受けませんでした。ただし、CloudFrontとCloudflareはどちらも巨大なグローバルAnycast網であり、同種の相関障害リスク構造を持っています。実際、Cloudflare自体も過去に世界規模の障害を起こしています。今回無傷だったのはたまたまで、CDNの選定自体がこの種のリスクを下げるわけではありません。&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;ITmedia NEWS.「AWSで障害 「CloudFront」世界規模で不調 PayPayに影響、noteやニコニコ生放送もつながりにくく」&lt;&#x2F;li&gt;
&lt;li&gt;ケータイ Watch.「PayPayの障害はAWSが原因、決済は「オフライン支払いモード」を」&lt;&#x2F;li&gt;
&lt;li&gt;BigGo ファイナンス.「PayPayで大規模障害、AWSのCDN不調が波及 公式サイトもダウン」&lt;&#x2F;li&gt;
&lt;li&gt;GIGAZINE.「AWSのCDNサービスで大規模障害発生、各種ウェブサイトに接続しにくい状態が発生」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;note.com&#x2F;zephel01&#x2F;n&#x2F;n274043a396db?hl=en&quot;&gt;note - zephel01&lt;&#x2F;a&gt;. &quot;Summary of AWS (Mainly CloudFront) Outage (July 16, 2026)&quot;&lt;&#x2F;li&gt;
&lt;li&gt;Sunday Guardian Live.「AWS CloudFront Outage Today: Amazon Web Services Confirms Service Disruption as &#x27;5xx Errors&#x27; Hit Websites Across Multiple Regions」&lt;&#x2F;li&gt;
&lt;li&gt;The Nightly.「AWS outage update: CloudFront experience global outage, operation issue」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">2026年7月16日、AWSのCDN「CloudFront」で障害が発生し、PayPayの決済やニコニコ生放送、はてなブログなど多数のサービスに影響が出ました。発生源はフランクフルトの単一AZという局所的な障害でしたが、なぜ日本を含む世界9か国に波及したのか、その仕組みを整理します。</summary>
        </entry><entry xml:lang="en">
        <title>CLIエージェント時代のMCP設計論：Fastmailのウィジェット実装から考える「フォールバック」の重要性</title>
        <published>2026-07-15T14:04:12+09:00</published>
        <updated>2026-07-15T14:04:12+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/fastmail-mcp/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/fastmail-mcp/</id>
        
            <content type="html">&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;fastmail-mcp&amp;#x2F;cover.webp?h=c4d41dc3873f422de207&quot;
  alt=&quot;Cover&quot; width=&quot;1376&quot; height=&quot;768&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;2026年4月22日、National Email Dayに合わせて、私がメインの個人メールとして利用しているFastmailが公式MCP&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;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&#x2F;blog&#x2F;an-mcp-server-for-fastmail&#x2F;&quot;&gt;An MCP server for Fastmail — National Email Day | Fastmail Blog&lt;&#x2F;a&gt;）。
エンドポイントは &lt;code&gt;https:&#x2F;&#x2F;api.fastmail.com&#x2F;mcp&lt;&#x2F;code&gt;です。
Claude・ChatGPTなど任意のAIクライアントから、自然言語で「明日の予定は？」「Sarahへの返信を下書きして」「歯医者の住所を教えて」といった操作を、実際のメール・連絡先・カレンダーに対して実行できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;この記事は2ヶ月ほど、Fastmail MCPを利用した評価をまとめたものです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Fastmail_MCPで何ができるか？&quot;&gt;Fastmail MCPで何ができるか？&lt;&#x2F;h2&gt;
&lt;p&gt;接続はOAuthで認可し、アクセス権限は次の3段階から選択するようになっています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;read-only&lt;&#x2F;strong&gt;: メール・連絡先・カレンダーの閲覧のみ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;write&lt;&#x2F;strong&gt;: 下書き保存、連絡先・予定の編集&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;send&lt;&#x2F;strong&gt;: メール送信&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Fastmailが強調したのは、受信箱にチャットボットを組み込んだり、メールをモデルに流してもいないことです。
生成AIへのインターフェイスとして、MCPの入り口だけ用意しユーザー自身がアクセスできるAIツールを選ぶという姿勢です。
MCPというオープン標準に乗ることで、特定ベンダーへのロックインを避けているわけです。&lt;&#x2F;p&gt;
&lt;p&gt;Fastmail MCPサーバーは、メール・カレンダー・連絡先・ノートの4領域にわたるツール群を提供しており、
アクセス権限（read-only &#x2F; write &#x2F; send）に応じて呼び出せる範囲が変わります。&lt;&#x2F;p&gt;
&lt;p&gt;以下が、MCPで呼び出し可能なツール一覧です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;ツール一覧（メール・カレンダー・連絡先・ノート）&lt;&#x2F;strong&gt;&lt;&#x2F;summary&gt;
&lt;p&gt;&lt;strong&gt;メール&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;search_email&lt;&#x2F;code&gt; — 条件を指定してメールを検索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;read_email&lt;&#x2F;code&gt; — 個別メールの本文・ヘッダーを取得&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;read_thread&lt;&#x2F;code&gt; — スレッド単位でメールをまとめて取得&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;draft_email&lt;&#x2F;code&gt; — 送信せず下書きとして保存（新規作成・返信・転送に対応、返信は&lt;code&gt;mode: reply&lt;&#x2F;code&gt;＋&lt;code&gt;emailId&lt;&#x2F;code&gt;でスレッドヘッダーや引用を自動処理、&lt;code&gt;replyAll&lt;&#x2F;code&gt;で全員返信も可能。本文はMarkdown入力に対応しており、送信時にHTML＋プレーンテキストへ自動変換される）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;send_email&lt;&#x2F;code&gt; — メールを即座に送信（send権限が必要）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;update_email&lt;&#x2F;code&gt; — 既読&#x2F;未読・フラグなどメールの状態を更新&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;archive_email&lt;&#x2F;code&gt; — メールをアーカイブ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;delete_email&lt;&#x2F;code&gt; — メールを削除&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;upload_attachment&lt;&#x2F;code&gt; — 添付ファイルをアップロード&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;list_folders&lt;&#x2F;code&gt; — フォルダ一覧を取得&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;list_identities&lt;&#x2F;code&gt; — 送信元として使える送信アイデンティティ（差出人アドレス）一覧を取得&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;カレンダー&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;list_calendars&lt;&#x2F;code&gt; — カレンダー一覧を取得&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;search_events&lt;&#x2F;code&gt; — 予定を検索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;create_event&lt;&#x2F;code&gt; — 予定を直接作成（確認なしでコミット）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;compose_event&lt;&#x2F;code&gt; — 予定の作成・編集をウィジェットとしてステージングし、ユーザーの確認後にコミット（&lt;code&gt;id&lt;&#x2F;code&gt;を渡せば既存イベントの編集、省略すれば新規作成）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;update_event&lt;&#x2F;code&gt; — 既存の予定を直接更新（確認を挟まない）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;delete_event&lt;&#x2F;code&gt; — 予定を削除&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;rsvp_event&lt;&#x2F;code&gt; — 招待された予定に出欠回答&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;連絡先&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;search_contacts&lt;&#x2F;code&gt; — 連絡先を検索（メール作成前のアドレス特定などに利用）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;create_contact&lt;&#x2F;code&gt; — 連絡先を新規作成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;update_contact&lt;&#x2F;code&gt; — 連絡先を更新&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;delete_contact&lt;&#x2F;code&gt; — 連絡先を削除&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;ノート&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;search_notes&lt;&#x2F;code&gt; — ノートを検索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;read_note&lt;&#x2F;code&gt; — ノートを取得&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;create_note&lt;&#x2F;code&gt; — ノートを新規作成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;update_note&lt;&#x2F;code&gt; — ノートを更新&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;delete_note&lt;&#x2F;code&gt; — ノートを削除&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;add_to_note&lt;&#x2F;code&gt; — 既存ノートに追記&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;set_memo&lt;&#x2F;code&gt; — メモ欄の内容を設定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;details&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;こうしたツールを組み合わせると、たとえば次のような使い方ができます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;朝、Claudeに「今日の予定と未読メールをまとめて」と頼むと、fastmailからカレンダーと直近の未読メールを読んで、1日の見通しをサマリーしてくれる&lt;&#x2F;li&gt;
&lt;li&gt;ChatGPTに「山田さんからの問い合わせに返信案を作って」と頼むと、連絡先からアドレスを確認したうえで返信の下書きを作成し、送信前に内容を確認できる&lt;&#x2F;li&gt;
&lt;li&gt;Claudeに「来週火曜の14時に田中さんとのミーティングを入れて」と頼むと、田中さんを出席者とした予定を登録できる&lt;&#x2F;li&gt;
&lt;li&gt;Claudeに「鈴木さんとの一連のメールのやりとりを確認して、鈴木さんの質問とその回答を1つのノートにまとめて」と頼むと、メールのやりとりを読み込んだうえで、要点を新しいノートとして作成する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ここまでがFastmail MCPで実現できることの紹介です。ここから先は、この2ヶ月の運用で見えてきた設計上の課題を掘り下げます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Fastmail_MCPのConfirmationの仕組み&quot;&gt;Fastmail MCPのConfirmationの仕組み&lt;&#x2F;h2&gt;
&lt;p&gt;Fastmail MCPには、AIエージェントが提案した操作をそのまま確定させず、いったんユーザーの確認を挟んでから反映する仕組みが用意されています。エージェントが意図と異なる内容で操作したり、そのまま実行してしまったりするリスクを抑えるためです。対象となる操作の内容を「ウィジェット」としてチャットUI上にステージングし、ユーザーがボタン操作で確認・修正してから初めて確定します。&lt;&#x2F;p&gt;
&lt;p&gt;たとえばカレンダーの予定作成・編集には、2つの経路が用意されています。&lt;code&gt;create_event&lt;&#x2F;code&gt;と&lt;code&gt;update_event&lt;&#x2F;code&gt;は呼び出すと即座に予定表へ反映され、参加者を招待する場合はその場で招待メールが送信されます。一方&lt;code&gt;compose_event&lt;&#x2F;code&gt;は、予定の内容をいったんこのウィジェットにステージングし、ユーザーが確認・修正してから初めてカレンダーに反映されます。&lt;&#x2F;p&gt;
&lt;p&gt;Fastmail MCPのツール群の中で、実際にこの確認の仕組みを使うのは次の4つです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compose_event&lt;&#x2F;code&gt; — 予定の作成・編集&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;delete_event&lt;&#x2F;code&gt; — 予定の削除&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;delete_contact&lt;&#x2F;code&gt; — 連絡先の削除&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;delete_note&lt;&#x2F;code&gt; — ノートの削除&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらのツールは、呼び出した時点では何もコミットされません。ステージングされた内容がウィジェットとして表示され、ユーザーがボタン操作で確認・修正してから初めて確定します。ツール自身の説明にも「成功はウィジェットが表示されたことを意味するのであって、削除が確定したことを意味しない」という趣旨の注記があり、実行結果を判定するにはウィジェットの応答を読み取るか、削除後に検索し直して存在を確認する必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;一方、次のツールは確認を挟まず直接コミットします。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;create_event&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;update_event&lt;&#x2F;code&gt; — 予定の直接作成・更新（参加者への招待・変更通知メールもその場で送信される）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;rsvp_event&lt;&#x2F;code&gt; — 招待への出欠回答&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;create_contact&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;update_contact&lt;&#x2F;code&gt; — 連絡先の直接作成・更新&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;update_note&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;add_to_note&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;set_memo&lt;&#x2F;code&gt; — ノート・メモの内容変更&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Fastmail MCPサーバー自身のツール説明にも「対話的なカレンダー操作では&lt;code&gt;compose_event&lt;&#x2F;code&gt;を優先し、ユーザーが確認できない場合にのみ&lt;code&gt;update_event&lt;&#x2F;code&gt;のような直接コミット系を使うべき」という指示が書かれています。つまりFastmail自身が、確認フローの有無をクライアント側の対話能力に委ねていることを認識しているわけです。&lt;&#x2F;p&gt;
&lt;p&gt;なお、メールに関するツールにはウィジェットによる確認が1つも用意されていません。メール送信（&lt;code&gt;send_email&lt;&#x2F;code&gt;）は&lt;code&gt;send&lt;&#x2F;code&gt;権限自体が&lt;code&gt;read-only&lt;&#x2F;code&gt;／&lt;code&gt;write&lt;&#x2F;code&gt;とは別に明示的な許可を必要とする仕組みになっているため、confirmation UIは用意されていないのでしょう。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;claude.aiはWeb版のClaudeを指します。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;この仕組みには、見過ごせない課題があります。
このウィジェットによる確認は、claude.aiでは上手く動作しますが、Claude Codeでは機能しません。
同じFastmail MCPサーバー、同じツール定義に接続していても、
確認フローが機能するかどうかがクライアント次第で変わってしまう、という非対称性が発生してしまっています。&lt;&#x2F;p&gt;
&lt;p&gt;なぜこのような差が生まれるのか、標準化の状況を整理します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;確認メカニズムの標準化とCLIの対応状況&quot;&gt;確認メカニズムの標準化とCLIの対応状況&lt;&#x2F;h2&gt;
&lt;p&gt;AIエージェントは、メール・カレンダー・連絡先といった、取り消しにくい実世界のデータを操作します。そのため、操作を確定する前にユーザーへ確認や追加入力を求める手段を、プロトコルレベルでどう用意するかは、MCP自体にとっても大きな課題でした。この課題に対して、MCPには現在2つの標準機構が用意されています。大まかに言うと、elicitationは会話の中でフォームに答えてもらう方式、MCP Appsは画面上にアプリの小さな操作画面を表示する方式です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;2025年6月にMCP仕様へ追加され、同年11月にURLモードが拡張された「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;modelcontextprotocol.io&#x2F;specification&#x2F;draft&#x2F;client&#x2F;elicitation&quot;&gt;elicitation&lt;&#x2F;a&gt;（誘発）」。
サーバーがユーザーに入力や確認を求める際、JSON Schemaで定義したフォーム（文字列・数値・真偽値・選択肢など）を送り、
クライアントが対話ダイアログを表示してユーザーの回答を返す、という仕組みが定義された。
iframeやHTMLレンダリングを必要とせず、accept（承認）・decline（拒否）・cancel（取り消し）の3種類の応答が標準化されている。&lt;&#x2F;li&gt;
&lt;li&gt;2025年11月にAnthropicとOpenAIが共同で提案した「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.modelcontextprotocol.io&#x2F;posts&#x2F;2025-11-21-mcp-apps&#x2F;&quot;&gt;MCP Apps&lt;&#x2F;a&gt;」という拡張仕様（SEP-1865）。サンドボックス化されたiframe内でHTMLを描画し、複雑なユーザー入力や確認操作をチャットUI上で完結させるための仕組みで、Fastmailの&lt;code&gt;compose_event&lt;&#x2F;code&gt;が使っているウィジェットもこれに基づいている。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この2つの標準は、CLI環境への対応状況が対照的です。Claude Code CLIはelicitationに対応しており、フォームモードのダイアログはターミナル上に自動的に表示され、設定なしにユーザーの回答をサーバーへ返せます。一方MCP Appsは、サンドボックス化されたiframeでHTMLを描画する設計が前提になっており、そもそもブラウザのようなレンダリング環境を必要とします。ターミナル上で動くClaude Codeには、この種のレンダリング面が存在しません。これはAnthropicがClaude Codeへの対応を怠っているのではなく、CLI&#x2F;エージェント実行環境全般が構造的に抱える制約です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;非対称性の正体：Fastmailの実装選択&quot;&gt;非対称性の正体：Fastmailの実装選択&lt;&#x2F;h2&gt;
&lt;p&gt;MCP Appsは任意拡張であり、公式ブログは義務ではなく推奨として次のような指針を明記しています。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Servers should provide text-only fallback for all UI-enabled tools and return meaningful content even when UI is unavailable, so they can serve both UI-capable and text-only hosts.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;UIに対応していないクライアントのためにも、意味のあるテキストベースのフォールバックを用意すべきだ、という趣旨です。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、Fastmailの場合、&lt;code&gt;compose_event&lt;&#x2F;code&gt;のような確認操作を、
MCP Appsのウィジェットではなくelicitationの仕組みにfallbackするように実装していれば、
claude.aiとClaude Codeのどちらでも確認自体は機能したはずです&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;。前節で見た非対称性の実体は、MCPやClaude Codeの限界ではなく、Fastmailがどちらの確認機構を選んだかという実装判断にあります。&lt;&#x2F;p&gt;
&lt;p&gt;ところがFastmail MCPが実際に提供しているフォールバックは、「ホストの&lt;code&gt;read-widget-context&lt;&#x2F;code&gt;ツールで結果を読み取るか、&lt;code&gt;search_events&lt;&#x2F;code&gt;で存在を確認する」という、確認手段の代替にとどまります。
ユーザーの確認そのものを完了させる、elicitationのようなテキストベースの経路は用意されていません。結果としてMCP Appsに対応していないクライアントでは、ステージングされた操作が確定されないまま残るか、エージェントが&lt;code&gt;update_event&lt;&#x2F;code&gt;のような直接コミット系ツールに頼らざるを得なくなります。&lt;&#x2F;p&gt;
&lt;p&gt;この記事で見てきた非対称性は、MCPというプロトコルが未成熟だから起きているのでも、Claude Codeが対話UIに対応していないから起きているのでもありません。MCPにはすでにelicitationとMCP Appsという2つの標準機構があり、Claude Codeはelicitationに正しく対応しています。Fastmailが、両方のクライアントで機能するelicitationをフォールバックとして使わず、片方のクライアントにしか効かないMCP Appsのウィジェットだけに頼ったことが、非対称性の直接の原因です。&lt;&#x2F;p&gt;
&lt;p&gt;Fastmail、および同様の設計を選ぶ他のMCPサーバーに対して考えられる改善の方向性は、次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compose_event&lt;&#x2F;code&gt;や&lt;code&gt;delete_event&lt;&#x2F;code&gt;のような操作に、MCP Appsのウィジェットに加えてelicitationベースのテキスト確認フローをフォールバックとして実装する&lt;&#x2F;li&gt;
&lt;li&gt;クライアントがMCP Apps・elicitationのどちらに対応しているかを見て、対応する機構へ自動的に切り替える&lt;&#x2F;li&gt;
&lt;li&gt;ツール説明文で「確認できない場合は直接コミット系を使え」とエージェントに指示するのではなく、プロトコルが提供する確認機構を正しく使い分けることで、直接コミットへのフォールバック自体を避ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Fastmail MCPはリリースされたばかりの機能であり、こうした設計上の判断の是非が表面化するのはむしろ健全なことです。MCPエコシステムには必要な標準がすでに揃っており、あとはツール提供側がそれを正しく使い分けるかどうかにかかっています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;ここまで見てきた非対称性は、誰にとっても等しく問題になるわけではありません。claude.aiやChatGPTのようなMCP Apps対応クライアントから使う分には、ウィジェットが正しくレンダリングされ、確認・修正・確定が意図通りに機能するため、実用上の支障はないはずです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;MulmoClaudeは中島聡氏が開発するClaude Codeを利用したローカルAIアシスタント育成プラットフォーム&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;私自身の利用実態で言えば、日常的なやりとりのほとんどをClaude Codeで行っています。特に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;receptron&#x2F;mulmoclaude&quot;&gt;MulmoClaude&lt;&#x2F;a&gt;をClaude Code CLIをバックエンドにしたアシスタントとして使う場面が多く、これもMCP Appsが前提とするブラウザ内蔵のレンダリング環境を持たない実行環境です。Claude Code自体はelicitationに対応していますが、MulmoClaudeがそれを自分のWeb UIへどこまで橋渡ししているかは未確認で、同じ制約を抱えている可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;実際、Claude Codeで&lt;code&gt;compose_event&lt;&#x2F;code&gt;を使って予定を追加したつもりが、ステージングされたウィジェットの確認が反映されないまま止まっており、予定自体が入っていなかったために予定を丸ごと飛ばしてしまったことがあります。&lt;&#x2F;p&gt;
&lt;p&gt;そのため、この記事で取り上げた非対称性は、私にとっては理論上の課題ではなく、日常的にツールの使い勝手を制限している具体的な制約です。ただしその原因は、MCPというプロトコルの限界ではなく、Fastmailが既存の解決策であるelicitationを今のところ使っていないという、一企業の実装判断にあります。&lt;&#x2F;p&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;Model Context Protocolの略。AIモデルと外部のデータソースやツールを安全に接続するための標準的なプロトコル &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;ただしelicitationのform modeは仕様上オブジェクト配列の編集を想定しておらず、&lt;code&gt;compose_event&lt;&#x2F;code&gt;ウィジェットと全く同じ編集体験になるとは限らない。 &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">「今日の予定と未読メールをまとめて」とAIに頼むだけで、実際のメールボックスが動く時代になりました。
愛用しているFastmailでも2026年4月に公式MCPサーバーが公開され、生成AIからの利用が簡単にできるようなりました。
2ヶ月使い込んで見えてきたのは、便利さの一方MCPの挙動についてひとつの技術的な課題でした。
</summary>
        </entry><entry xml:lang="en">
        <title>技術文書用フォーマット AsciiDoc</title>
        <published>2026-07-10T05:00:00+09:00</published>
        <updated>2026-07-10T05:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/asciidoc/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/asciidoc/</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;07&amp;#x2F;asciidoc&amp;#x2F;cover.webp?h=2af306a0693c3ee09dbc&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;AsciiDocで書かれたドキュメントを修正する必要があったので、
AsciiDoctorを導入しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AsciiDocとは&quot;&gt;AsciiDocとは&lt;&#x2F;h2&gt;
&lt;p&gt;AsciiDocは、2002年にStuart Rackham氏が開発したマークアップ言語です。
もともとはDocBook XMLを人間が書きやすい記法で表現するためのPython製ツールとして
誕生しました。プレーンテキストで書いた文書を、HTMLやPDF、EPUBなど複数の形式に
変換できる点が特徴です。&lt;&#x2F;p&gt;
&lt;p&gt;2013年にはRuby実装のAsciidoctorが登場し、現在ではこちらが主流の処理系となっています。
本記事でも、AsciiDocの処理系としてAsciidoctorを使用します。&lt;&#x2F;p&gt;
&lt;p&gt;2019年からはEclipse Foundation傘下の
AsciiDoc Working Groupによって言語仕様の標準化も進められており、
処理系間の互換性が高まりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、技術文書での採用率では明確にMarkdownが優位です。
技術文書作成者の主要フォーマットとしてMarkdownを使う割合が约65%とされ、デファクトスタンダードの地位にあります。学習コストの低さとツールの豊富さ、生成AIで扱う文書形式の標準となっていることが理由です。
実際にはAsciiDocは全体の採用率では大きく水を開けられています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MacへのAsciiDocの導入&quot;&gt;MacへのAsciiDocの導入&lt;&#x2F;h2&gt;
&lt;p&gt;AsciiDocの処理系としてAsciiDoctorを使用します。&lt;&#x2F;p&gt;
&lt;p&gt;ランタイムにRubyを使用するので、Rubyのインストールから行っています。
前提として、私の環境では
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mise.jdx.dev&quot;&gt;mise&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;install.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Rubyのインストール&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;mise&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; use -g ruby@latest&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;gem&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install asciidoctor asciidoctor-pdf asciidoctor-rouge&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;gem&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install asciidoctor-pdf-cjk asciidoctor-diagram&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AsciiDocのサンプル&quot;&gt;AsciiDocのサンプル&lt;&#x2F;h2&gt;
&lt;p&gt;似たようなマークアップ言語にMarkdownがありますが、
以下のような点でAsciiDocが優れているので作る文書の特性で
使い分けています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;目次や表紙の生成が可能&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;GitHubやGitLabでもネイティブでAsciiDocのレンダリングに対応しています。
始めからHTMLやPDFへの変換を意識して作られている点でも優れています。&lt;&#x2F;p&gt;
&lt;p&gt;次にサンプルを提示します。
Frontmatterを除くと、ソースのままでも読みやすい形式です。
特に今回はソースコードの解説だったので、以下の例ではソースコードへの解説を追記する例となっています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;asciidoc&quot; data-name=&quot;sample.adoc&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-markup z-heading z-heading-0 z-asciidoc&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-text&quot;&gt;toc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; left&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-text&quot;&gt;toc-title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&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-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;toclevel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&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&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;imagesdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; images&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-text&quot;&gt;figure-caption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&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-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;chapter-signifier&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-text&quot;&gt;scripts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cjk&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-text&quot;&gt;pdf-theme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; default-with-font-fallbacks&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-text&quot;&gt;doctype&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; book&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-text&quot;&gt;sectnumlevels&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&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&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;sectnums&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-text&quot;&gt;source-highlighter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; rouge&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-text&quot;&gt;rouge-style&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gruvbox&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-markup z-heading z-heading-1 z-asciidoc&quot;&gt;== Hello World&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-text&quot;&gt;.hello.py&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;python]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Hello World!&amp;quot;&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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&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 class=&quot;z-text&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; 3&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 z-control z-flow z-python&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&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; 1&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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 1&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;elif&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&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; 2&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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 2&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;elif&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&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; 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-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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 3&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;else&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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 4&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-text&quot;&gt;----&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;&amp;lt;1&amp;gt; やっぱりサンプルといえばコレな&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;&amp;lt;2&amp;gt; IF文です！&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AsciiDocを変換する&quot;&gt;AsciiDocを変換する&lt;&#x2F;h2&gt;
&lt;p&gt;作成したAsciiDocのソースは以下のコマンドでHTMLやPDFに変換します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;convert.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# HTMLの生成&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;asciidoctor&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --backend html5 sample.adoc -o sample.html&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;# 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;asciidoctor-pdf&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sample.adoc -o sample.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下が生成したサンプルです。&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;07&amp;#x2F;asciidoc&amp;#x2F;sample.webp?h=aa551a1eddeb908ee3e0&quot;
  alt=&quot;AsciiDoc生成結果&quot; width=&quot;983&quot; height=&quot;572&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;AsciiDocは
Markdownと似ているので混乱する部分もありますが、
Markdownよりやりたいことをストレートに書けると思います。&lt;&#x2F;p&gt;
&lt;p&gt;サンプルのようにAsciiDocのメタデータにいろいろ記載すると生成するスタイルも
変更できるのでいろんな文章に柔軟に対応できると思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ソースコードの解説を含む技術文書を書く必要があり、AsciiDocとその処理系Asciidoctorを
導入しました。Markdownが標準となった今あえてAsciiDocを選ぶ理由と、
Mac環境での導入手順、実際の変換サンプルを紹介します。
</summary>
        </entry><entry xml:lang="en">
        <title>CloudflareのAI対策見直しとAIエージェント対応度診断</title>
        <published>2026-07-08T00:00:00+00:00</published>
        <updated>2026-07-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/cloudflare-ai-access-review/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/cloudflare-ai-access-review/</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;07&amp;#x2F;cloudflare-ai-access-review&amp;#x2F;cover.webp?h=be4593eef9e356ff784e&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;2026年2月、&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;cloudflare-benefits&#x2F;&quot;&gt;Cloudflareへ移転した際の記事&lt;&#x2F;a&gt;で、AI学習クローラー対策としてContent Signals Policy、Block AI bots、AI Labyrinthという3層構成を紹介しました。あれから4か月、AIによるアクセスの重要性はさらに増しています。改めてこのブログのCloudflare設定を見直すとともに、Cloudflareが新しく公開したAgent Readinessスキャナーで「AIエージェントへの対応度」を診断してみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Managed_robots.txtまわりを再確認する&quot;&gt;Managed robots.txtまわりを再確認する&lt;&#x2F;h2&gt;
&lt;p&gt;まず、AI Crawl Controlのダッシュボードを一通り確認しました。&lt;&#x2F;p&gt;
&lt;p&gt;Block AI training botsは「Block on all pages」のままで変更していません。このブログのコンテンツはCC BY-NC-ND 4.0(非営利・改変禁止)で公開しているので、商用LLMの学習データとして使われることは元々ライセンスの意図と衝突します。学習目的のクローラーは全ページで拒否するのが一貫した方針です。&lt;&#x2F;p&gt;
&lt;p&gt;Content Signalsでは、Managed robots.txtをオンにしています。&lt;&#x2F;p&gt;
&lt;p&gt;AI Crawl ControlのCrawlers一覧では、クローラーごとの許可&#x2F;ブロックを個別に確認しました。&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;AI Crawler(学習用)&lt;&#x2F;td&gt;&lt;td&gt;GPTBot、ClaudeBot、Bytespider、Amazonbot、TikTok Spider、Meta-ExternalAgent&lt;&#x2F;td&gt;&lt;td&gt;Block&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AI Search &#x2F; AI Assistant&lt;&#x2F;td&gt;&lt;td&gt;Applebot、PerplexityBot、ChatGPT-User&lt;&#x2F;td&gt;&lt;td&gt;Allow&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Search Engine Crawler&lt;&#x2F;td&gt;&lt;td&gt;Googlebot、BingBot&lt;&#x2F;td&gt;&lt;td&gt;Allow&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Crawlers一覧の分類も、学習目的のクローラーを拒否するという方針のとおりでした。あわせてAI Labyrinth(クロールルールを無視するボットに偽コンテンツを読ませるハニーポット機能、Beta)も確認しましたが、2月から変わらずONのままでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「混在クローラー」という新しい論点&quot;&gt;「混在クローラー」という新しい論点&lt;&#x2F;h2&gt;
&lt;p&gt;今回の見直しで、2月時点にはなかった変化に気づきました。レガシー機能「Block AI bots」の設定画面に、次のような予告が表示されていたのです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;On September 15, mixed-purpose crawlers that are used both for search indexing and for training AI will be included in blocking AI training.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ここで言う混在クローラーとは、前段のCrawlers一覧でSearch Engine CrawlerやAI Searchに分類し、学習とは無関係としてAllowにしていたGooglebot、Applebot、BingBotのことです。検索とAI学習を1回のクロールで同時に行うため両者を切り分けられず、学習ブロックを選んでいるサイトでは最も制限の強いルールを適用する、というのが実質的な立場だと考えられます。そのままでは検索エンジン経由の流入もAI検索・AIアシスタント経由の露出も失うため、「Mixed purpose crawlers will continue to be allowed」を選び、混在クローラーは引き続き許可する設定にしました。&lt;&#x2F;p&gt;
&lt;p&gt;レガシー機能は9月15日に廃止され、後継の「Configure AI bot policies」に一本化されます。こちらはボットを3種類に分類し、それぞれ個別にAllow&#x2F;Blockを選べる形になっていました。&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;Search&lt;&#x2F;td&gt;&lt;td&gt;検索エンジンのインデックス用ボット&lt;&#x2F;td&gt;&lt;td&gt;Allow(Recommended)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Agent&lt;&#x2F;td&gt;&lt;td&gt;ユーザーの質問への回答生成のために参照するボット&lt;&#x2F;td&gt;&lt;td&gt;Allow(Recommended)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Training&lt;&#x2F;td&gt;&lt;td&gt;AI学習用にコンテンツをスクレイピングするボット&lt;&#x2F;td&gt;&lt;td&gt;Block(Recommended値はBlock on pages with ads)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Trainingだけ、広告のないこのブログの事情に合わせて推奨値の「Block on pages with ads」から「Block」に変更しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AIエージェント対応度を診断してみた&quot;&gt;AIエージェント対応度を診断してみた&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;isitagentready.com&#x2F;&quot;&gt;isitagentready.com&lt;&#x2F;a&gt;という無料の診断ツールを公開しています。&lt;&#x2F;p&gt;
&lt;p&gt;この診断ツールでは、サイトのAIエージェントへの対応度(Agent Readiness)を診断してくれます。&lt;&#x2F;p&gt;
&lt;p&gt;このブログのURLでスキャンしたところ、次のようなものでした。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;cloudflare-ai-access-review&amp;#x2F;agent-readiness.webp?h=634fa8b7fd82807af8a4&quot;
  alt=&quot;Agent Readiness&quot; width=&quot;1472&quot; height=&quot;1486&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;当サイトのAgent Readiness&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;個人ブログサイトでは該当しない項目&quot;&gt;個人ブログサイトでは該当しない項目&lt;&#x2F;h3&gt;
&lt;p&gt;改善項目として、10個の指摘を受けました。
ただし、10個のうち6個はいずれも「稼働しているAPIやエージェントサービスがあること」を前提にした指摘でした。&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;DNS for AI Discovery (DNS-AID)&lt;&#x2F;td&gt;&lt;td&gt;IETFドラフト、Linux Foundation 2026年発表&lt;&#x2F;td&gt;&lt;td&gt;他のAIエージェントから発見・接続されるエージェントサービス(チャットボット、MCPサーバー等)を運用していない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;API Catalog&lt;&#x2F;td&gt;&lt;td&gt;RFC 9727&lt;&#x2F;td&gt;&lt;td&gt;カタログ化すべきAPIが存在しない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;OAuth&#x2F;OIDC discovery metadata&lt;&#x2F;td&gt;&lt;td&gt;RFC 8414 等&lt;&#x2F;td&gt;&lt;td&gt;認証保護されたAPIや会員機能がない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;OAuth Protected Resource Metadata&lt;&#x2F;td&gt;&lt;td&gt;RFC 9728&lt;&#x2F;td&gt;&lt;td&gt;同上&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;auth.md&lt;&#x2F;td&gt;&lt;td&gt;WorkOS提唱&lt;&#x2F;td&gt;&lt;td&gt;OAuth Protected Resource Metadataを前提とする、同上の理由&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MCP Server Card&lt;&#x2F;td&gt;&lt;td&gt;SEP-1649(標準化進行中)&lt;&#x2F;td&gt;&lt;td&gt;MCPサーバーを運用していない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;このブログは静的コンテンツを配信するだけのサイトで、APIやエージェント向けサービスは一切運用していません。この種の指摘は、SaaSやEC、API提供事業者向けのチェックリストとしては妥当ですが、個人ブログにはそもそも対象が存在しませんでした。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;対応した項目&quot;&gt;対応した項目&lt;&#x2F;h3&gt;
&lt;p&gt;「ホームページにLink response header(RFC 8288)がない」という指摘もありました。ツールの提案は&lt;code&gt;rel=&quot;api-catalog&quot;&lt;&#x2F;code&gt;や&lt;code&gt;rel=&quot;service-doc&quot;&lt;&#x2F;code&gt;でAPIカタログやAPI仕様書を指すというものでしたが、このブログにAPIはないので、この提案どおりに実装しても意味がありません。&lt;&#x2F;p&gt;
&lt;p&gt;代わりに、Linkヘッダーの仕組み自体はこのブログでも使い道があると考え、次の2つを指すヘッダーを追加しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;static&#x2F;_headers&quot;&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;  Link: &amp;lt;&#x2F;license&#x2F;&amp;gt;; rel=&amp;quot;license&amp;quot;, &amp;lt;&#x2F;atom.xml&amp;gt;; rel=&amp;quot;alternate&amp;quot;; type=&amp;quot;application&#x2F;atom+xml&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;rel=&quot;license&quot;&lt;&#x2F;code&gt;はIANA登録済みの正式なrelationで、CC BY-NC-ND 4.0を明記したライセンスページ(&lt;code&gt;&#x2F;license&#x2F;&lt;&#x2F;code&gt;)をAIエージェントが機械的に検出できるようにします。学習ボットのブロックと合わせて、コンテンツの利用条件を多層的に伝える形になりました。&lt;code&gt;rel=&quot;alternate&quot;&lt;&#x2F;code&gt;はZolaが生成するAtomフィード(&lt;code&gt;&#x2F;atom.xml&lt;&#x2F;code&gt;)へのリンクで、フィードの発見性を高めます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;対応を見送った項目&quot;&gt;対応を見送った項目&lt;&#x2F;h3&gt;
&lt;p&gt;残る3個は、対応自体は可能でも今回は見送りました。&lt;&#x2F;p&gt;
&lt;p&gt;Markdown for Agentsは、&lt;code&gt;Accept: text&#x2F;markdown&lt;&#x2F;code&gt;のリクエストにHTMLの代わりにMarkdownを返す機能です。CloudflareのAI Crawl Control上では確認できましたが、Proプラン以上限定(2026年7月時点で月$20〜25)のため、Freeプランの現状ではロックされていました。個人ブログの一機能としてはコストに見合わないと判断し、見送りました。&lt;&#x2F;p&gt;
&lt;p&gt;WebMCPは、ブラウザ内蔵のAIエージェントに&lt;code&gt;navigator.modelContext.provideContext()&lt;&#x2F;code&gt;でサイトの操作(検索など)を直接公開する仕組みです。現状はEarly Preview Program参加者限定の実験段階で、一般のブラウザではまだ有効化されていません。このブログの操作対象もpagefindによる検索程度で薄く、標準化が進んだ段階で再検討することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;Agent Skills discovery indexは、&lt;code&gt;&#x2F;.well-known&#x2F;agent-skills&#x2F;index.json&lt;&#x2F;code&gt;にサイト固有の作業手順(SKILL.md)を公開する仕組みです。コンテンツサイト向けの想定用途は「文章校正」「カテゴリ分類の提案」といった編集アシスタント業務で、これは既に自分のClaude Code環境でローカルに完結しています。v0.2.0のドラフト段階でエコシステムの普及状況も未検証なため、こちらも見送りとしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Agent Readinessスキャンの10個の指摘を並べてみると、その多くはAPIやSaaS、エージェント向けサービスを運用している事業者を想定したチェックリストだと分かりました。静的な個人ブログにとって本当に意味のある「AI対応」は、実は範囲が絞られます。当サイトでの結論は次のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CC BY-NC-NDライセンスの意図に沿って、学習目的のクローラーは技術的にブロックする&lt;&#x2F;li&gt;
&lt;li&gt;robots.txtのContent Signalsとライセンスページへの&lt;code&gt;rel=&quot;license&quot;&lt;&#x2F;code&gt;で、利用条件を機械可読な形でも表明する&lt;&#x2F;li&gt;
&lt;li&gt;検索エンジンやAI回答エンジンからの参照は妨げず、露出の機会は残す&lt;&#x2F;li&gt;
&lt;li&gt;WebMCPやAgent Skillsのようなドラフト段階の規格には、実際に普及するまで様子見の姿勢を崩さない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;2月の記事で組んだ多層防御の骨格は変わっていませんが、Cloudflare側の仕様変更(混在クローラーの扱い)に合わせて設定を追随させ、Agent Readinessという新しい物差しで一度棚卸しをしたことで、このブログのAI対応の現在地を再確認できました。&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;blog.cloudflare.com&#x2F;content-signals-policy&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Giving users choice with Cloudflare&#x27;s new Content Signals Policy&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;bots&#x2F;additional-configurations&#x2F;managed-robots-txt&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;robots.txt setting&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;content-independence-day-ai-options&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Your site, your rules: new AI traffic options for all customers&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;agent-readiness&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Introducing the Agent Readiness score&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;plans&#x2F;pro&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Pro Plan Overview&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ietf.org&#x2F;archive&#x2F;id&#x2F;draft-mozleywilliams-dnsop-dnsaid-01.html&quot;&gt;IETF&lt;&#x2F;a&gt;. &quot;DNS for AI Discovery&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dns-aid.org&#x2F;&quot;&gt;DNS-AID&lt;&#x2F;a&gt;. &quot;AI Agent Discovery via DNS&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.rfc-editor.org&#x2F;rfc&#x2F;rfc9727&quot;&gt;IETF&lt;&#x2F;a&gt;. &quot;RFC 9727: The api-catalog Well-Known URI and Link Relation Type&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.rfc-editor.org&#x2F;rfc&#x2F;rfc8288&quot;&gt;IETF&lt;&#x2F;a&gt;. &quot;RFC 8288: Web Linking&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;workos.com&#x2F;auth-md&quot;&gt;WorkOS&lt;&#x2F;a&gt;. &quot;auth.md — Open Protocol for Agent Registration&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;modelcontextprotocol&#x2F;modelcontextprotocol&#x2F;pull&#x2F;2127&quot;&gt;Model Context Protocol&lt;&#x2F;a&gt;. &quot;MCP Server Card (SEP-1649)&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;agent-skills-discovery-rfc&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Agent Skills Discovery RFC&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;agentskills.io&#x2F;&quot;&gt;Agent Skills&lt;&#x2F;a&gt;. &quot;Agent Skills&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.chrome.com&#x2F;blog&#x2F;webmcp-epp&quot;&gt;Chrome Developers&lt;&#x2F;a&gt;. &quot;WebMCP Early Preview Program&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">2026年2月に整えたCloudflareのAIボット対策を4か月ぶりに見直しました。検索とAI学習を兼ねる「混在クローラー」を9月15日からブロック対象に含めるという仕様変更や、Agent Readinessスキャンで受けた10個の指摘を、個人ブログの視点で整理します。</summary>
        </entry><entry xml:lang="en">
        <title>メッセージングアプリの匿名性考察</title>
        <published>2026-07-01T10:00:00+09:00</published>
        <updated>2026-07-01T10:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/messenger-anonymity/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/messenger-anonymity/</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;07&amp;#x2F;messenger-anonymity&amp;#x2F;cover.webp?h=c60e5fcb30b3118d869c&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;Threema GmbH（以下、Threema社）の公式ブログに「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threema.com&#x2F;en&#x2F;blog&#x2F;anonymity-at-the-system-level-the-ultimate-privacy-protection&quot;&gt;システムレベルの匿名性についての記事&lt;&#x2F;a&gt;」という記事が投稿されました。&lt;&#x2F;p&gt;
&lt;p&gt;メッセージングアプリの匿名性について論じています。以前、市川の強盗傷害事件をきっかけに&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2024&#x2F;10&#x2F;modern-messaging-apps&#x2F;&quot;&gt;暗号化やメタデータで機能比較した記事&lt;&#x2F;a&gt;を書きましたが、匿名性という観点はなかったのでこの記事を参考に解説したいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリの匿名性について&quot;&gt;メッセージングアプリの匿名性について&lt;&#x2F;h2&gt;
&lt;p&gt;Threema社の技術記事では、匿名性を二種類に分けています。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;水平的匿名性&lt;&#x2F;dt&gt;
&lt;dd&gt;会話の相手に対する匿名性です。ユーザー名だけで連絡先を交換できれば、相手は電話番号や本名を知りません。対等な利用者どうしの間で成り立ちます。&lt;&#x2F;dd&gt;
&lt;dt&gt;垂直的匿名性&lt;&#x2F;dt&gt;
&lt;dd&gt;サービス運営者に対する匿名性です。登録時に電話番号やメールアドレスを渡していなければ、運営は身元を特定する手がかりを持ちません。利用者とサービスという上下の関係で成り立ちます。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;Threema社は、ユーザー名機能で水平的匿名性は広まったものの、プライバシー保護で本当に重要なのは垂直的匿名性であり、これはセキュリティにおけるエンドツーエンド暗号化に相当する基盤だと主張します。あくまで同社の枠組みですが、この二軸はアプリを見比べる土台として使えます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;垂直的匿名性の重要性について&quot;&gt;垂直的匿名性の重要性について&lt;&#x2F;h2&gt;
&lt;p&gt;なぜ運営に対する匿名性がそれほど問題になるのでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;メッセージングアプリでは、登録時に電話番号やメールアドレスを要求するものがあります。&lt;&#x2F;p&gt;
&lt;p&gt;ユーザー名で連絡先を交換できるサービスでも、相手にこうした個人情報を見せずに済むだけで、登録の段階では運営に渡しています。
電話番号やメールアドレスは本人確認や他サービスの登録にも使われる、生活に密着した識別子です。
運営がこれを保持していれば、別々の文脈で集めた情報を同一人物に結びつける手がかりとして使えてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;この紐付けは、広告で収益を上げるサービスでは特に意味を持ちます。利用者の行動を束ねてプロフィールを作るほど広告の精度が上がるので、複数の情報源を統合する動機がもともと働きます。電話番号やメールアドレスのような確実な識別子があれば、その統合は格段にやりやすくなります。メッセージの中身が暗号化されていても、誰がいつ誰と連絡したかというメタデータや、それを個人に結びつける識別子までは覆い隠せません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリの匿名性の比較&quot;&gt;メッセージングアプリの匿名性の比較&lt;&#x2F;h2&gt;
&lt;p&gt;ここまでの軸で、私が知る範囲の主要なアプリを並べてみます。&lt;&#x2F;p&gt;
&lt;p&gt;暗号化の強さと、運営に対する匿名性は別物だという点に注目してください。暗号化の対応範囲やメタデータ収集、法執行機関への開示といった機能面の詳しい比較は&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2024&#x2F;10&#x2F;modern-messaging-apps&#x2F;&quot;&gt;前回の記事&lt;&#x2F;a&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;th&gt;運営に対する匿名性&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;LINE&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;WhatsApp&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;iMessage&lt;&#x2F;td&gt;&lt;td&gt;電話番号または Apple Account&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Signal&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;Element &#x2F; Matrix&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;Threema&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;Session&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;SimpleX&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;国内利用者の多いLINEは、もう少し細かく見ておきます。LINEのメッセージはLetter Sealingと呼ぶ技術で暗号化されていますが、50人を超えるグループトーク、グループ音声・ビデオ通話、LINEミーティング、アルバム、ノートは対象外で、通信路のTLS暗号化にとどまります。
この範囲は運営が技術的に中身へアクセスし得ます。そして匿名性の面では、登録に電話番号が必須なので運営に対する匿名性は持ちません。自治体などが市民の申請にLINEを使
うケースが増えていますし、たまに企業でも業務で使用しているケースを見かけます。セキュリティ意識の低さには驚きます。&lt;&#x2F;p&gt;
&lt;p&gt;WhatsAppとiMessageも、垂直的匿名性はありません。メッセージの暗号化に対応していますが、登録にはWhatsAppが電話番号、iMessageが電話番号かApple Accountを必要とします。この時点で運営に対する匿名性は持ちません。
特にWhatsAppを運営するMeta社は広告を収入源としているので
、個人情報に関連したメタデータを収集してグループ内の他社と共有している可能性があります。
中身は守られても、誰といつ繋がったかまでは隠せません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;ただし、Signalのメタ情報の電話番号、登録日、最終接続日のみ。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;暗号化に強いというイメージのSignalも垂直的匿名性はありません。
ユーザー名機能が2024年に加わり、電話番号を教えないまま連絡できるようになりました(水平的匿名性)が、
アカウントの作成には今も電話番号が必須です。
Signalを運営するのはSignal Foundationという非営利団体ですが、拠点はカリフォルニア州です。
つまり米国の管轄下なので、米国の捜査機関の要求があれば開示義務があります。&lt;&#x2F;p&gt;
&lt;p&gt;ElementはMatrixというオープンなプロトコルの上に作られています。登録に必要なのは、選んだサーバー上のユーザー名とパスワードだけで、電話番号は要りません。メールアドレスはパスワード再設定用に任意で登録でき、サーバーによっては不正利用対策で求められることもあります。利用者はmatrix.orgのような公開サーバーを選んで登録するのが一般的で、自前でサーバーを立てることもできます。運営に対する匿名性は、結局どのサーバーを信頼するかに依存します。&lt;&#x2F;p&gt;
&lt;p&gt;結局、垂直的匿名性を保持しているのは、Threema、Session、SimpleXのみです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;垂直的匿名性の代償&quot;&gt;垂直的匿名性の代償&lt;&#x2F;h2&gt;
&lt;p&gt;垂直的匿名性の仕組みと、その代わりに払う利便性のコストを見ておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Threemaは電話番号やメールアドレスを必要とせず、アカウントはランダムに割り当てられたThreema IDだけで機能します。
ユーザーはThreema IDを交換しメッセージの送受信を行ないます。
伝えるのはThreema IDのみなので、運営や相手に身元を明かさずに通信できます。
Threemaを使用していることすら秘匿する為にGoogle Playなどに依存せずThreemaを入手・購入できる手段も提供しています。
Threema IDはThreema社により管理されており、「IDが誰か」はThreema社に把握されませんが「いつ・どのIDと通信したか」は
論理的にはThreema社で把握可能です。ただし、Threema社は広告やトラッキングを行なわないというポリシーを持ち、収益源を買い切り課金に置いています。&lt;&#x2F;p&gt;
&lt;p&gt;SimpleXは、利用者を識別する固定IDを一切持たない設計です。電話番号やユーザー名はもちろん、ランダムなIDすら使いません。仕組みは一方向のメッセージキューで、接続ごとに送信用と受信用の別々のキューを持ち、通常はそれぞれ別のサーバーを経由します。
サーバーから見えるのは不透明なキューへの孤立した配送だけで、送信者と受信者を結びつけられません。サーバー同士も通信せず、配送が済んだメッセージは保存しません。&lt;&#x2F;p&gt;
&lt;p&gt;SessionはもともとSignalのフォークとして始まりました。電話番号やメールなどの個人データも不要で、ランダムなSession IDという66文字程度の公開鍵をアカウントのIDとして使います。メッセージは多数の有志ノードからなるオニオン型のネットワークを経由し、どのノードも送信者と受信者の両方を知ることはありません。運営は2024年10月に、暗号化技術への規制圧力を背景としてオーストラリアからスイスへ拠点を移し、現在はスイスのSession Technology Foundationが運営しています。コードはQuarkslabによる独立監査を受けています。SimpleXとの違いは、Sessionが永続的なアカウントのIDを持つ点です。&lt;&#x2F;p&gt;
&lt;p&gt;これらの高い匿名性には、現実的な代償が伴います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;いずれも、相手に直接リンクやQRコード、IDを渡さなければ会話を始められない&lt;&#x2F;li&gt;
&lt;li&gt;従って、電話番号やユーザー名で気軽に相手を見つけることはできず、なんらかの方法で相手と直接これらの情報を交換する必要がある&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一番問題になるのは、相手も同じアプリを入れている必要があるところでしょう。
いずれもマイナーなアプリなので、匿名性のために連絡相手の数と手軽さを大きく差し出すことになります。
この利便性の低さは、日常使いを考えるうえで無視できないトレードオフです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリについて私の選択&quot;&gt;メッセージングアプリについて私の選択&lt;&#x2F;h2&gt;
&lt;p&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;家族&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;&#x2F;tr&gt;
&lt;tr&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;このように考えると、家族とは水平的匿名性は不要で垂直的匿名性が必要です。
前回の記事でも軽く触れましたが、私自身は家族との連絡用にThreemaを選んでいます。
SimpleXやSessionでもよいのですが、かなり以前からThreemaを使用しており、特に問題もないために使用を続けています。&lt;&#x2F;p&gt;
&lt;p&gt;友人も同様です。知り合いなので水平的匿名性は不要ですが、垂直的匿名性は必要です。
しかし、現実的には垂直的匿名性を実現するために、先に記述した「代償」のため友人に対応するアプリを導入してもらうことは困難です。
そのため諦めて必要な場合は、友人にはメールかSMSでのコンタクトを依頼しています。暗号化、匿名性は放棄すると言うことです。
LINEなどを使っていると「じゃ、LINEで」と言われるので、私はLINEなどのアプリは使わずインストールさえしていません。&lt;&#x2F;p&gt;
&lt;p&gt;ネットで知り合ったような他人については、どちらの匿名性も重要だと思います。
しかし、私は、匿名のままネットで知り合った相手とメッセージングアプリを使って通信するようなニーズはないので無視します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;LINE・WhatsApp・iMessage・Signalなど主要なメッセージングアプリは、暗号化や水平的匿名性は実装されていますが、
垂直的匿名性は担保されていません。LINEなど「なりすまし防止、復旧、法令遵守」などを理由に電話番号への紐付けを強化しています。
自治体などでLINEを使用するケースが多いようですが、あれは個人特定を行政として放棄しているとしか思えません。&lt;&#x2F;p&gt;
&lt;p&gt;私にとって必要なのは垂直的匿名性です。メッセージの中身が暗号化されていても、運営に身元や「誰といつ通信したか」を握られては、プライバシーを守ったことになりません。
一方、相手に対しても名乗らない水平的匿名性は、私個人にはほとんど必要ありません。&lt;&#x2F;p&gt;
&lt;p&gt;両方の匿名性を保てるのは、Threema・Session・SimpleXの3つです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;米国報道機関ではSignalが使用されているケースが多いようです。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;両方の匿名性が必要なのは、相手や運営に身元を伏せたまま連絡したい場面だけです。
こうしたニーズは犯罪目的での使用を想起するかもしれませんが、内部告発や情報提供など正当な目的のためにも必要です。
米国では報道機関が情報提供の窓口としてメッセージングアプリの宛先などを公開しています。
日本ではこうした使い方はほとんど根づいておらず、全く遅れています。&lt;&#x2F;p&gt;
&lt;p&gt;大切なのは、自分がどちらの匿名性を必要とするのかを見極めることです。垂直的匿名性はほとんどの人に効きますが、水平的匿名性まで求めるかは人によって大きく変わります。私自身は、身元を隠す必要のない家族との連絡に、垂直的匿名性を保ちつつ扱いやすいThreemaを使っています。&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;threema.com&#x2F;en&#x2F;blog&#x2F;anonymity-at-the-system-level-the-ultimate-privacy-protection&quot;&gt;Threema&lt;&#x2F;a&gt;. &quot;Anonymity at the System Level: The Ultimate Privacy Protection&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threema.ch&#x2F;en&#x2F;blog&#x2F;posts&#x2F;news-alleged-weaknesses-statement&quot;&gt;Threema&lt;&#x2F;a&gt;. &quot;Statement on ETH Findings&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;breakingthe3ma.app&#x2F;&quot;&gt;ETH Zurich Applied Cryptography Group&lt;&#x2F;a&gt;. &quot;Three Lessons from Threema&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;signal.org&#x2F;blog&#x2F;phone-number-privacy-usernames&#x2F;&quot;&gt;Signal&lt;&#x2F;a&gt;. &quot;Keep your phone number private with Signal usernames&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;signalfoundation.org&#x2F;en&#x2F;&quot;&gt;Signal Foundation&lt;&#x2F;a&gt;. &quot;Signal Foundation&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;simplex.chat&#x2F;docs&#x2F;simplex.html&quot;&gt;SimpleX Chat&lt;&#x2F;a&gt;. &quot;How SimpleX works&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getsession.org&#x2F;blog&#x2F;introducing-the-session-technology-foundation&quot;&gt;Session&lt;&#x2F;a&gt;. &quot;Introducing the Session Technology Foundation&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getsession.org&#x2F;session-code-audit&quot;&gt;Session&lt;&#x2F;a&gt;. &quot;Session code audit by Quarkslab&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;faq.whatsapp.com&#x2F;820124435853543&quot;&gt;WhatsApp Help Center&lt;&#x2F;a&gt;. &quot;About end-to-end encryption&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;guide&#x2F;security&#x2F;imessage-security-overview-secd9764312f&#x2F;web&quot;&gt;Apple Support&lt;&#x2F;a&gt;. &quot;iMessage security overview&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.element.io&#x2F;latest&#x2F;element-support&#x2F;matrix-account-management&#x2F;creating-a-matrix-account&#x2F;&quot;&gt;Element&lt;&#x2F;a&gt;. &quot;Creating a Matrix Account&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;help.line.me&#x2F;line&#x2F;smartphone&#x2F;categoryId&#x2F;20010067&#x2F;3&#x2F;pc&quot;&gt;LINE Help Center&lt;&#x2F;a&gt;. &quot;Letter Sealing&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.lycorp.co.jp&#x2F;ja&#x2F;privacy-security&#x2F;security&#x2F;transparency&#x2F;encryption-report&#x2F;2025&#x2F;&quot;&gt;LINEヤフー&lt;&#x2F;a&gt;.「LINE暗号化状況レポート（2025年）」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Threema公式ブログに「システムレベルの匿名性」についての記事が公開されました。
日本ではLINEが主流で匿名性についての関心は薄いと思うので、その仕組みと重要性を解説してみました。
</summary>
        </entry><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>Claude Fable Loss</title>
        <published>2026-06-15T08:13:26+09:00</published>
        <updated>2026-06-15T08:13:26+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/fable-loss/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/fable-loss/</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;fable-loss&amp;#x2F;cover.webp?h=c18907ce2228e37f503e&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;2026年6月9日、Anthropic社は新しいAIモデル「Claude Fable 5」を一般公開しました。
これまで招待制でしか使えなかった「Mythosクラス」の推論能力を、安全機構付きで誰もが利用できるようにした初のモデルです。
ところが公開からわずか3日後、Fable 5は米政府の指示によって停止され、姿を消してしまいました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Fable_5とは&quot;&gt;Claude Fable 5とは&lt;&#x2F;h2&gt;
&lt;p&gt;Fable 5の位置づけは、公式の&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;platform.claude.com&#x2F;docs&#x2F;en&#x2F;about-claude&#x2F;models&#x2F;overview&quot;&gt;モデル一覧&lt;&#x2F;a&gt;を見るとわかりやすいです。
コンテキストウィンドウは100万トークン、最大出力は12万8千トークン、料金は入力が100万トークンあたり10ドル、出力が同じく50ドルです。&lt;&#x2F;p&gt;
&lt;p&gt;数字だけを並べると、コンテキスト長と出力上限はOpus 4.8と同じで、際立った違いは見えません。
肝はスペックの数字ではなく、その中身にあります。&lt;&#x2F;p&gt;
&lt;p&gt;ひとつはMythosクラスの推論能力です。
Mythosは本来、限定公開の枠組み「Project Glasswing」でしか提供されていなかった上位クラスで、その能力を一般向けに開放したのがFable 5にあたります。
もうひとつはアダプティブ思考が常時有効になっている点です。
従来のような拡張思考のオン&#x2F;オフという概念はなく、思考の深さは&lt;code&gt;effort&lt;&#x2F;code&gt;パラメータで調整します。&lt;&#x2F;p&gt;
&lt;p&gt;なお、Fable 5には危険な要求を断るための安全分類器が組み込まれており、拒否したリクエストには通常のエラーではなく拒否を示す応答を返します。
この分類器を外したモデルがMythos 5で、こちらは引き続きProject Glasswingの限定提供にとどまっています。
つまりFable 5は、Mythosの能力に安全機構という蓋をかぶせて世に出した版、という位置づけです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Fableが非公開となった理由&quot;&gt;Fableが非公開となった理由&lt;&#x2F;h2&gt;
&lt;p&gt;きっかけは1件のジェイルブレイクでした。
6月10日、著名なジェイルブレイカー「Pliny the Liberator」がFable 5の突破方法をX上で公開します。
報道によれば、その手口は「特定のコードベースを読み込ませ、ソフトウェアの欠陥を修正させる」というものです。これを悪用すると本来制限されているサイバー攻撃の情報を引き出せる、とされました。&lt;&#x2F;p&gt;
&lt;p&gt;これを重く見たのがAmazonでした。
同社CEOのAndy Jassy氏が米政府高官に連絡を取り、警告はやがて広範な規制へと発展します。
商務長官のHoward Lutnick氏は、AnthropicのAmodei CEOに宛てて、外国籍ユーザーによるFable 5・Mythos 5へのアクセスをすべて停止するよう求める書簡を送りました。
対象はAnthropic自身の従業員にまで及びました。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicは現地時間6月12日午後5時21分にこの指示を受け取ります。
外国籍ユーザーだけをリアルタイムに選別するのは難しいとして、結局、全ユーザーに対して両モデルを停止しました。
公開されているモデルが政府の介入で停止されたのは、主要なAI企業としては初めてのことだといわれています。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicはこの措置に同意していません。
公式声明では「数億人に提供している商用モデルを、狭いジェイルブレイクが見つかったことを理由に回収すべきだとは考えない」と述べ、この基準を認めればすべてのフロンティアモデルの新規提供が止まってしまう、と反論しています。
政府との「誤解」を解いて復旧を目指すとしていますが、その時期は明言されていません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Fableを使用した印象&quot;&gt;Fableを使用した印象&lt;&#x2F;h2&gt;
&lt;p&gt;短い公開期間でしたが、私もFable 5を試すことができました。&lt;&#x2F;p&gt;
&lt;p&gt;正直なところ、チャットで普通に対話している分には、Opusとの違いはそれほど感じませんでした。
印象がはっきり変わったのは、Claude Codeに組み込んでコードや文書を書かせたときです。
これまでのClaude Codeでは、指示の細部を待って手が止まったり、こちらでも気づくようなうっかりミスを残したりしていました。
Fable 5ではそうした場面がほとんどなく、目的だけを伝えると自分で段取りを考え、次々と問題を片付けていきます。
「指示を待つアシスタント」から「自分で走るエージェント」へと変わったような手応えがありました。&lt;&#x2F;p&gt;
&lt;p&gt;特に効いたのは、指示が曖昧なときの振る舞いです。
いきなり書き始めるのではなく、まず周辺のコードを読んで環境を把握し、どのファイルやツールが使えるかを確かめてから手を動かします。
段取りの組み立てがうまく、長い作業でも途中で判断がぶれない印象でした。&lt;&#x2F;p&gt;
&lt;p&gt;あとから振り返ると、こう感じていたのは私だけではなかったようです。
公開直後から、難しい仕事ほど評価が高いという声が界隈に広がっていました。
複数ファイルにまたがるリファクタリングや、長時間にわたるエージェント実行、スクリーンショットからのフロントエンド実装といった重いタスクで、これまで尻込みしていた問題を一気に片付けてくれた、という報告が目立ちます。
極端な例では、Stripeが5000万行規模のRubyコードを1日で移行したという話まで出ていました。手作業なら2ヶ月以上かかると見積もっていた作業だそうです。
私が味わった「自分で走る」感覚は、規模こそ違え、同じものだったのだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;もっとも、良いことばかりではありません。
Fable 5はじっくり考える分だけトークンを多く使うので、料金はOpus 4.8の2倍という表向きの数字以上に膨らみます。
実際のタスクでは3〜5倍になることもあるようで、日常の細かい作業まで何でもFableに任せればよい、という話ではなさそうでした。
難しい一手はFable、それ以外はOpus、という使い分けが現実的だろうと感じます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Fableが恋しい&quot;&gt;Fableが恋しい&lt;&#x2F;h2&gt;
&lt;p&gt;皮肉なことに、停止の引き金となったジェイルブレイクの手口は「コードベースを読ませて欠陥を直させる」というものでした。
私がFable 5に最も魅力を感じたのも、まさにコードを任せたときの自走力です。
停止の理由となった能力と、私が手放したくないと思った能力は、どうやら地続きのようです。&lt;&#x2F;p&gt;
&lt;p&gt;たった3日間の付き合いでしたが、いちど「自分で走るAI」を味わってしまうと、元の環境に戻るのが少し物足りなく感じます。
復旧の時期はまだ見えません。
Fableが、恋しいです。&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.anthropic.com&#x2F;news&#x2F;fable-mythos-access&quot;&gt;Anthropic&lt;&#x2F;a&gt;.「Statement on the US government directive to suspend access to Fable 5 and Mythos 5」公式声明&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;platform.claude.com&#x2F;docs&#x2F;en&#x2F;about-claude&#x2F;models&#x2F;overview&quot;&gt;Anthropic&lt;&#x2F;a&gt;.「Models overview」モデル一覧と仕様&lt;&#x2F;li&gt;
&lt;li&gt;BeInCrypto.「Amazonの警告がAnthropicのFable・Mythos停止を招いた」&lt;&#x2F;li&gt;
&lt;li&gt;NBC News.「Anthropic suspends new AI models after government directive」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mindstudio.ai&#x2F;blog&#x2F;claude-fable-5-agentic-coding-real-world-results&quot;&gt;MindStudio&lt;&#x2F;a&gt;.「Claude Fable 5 for Long-Running Agentic Coding: Real-World Results」長時間エージェント作業での実例&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.coderabbit.ai&#x2F;blog&#x2F;fable-5-model-review&quot;&gt;CodeRabbit&lt;&#x2F;a&gt;.「Claude Fable 5 Model Review」コーディング性能のレビュー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.truefoundry.com&#x2F;blog&#x2F;claude-fable-5-vs-opus-4-8-benchmarks-pricing-when-to-use-each&quot;&gt;TrueFoundry&lt;&#x2F;a&gt;.「Claude Fable 5 vs Opus 4.8: Benchmarks, Pricing &amp;amp; When to Use Each」料金と使い分け&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">公開からわずか3日で姿を消したClaude Fable 5。Mythosクラスの推論力を安全機構付きで誰もが使えるようにした初のモデルが、なぜ米政府の指示で停止されたのか。短い邂逅で味わった「自分で走るAI」の手応えと、それを手放した物足りなさを綴ります。
</summary>
        </entry><entry xml:lang="en">
        <title>Macバックアップ戦略・改訂版</title>
        <published>2026-06-09T13:37:30+09:00</published>
        <updated>2026-06-09T13:37:30+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/mac-backup/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/mac-backup/</id>
        
            <content type="html">&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;mac-backup&amp;#x2F;cover.webp?h=e1641700571b6a83b0d5&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;長らくMacのバックアップにはSuperDuperを使い、Bootableなクローンを作ってきました。その方針は、以前&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2025&#x2F;04&#x2F;backup-strategy-for-mac&#x2F;&quot;&gt;Apple Silicon時代のMacバックアップ最新戦略&lt;&#x2F;a&gt;で整理したとおりです。ですが新しいmacOSへの対応がなかなか進まず、Tahoeに至っては一年あまり経った今も正式版すら出ません。そこでSuperDuperを諦め、rsyncでホームディレクトリを鏡像コピーする方式に切り替えました。この記事はその続編であり、乗り換えの理由と設定方法をまとめたものです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜTime_Machineが嫌いか&quot;&gt;なぜTime Machineが嫌いか&lt;&#x2F;h2&gt;
&lt;p&gt;バックアップの話をすると、まずTime Machineを勧められます。ですが私は、ごく初期に使ったきり、その後はすっかり避けるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;もともとは、Bootableなクローンを作れるサードパーティツールを使っていたからです。
Bootableなクローンが作れれば、ディスクが壊れた際にはクローンからmacOSを起動して復旧できます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、現在ではBootableなクローンを技術的に作成できなくなりました(後述)。
それでも、Time Machineには不信感が根強く、直感が先に拒否します。その裏には技術的な理由が3つあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不確実性&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Time Machineはバックアップ先を専用のアーカイブ(sparsebundle)として抱え込む。中で何が起きているかは見えず、壊れていても警告は出ない。実際、復元しようとしたらアーカイブが読めず、修復もできず、履歴を全部捨てて最初からやり直すしかなかったという報告は後を絶たない。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;破損に弱い&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;sparsebundleは中身を多数の小さなバンドファイルに分け、その内側に1つのファイルシステムを抱える構造になっている。個々のファイルを直接取り出すことはできず、必ずイメージ全体をマウントして読む。だからバンドや内部の目次(カタログ)が一部でも壊れると、イメージごとマウント不能になり、世代を問わず全データに手が届かなくなる。世代を積み上げる構造だけに、過去のバックアップまでまとめて道連れになりやすい。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ブラックボックス&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;何がどうコピーされ、どう積み上げられているのか、仕組みそのものがユーザーからは見えない。バックアップ先を開いても何がどう入っているか分からず、「このファイルが今そこにある」とFinderで素朴に確かめることもできない。中で何が行われているか把握できないものに大事なデータを預けるのは、技術者としてどうにも信用しきれない。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私が欲しいのはその逆です。バックアップ先を開けば、コピー元とそっくり同じ構造でファイルがそのまま並んでいて、いざというとき個別のファイルをドラッグで取り出せる。履歴はいりません。今この瞬間の鏡像が1つあれば十分です。見えて、触れて、そのまま取り出せること。Time Machineはこの要求に対して、仕組みからして向いていません。&lt;&#x2F;p&gt;
&lt;p&gt;そのため、私は丸ごとBootableなディスククローンを作成できるサードパーティ製のツールを利用してきました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macOSの変化で、bootableクローンが封じられた&quot;&gt;macOSの変化で、bootableクローンが封じられた&lt;&#x2F;h2&gt;
&lt;p&gt;ところが、ここ数年のmacOSの変化で、その前提が崩れました。サードパーティ製ツールによるBootableなクローンが、事実上できなくなったのです。経緯を追うと、じわじわと封じられてきたことが分かります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Big Surでシステムとデータが分離&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;起動ディスクが、OSの入った読み取り専用のシステムボリュームと、ユーザーデータのデータボリュームに完全分離された。システム側は改ざん防止のため署名・封印され、サードパーティ製アプリが直接コピーできなくなった。OSを複製する役目はApple自身の仕組み(レプリケーター)に移り、それが動き続けるかどうかもApple次第になった。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Sequoia 15.2が決定打&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Appleがそのレプリケーターを壊し、SuperDuperはBootableなバックアップを作れなくなった。データ複製の終盤、PrebootやRecoveryをコピーするあたりで失敗する。これはツール側のバグではなく、Apple側の問題だと開発元が明言している。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Tahoeでは正式対応すら出せず&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;互換性の壁がさらに増え、SuperDuperは正式版を出せていない。Tahoe対応は暫定ベータ(v3.20系)でしのぐ状態が続いている。一時はベータでの改善に期待もしたが、一年あまり経ってもベータのまま。起動可能クローンへの望みは、もう捨てた。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;要点を取り違えないことが大事です。壊れたのはBootableなシステム丸ごとクローンであって、ホーム(データ)のコピーが禁じられたわけではありません。Appleが封じたのはシステムボリュームの複製で、ユーザーのデータをコピーすること自体は今も普通にできます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;今日のmacOSでのバックアップ戦略&quot;&gt;今日のmacOSでのバックアップ戦略&lt;&#x2F;h2&gt;
&lt;p&gt;ここで要件が変わります。&lt;&#x2F;p&gt;
&lt;p&gt;Bootableにできないのなら、システムボリュームまで丸ごとコピーする意味はもうありません。bootableという目的が消えた以上、「全部コピーする」根拠も一緒に消えました。残ったのは、自分のデータだけを守れればいい、という縮退した要求です。&lt;&#x2F;p&gt;
&lt;p&gt;つまり「ホームディレクトリだけでいい」は、最初からそう思っていたわけではありません。bootableを失った結果として、そこまで切り詰めた制約の上に成り立っています。この経緯を踏まえると、要件は次のように整理できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;バックアップ対象はホームディレクトリのみ。システムは諦める。&lt;&#x2F;li&gt;
&lt;li&gt;アプリが&lt;code&gt;~&#x2F;Library&lt;&#x2F;code&gt;配下などに書く、ユーザーが関知しないデータも要らない。多くは再生成されるので、守る価値がない。&lt;&#x2F;li&gt;
&lt;li&gt;差分でいい。変わっていないファイルは書き換えず、変わったぶんだけ転送する。&lt;&#x2F;li&gt;
&lt;li&gt;世代管理はいらない。常にコピー元と同じ、今この瞬間の鏡像が1つあればいい。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;rsyncのメリット&quot;&gt;rsyncのメリット&lt;&#x2F;h2&gt;
&lt;p&gt;この縮退した要件に、rsyncはきれいに合います。&lt;&#x2F;p&gt;
&lt;p&gt;第一に、差分転送が本職です。rsyncは初期状態で、サイズと更新日時を見て一致するファイルをまるごとスキップします。変わっていないファイルは触らず、変わったぶんだけ送ります。「変更ないファイルは書き換えたくない」という要求が、特別な設定なしにそのまま満たされます。&lt;&#x2F;p&gt;
&lt;p&gt;第二に、コピー先がただのファイルになります。バックアップ先は元と同じフォルダ階層がそのまま並ぶので、Finderで全部見えますし、個別ファイルをドラッグで取り出せます。Time Machineの抽象化とは正反対の、見える鏡像が手に入ります。&lt;&#x2F;p&gt;
&lt;p&gt;第三に、世代を持たない運用ができます。&lt;code&gt;--delete&lt;&#x2F;code&gt;を付ければ、コピー元で消したものはバックアップ先からも消え、常に最新の一枚の鏡像が保たれます。履歴の束は作られません。&lt;&#x2F;p&gt;
&lt;p&gt;第四に、無料で、スクリプトに組めて、スケジュール実行まで自前で完結します。専用アプリのライセンスや、OSの更新に追従できないツールの都合で振り回されることもありません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;標準のrsyncは使わない&lt;&#x2F;strong&gt;
        &lt;p&gt;Sequoia&#x2F;Tahoe標準のrsyncは&lt;code&gt;openrsync&lt;&#x2F;code&gt;という別実装で、出来がよくありません。&lt;code&gt;-a&lt;&#x2F;code&gt;で特殊ファイルに当たると止まる、拡張属性でクラッシュするといった報告があります。標準のものは避け、Homebrewで本家のrsync(3.x系)を入れて使いましょう。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;準備&quot;&gt;準備&lt;&#x2F;h2&gt;
&lt;p&gt;まずHomebrewで本家rsyncを入れます。TahoeはApple Silicon専用なので、入れると&lt;code&gt;&#x2F;opt&#x2F;homebrew&#x2F;bin&#x2F;rsync&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;brew install rsync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;もう1つ、フルディスクアクセスの設定が要ります。最近のmacOSでは、これが無いとホーム内の保護領域(メールなど)が読めず、警告も出さずに黙って飛ばされます。手で動作確認するときは使っているターミナルを、自動実行するときは後述のスクリプトを、システム設定のプライバシーとセキュリティ → フルディスクアクセスに追加しておきます。これを怠ると「バックアップしたつもりで一部入っていない」が起きます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;コマンドと除外設計&quot;&gt;コマンドと除外設計&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; data-name=&quot;~&#x2F;bin&#x2F;backup-home.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;span class=&quot;z-source&quot;&gt;DEST&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;quot;&#x2F;Volumes&#x2F;Backup&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;LOG&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-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;Library&#x2F;Logs&#x2F;backup-home.log&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-keyword&quot;&gt;if&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; &#x2F;sbin&#x2F;mount&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; -q &amp;quot;on &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DEST&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&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-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt; $DEST&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; not mounted, skipped&amp;quot;&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-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;$LOG&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; 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;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-entity z-name z-function&quot;&gt;&#x2F;opt&#x2F;homebrew&#x2F;bin&#x2F;rsync&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -aE --delete --info=progress2&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;  --exclude=&amp;#39;&#x2F;Library&#x2F;&amp;#39;&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;  --exclude=&amp;#39;.Trash&#x2F;&amp;#39;&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;  --exclude=&amp;quot;.cache&#x2F;&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;  --exclude=&amp;#39;tmp&#x2F;&amp;#39;&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;  --exclude=&amp;#39;.DS_Store&amp;#39;&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;  --exclude=&amp;#39;&#x2F;pCloud Drive&amp;#39;&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;  --exclude=&amp;#39;&#x2F;.pcloud&#x2F;&amp;#39;&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-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;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DEST&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;home&#x2F;&amp;quot;&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-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;$LOG&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;&#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-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; done&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;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;$LOG&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;先頭の&lt;code&gt;if ! &#x2F;sbin&#x2F;mount ...&lt;&#x2F;code&gt;は、バックアップ先が未マウントのときに内蔵ディスクへ誤って書き込む事故を防ぐガードです。&lt;code&gt;-a&lt;&#x2F;code&gt;は権限・更新日時・シンボリックリンクなどを保ったまま再帰コピーし、&lt;code&gt;-E&lt;&#x2F;code&gt;はmacOSの拡張属性を保持します。&lt;code&gt;--delete&lt;&#x2F;code&gt;でコピー元から消したものをバックアップ先からも消し、常に鏡像に保ちます。&lt;code&gt;--info=progress2&lt;&#x2F;code&gt;は全体の総進捗を一行で表示します。&lt;code&gt;$HOME&#x2F;&lt;&#x2F;code&gt;の末尾スラッシュは「ホームの中身を」コピーする指定で、これが無いとhome自体が一段深く入れ子になります。&lt;&#x2F;p&gt;
&lt;p&gt;除外設計が実は一番の勘どころになります。詰まりの原因はほぼここに集約されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.Trash&lt;&#x2F;code&gt;はゴミ箱、&lt;code&gt;.cache&lt;&#x2F;code&gt;や&lt;code&gt;tmp&lt;&#x2F;code&gt;は再生成される一時データ、&lt;code&gt;.DS_Store&lt;&#x2F;code&gt;はFinderの表示情報。どれもバックアップする価値がない。&lt;&#x2F;li&gt;
&lt;li&gt;クラウドや外部接続の仮想ドライブも必ず外す。ローカルに実体がなく、rsyncが舐めるとオンデマンドのダウンロードを次々誘発し、激遅やタイムアウト、最悪はクラウド上の全データの引きずり下ろしを招く。iCloud DriveやDropbox、OneDrive、Google Driveは&lt;code&gt;Library&#x2F;CloudStorage&lt;&#x2F;code&gt;や&lt;code&gt;Library&#x2F;Mobile Documents&lt;&#x2F;code&gt;にあるので、&lt;code&gt;&#x2F;Library&#x2F;&lt;&#x2F;code&gt;を外せば一緒に消える。&lt;code&gt;pCloud Drive&lt;&#x2F;code&gt;のようにホーム直下へマウントされるものだけ、個別に除外する。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;Library&lt;&#x2F;code&gt;配下をどこまで残すかは判断が要ります。大半はアプリが再生成する状態ファイルなので、丸ごと&lt;code&gt;--exclude=&#x27;Library&#x2F;&#x27;&lt;&#x2F;code&gt;で外しても困らない人は多いでしょう。ただしローカルにしか実体のないデータ(ローカル保存のメールなど)がある場合は、その特定フォルダだけ残す配慮がいります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自動化&quot;&gt;自動化&lt;&#x2F;h2&gt;
&lt;p&gt;週1回の自動実行は、非推奨のcronではなくlaunchdで組みます。さきほどの&lt;code&gt;~&#x2F;bin&#x2F;backup-home.sh&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;chmod +x ~&#x2F;bin&#x2F;backup-home.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次に&lt;code&gt;~&#x2F;Library&#x2F;LaunchAgents&#x2F;com.user.backup-home.plist&lt;&#x2F;code&gt;を作ります。毎週日曜の午前3時に走る例です(Weekdayの0が日曜)。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;xml&quot; data-name=&quot;~&#x2F;Library&#x2F;LaunchAgents&#x2F;com.user.backup-home.plist&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;xml&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; version&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; encoding&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;UTF-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;?&amp;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-tag z-keyword z-other z-doctype&quot;&gt;&amp;lt;!DOCTYPE&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; plist PUBLIC &amp;quot;-&#x2F;&#x2F;Apple&#x2F;&#x2F;DTD PLIST 1.0&#x2F;&#x2F;EN&amp;quot; &amp;quot;http:&#x2F;&#x2F;www.apple.com&#x2F;DTDs&#x2F;PropertyList-1.0.dtd&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;plist&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; version&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;com.user.backup-home&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;ProgramArguments&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;Users&#x2F;ユーザ名&#x2F;bin&#x2F;backup-home.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;StartCalendarInterval&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Weekday&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Hour&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Minute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;plist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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;launchctl bootstrap gui&#x2F;$(id -u) ~&#x2F;Library&#x2F;LaunchAgents&#x2F;com.user.backup-home.plist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;launchdの利点は、指定時刻にMacが起動していなくても、次に起動したときに取りこぼしを拾って実行してくれる点です。cronのように「その時刻に寝ていたら丸ごと飛ぶ」ということがありません。複数回ぶんが溜まっても、起動時に走るのは1回にまとめられます。週一の用途なら、これで実用上困りません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;つまずきどころ&quot;&gt;つまずきどころ&lt;&#x2F;h2&gt;
&lt;p&gt;実際に動かすと、たいてい最初の数回はここで引っかかります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;初回はホーム全体のフルコピーなので、容量とドライブ速度によっては数時間かかる。差分で速くなるのは2回目以降。止まっているのか遅いだけなのかは、&lt;code&gt;du -sk &#x2F;Volumes&#x2F;Backup&#x2F;home&lt;&#x2F;code&gt;を時間を空けて2回打ち、数字が増えているかで判別する。&lt;&#x2F;li&gt;
&lt;li&gt;異常に遅い・止まる場合は、まず標準の&lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;rsync&lt;&#x2F;code&gt;(openrsync)を叩いていないか&lt;code&gt;which rsync&lt;&#x2F;code&gt;で確認する。そして上のクラウド系の除外が効いているかを見る。GoProなどをMTP接続してマウントしている場合、それも&lt;code&gt;Library&#x2F;CloudStorage&lt;&#x2F;code&gt;に入り込んでタイムアウトの山を作るので、除外で一掃される。&lt;&#x2F;li&gt;
&lt;li&gt;Permission Deniedが出ても、rsyncはそのファイルを飛ばして続行する。多くはフルディスクアクセス不足か、root所有の触れないファイルだ。前者は設定で解決し、後者は無視してよいが、拒否されたのが自分の大事なデータでないかだけは確認する。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;この構成にも、諦めた点はあります。起動可能なクローンではないので、ディスクが飛んだら、まずmacOSを入れ直し、それからホームを書き戻す手間が残ります。アプリの再インストールも要ります。「つなげば即座に元通り」とはいきません。そこは割り切りです。&lt;&#x2F;p&gt;
&lt;p&gt;それでも私は、こちらを選びました。中身が見えて、いざとなれば一ファイルから引き出せて、仕組みを丸ごと自分の手で握れる。バックアップに一番ほしいのは、派手な復旧速度ではなく、この「見えている」という安心でした。OSやアプリの都合に振り回されないかぎり、この鏡像は週末ごとに静かに更新され続けてくれます。それだけで、私には十分です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">長年使ってきた起動可能クローンが、macOSの変化でついに作れなくなりました。SuperDuperを手放し、信用しきれないTime Machineにも戻りたくない。残された道はどこにあるのか。見えて、触れて、そのまま取り出せるバックアップを求めて、rsyncによる鏡像コピーへたどり着くまでの記録です。
</summary>
        </entry><entry xml:lang="en">
        <title>三菱UFJ銀行のPPAP廃止は、半歩前進で半歩後退</title>
        <published>2026-06-08T00:00:00+00:00</published>
        <updated>2026-06-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/mufg-ppap/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/mufg-ppap/</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;mufg-ppap&amp;#x2F;cover.webp?h=027a043bdcc9bd7b745e&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;三菱UFJ銀行が2026年6月8日付で「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bk.mufg.jp&#x2F;info&#x2F;pdf&#x2F;20260608_send_attachments.pdf&quot;&gt;当行からの添付ファイル送信方法の変更に関するご案内&lt;&#x2F;a&gt;」を公表しました。
日本を代表するメガバンクがまだPPAPやっていたと衝撃を受けました。
内容を読んで考えさせられたので記録しておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;三菱UFJ銀行のアナウンス&quot;&gt;三菱UFJ銀行のアナウンス&lt;&#x2F;h2&gt;
&lt;p&gt;要点はシンプルです。&lt;&#x2F;p&gt;
&lt;p&gt;同行は、お客さま側のセキュリティを確保するため、パスワード付き添付ファイルのメール送信を原則取り止めると発表しました。
2026年7月18日より順次、添付ファイルを送る際は専用のダウンロードサイトを利用する方式へ変更されます。&lt;&#x2F;p&gt;
&lt;p&gt;理由として挙げられているのは次の2点です。
これまでの「メールでパスワード付きZIPファイルを送り、パスワードを別送する方法」、いわゆる &lt;strong&gt;PPAP&lt;&#x2F;strong&gt; は、ファイルが暗号化されているためメール受信時のマルウェアチェックが困難であること。
そして近年、パスワード付きZIPファイルを悪用したサイバー攻撃の事例が確認されていることです。&lt;&#x2F;p&gt;
&lt;p&gt;新方式では、同行の役職員が添付ファイルを送る際、メール本文に専用ダウンロードサイトへアクセスするためのURLを記載します。
受け手はそのサイトにアクセスし、別送されるダウンロード専用のパスワードを使ってファイルを取得します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;PPAPの何が問題だったのか&quot;&gt;PPAPの何が問題だったのか&lt;&#x2F;h2&gt;
&lt;p&gt;PPAPの是非については、昨年「&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;06&#x2F;aws-sns&#x2F;&quot;&gt;AWSからSMSにメッセージを送る&lt;&#x2F;a&gt;」という記事で一度整理しました。&lt;&#x2F;p&gt;
&lt;p&gt;そのとき、機密文書をメールで送る手段を秘匿性と本人確認性の観点で並べて評価したのですが、結論は変わっていません。&lt;&#x2F;p&gt;
&lt;p&gt;PPAP、つまり暗号化ファイルとパスワードを同じ経路で送る方法は、1通盗まれればすべて漏洩します。
パスワードを別メールにしても、同じメールインフラを流れる以上、傍受や誤送信のリスクは本質的には下がりません。
加えて、暗号化されたZIPはメールゲートウェイでウイルススキャンできないため、マルウェアの運び屋になりやすい。
三菱UFJ銀行が今回理由として挙げているのは、まさにこの最後の点です。&lt;&#x2F;p&gt;
&lt;p&gt;ですから、PPAPをやめるという判断そのものは正しいと思います。
日本でも2020年に政府がPPAPの廃止方針を打ち出して以降の流れに沿っていますし、銀行という立場で旗を振る意味も小さくありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;新方式は本当に安全になったのか&quot;&gt;新方式は本当に安全になったのか&lt;&#x2F;h2&gt;
&lt;p&gt;問題は、その置き換え先です。&lt;&#x2F;p&gt;
&lt;p&gt;新方式は「メール本文にダウンロードサイトのURLを記載し、パスワードは別送する」というものでした。
マルウェアスキャンの観点では確かに前進しています。
ファイルが暗号化ZIPとしてメールに乗らなくなるので、受信側のゲートウェイで中身を検査できるようになるからです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、フィッシング耐性という観点では、むしろ後退しかねません。&lt;&#x2F;p&gt;
&lt;p&gt;ひとつは、銀行が自ら「メール本文のURLをクリックさせる」習慣を送信先に植え付けてしまう点です。
銀行はこれまでフィッシング対策として、「当行からのメールにURLは記載しません」「メール内のリンクは開かないでください」と顧客には教育してきたはずです。
メールの送信先は顧客ではないと思いますが、今回はその逆を習慣づけることになります。
なりすましメールに偽のダウンロードURLが貼られていても、利用者は見分けがつかなくなります。&lt;&#x2F;p&gt;
&lt;p&gt;もうひとつは、「パスワードを別送する」という発想がPPAPのままという点です。
日ごろ支援しているコンサルテーション会社やITベンダーはちゃんと技術的に支援できなかったんでしょうか？&lt;&#x2F;p&gt;
&lt;p&gt;URLとパスワードを両方メールで送るのであれば、構造的にはPPAPの暗号化ZIPをWebサイトに置き換えただけです。
同じ経路を流れる以上、傍受や誤送信による漏洩リスクは解決していません。
マルウェアの問題は片付いても、秘匿性の問題は手つかずなのです。&lt;&#x2F;p&gt;
&lt;p&gt;整理すると、今回の変更は「マルウェアスキャン」という一点ではマシになる一方で、フィッシング耐性では弱点を抱え込む、惜しい設計だと感じます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;本来あるべき姿&quot;&gt;本来あるべき姿&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;06&#x2F;aws-sns&quot;&gt;以前の記事&lt;&#x2F;a&gt;でも書きましたが、
現実的なのは認証付きのクラウドストレージで共有する方法でした。
受け手がログインして初めてファイルにアクセスできる仕組みなら、URLが単体で漏れても無効ですし、誰がいつアクセスしたかのログも残せます。
パスワードを別送する必要すらありません。&lt;&#x2F;p&gt;
&lt;p&gt;メールの送付先は取引業者だと思いますから、銀行が共通の認証を払い出すのは困難です。
たとえばBoxやDropboxのようなクラウドストレージであれば、受け手は無料のアカウントを気軽に作れます。
銀行側が取引先ごとにアカウントを発行・運用しなくても、受け手がログインして初めてファイルにアクセスできる仕組みを成り立たせられるわけです。
URLが単体で漏れても無効ですし、誰がいつアクセスしたかのログも残ります。&lt;&#x2F;p&gt;
&lt;p&gt;さらに言えば、この方式ならメールにリンクを書く必要すらありません。
ファイルを共有すれば、受け手にはクラウドストレージ側から「共有されました」という通知が届きます。
受け手は自分が信頼しているサービスにログインしてファイルを取りに行くだけです。
冒頭で挙げた、メール内URLをクリックさせる習慣づけという問題が、根本から消えてなくなるのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;より根本的な解はないのか&quot;&gt;より根本的な解はないのか&lt;&#x2F;h2&gt;
&lt;p&gt;もっとも、銀行ともあろうものがファイルの受け渡しを外部のクラウドサービスに丸ごと預けるのも、それはそれで引っかかります。
委託先管理やデータの所在、サービスへの従属といった問題が新たに生じるからです。
だとすれば、現実的な落としどころは、銀行が認証付きの受け渡しポータルを自前で持つことでしょう。
インターネットバンキングという認証基盤と運用ノウハウをすでに備え、取引先の本人確認も日常的に行っている組織です。
Boxがやっていることを内製すればよいだけです。技術力と体力の両面で、銀行はそれができる立場にあります。&lt;&#x2F;p&gt;
&lt;p&gt;では、もっと教科書的な根本解はないのか。
あります。受け手の証明書でメールそのものを暗号化・署名するS&#x2F;MIME、いわゆるPKIです。
外部サービスやポータル、パスワードの別送といった仕組みが一切要らず、本人性と秘匿性をエンドツーエンドで担保できる、理屈のうえでは最も美しい解です。&lt;&#x2F;p&gt;
&lt;p&gt;ところがPKIは、米国ですら普及しませんでした。
証明書の発行や管理が高コストで手作業が多く、ユーザーごと・端末ごとに鍵を入れて回る運用負荷に耐えられなかったためです。
そして決定的なのは、&lt;strong&gt;送り手と受け手の双方が対応していないと成り立たない&lt;&#x2F;strong&gt;という両側依存です。
暗号化して送るには、相手があらかじめ証明書を用意していなければなりません。
相手が対応していなければ、文字どおり意味がない。
この鶏と卵の構造ゆえに、誰も最初の一歩を踏み出せませんでした。
受け手に「アカウントを作ってログインする」という自己完結した操作しか求めないポータル方式に世界が流れたのは、そのためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;それでもリーダーシップを期待したかった&quot;&gt;それでもリーダーシップを期待したかった&lt;&#x2F;h2&gt;
&lt;p&gt;ここで私が惜しいと思うのは、まさにこの一点です。
PKIが普及しなかった最大の理由が「最初の一歩を誰も踏み出せなかった」ことなら、その一歩を踏み出せる体力と影響力を持つ組織こそ、日本を代表するメガバンクのはずです。&lt;&#x2F;p&gt;
&lt;p&gt;率先してS&#x2F;MIMEを導入し、添付ファイルをやり取りするような主要な取引先には導入を促す。
場合によっては証明書発行の基盤を貸し出したり、運用を支援したりする。
そうやって両側依存の壁を、影響力のある側から崩していく。
そんなリーダーシップを見せてくれたら、日本全体のメール文化が一段前に進んだかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;現実的な着地は認証付きポータルでよいと思います。
ただ、PPAPをやめるという入口が正しかっただけに、出口がもう一歩踏み込めなかったのは惜しい。
日本をリードする銀行のやることだからこそ、ここにこそリーダーシップを期待したかった、というのが私の正直な感想です。&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.bk.mufg.jp&#x2F;info&#x2F;pdf&#x2F;20260608_send_attachments.pdf&quot;&gt;株式会社三菱UFJ銀行&lt;&#x2F;a&gt;. 「当行からの添付ファイル送信方法の変更に関するご案内」（2026年6月8日）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;06&#x2F;aws-sns&#x2F;&quot;&gt;Coded Chords&lt;&#x2F;a&gt;. 「AWSからSMSにメッセージを送る」（2025年6月9日）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">日本を代表する銀行がPPAPの廃止を発表しました。マルウェア対策としては正しい一歩ですが、新しい受け渡し方法には見過ごせない落とし穴が残っています。</summary>
        </entry><entry xml:lang="en">
        <title>Amazon S3からCloudflare R2への移行</title>
        <published>2026-05-22T00:00:00+00:00</published>
        <updated>2026-05-22T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/05/cloudflare-r2/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/05/cloudflare-r2/</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;05&amp;#x2F;cloudflare-r2&amp;#x2F;cover.webp?h=1e92776e8f350ad0d4c1&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;以前「&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;01&#x2F;blog-to-zola-aws-cleanup&#x2F;&quot;&gt;ブログをZolaに移行、AWSの後始末&lt;&#x2F;a&gt;」で、Next.js + Amplify構成のブログをZolaへ移し、Amplifyを含む大半のAWSリソースを削除しました。ただ、そのとき1つだけ削除せずに残したものがあります。有償のWEBフォントを配信するためのS3バケットとCloudFrontです。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、この最後のAWSリソースをCloudflare R2へ移した記録をまとめます。題材はフォント1つですが、個人ブログのスタティックなリソースをS3とR2のどちらに置くか、という選択の話でもあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;移行前の構成&quot;&gt;移行前の構成&lt;&#x2F;h2&gt;
&lt;p&gt;配信していたのは有償のWEBフォントです。このフォントはライセンス上、誰でもwoff2ファイルをダウンロードできる状態にしておくわけにはいきません。一方でWEBフォントである以上、ブラウザからは取得できる必要があります。この相反する要件を、移行前はAWS側で次のように満たしていました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-oac-1&quot;&gt;&lt;a href=&quot;#fn-oac&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;woff2ファイルをS3バケットに保管し、その前段のCloudFrontから配信&lt;&#x2F;li&gt;
&lt;li&gt;CloudFront FunctionでリクエストのRefererヘッダを検査し、ブログのドメイン以外からのアクセスを遮断&lt;&#x2F;li&gt;
&lt;li&gt;S3バケットポリシーにも同じReferer条件を設定し、CloudFrontを経由しないS3への直接アクセスも遮断&lt;&#x2F;li&gt;
&lt;li&gt;フォントがCloudFrontのドメイン(ブログとは別オリジン)から読み込まれるため、S3側のCORS設定でブログのドメインからの要求のみを許可&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ブログのCSSでは、すべての &lt;code&gt;@font-face&lt;&#x2F;code&gt; がこのCloudFrontのURLを参照していました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflare_R2_への移行&quot;&gt;Cloudflare R2 への移行&lt;&#x2F;h2&gt;
&lt;p&gt;ブログのワークロードは、すでにCloudflareに移っていました。ホスティングはCloudflare Workersの静的アセット配信で動いており、フォントだけをAWSに残しておく理由は薄くなっていました。配信元をS3 + CloudFrontからCloudflare R2に移すと、次のメリットがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AWSとCloudflareに分かれていたインフラの一本化&lt;&#x2F;li&gt;
&lt;li&gt;Referer制限のための仕組み(CloudFront Function・バケットポリシーの条件・CORS)の全廃&lt;&#x2F;li&gt;
&lt;li&gt;フォントの同一オリジン配信化(別オリジンへの &lt;code&gt;preconnect&lt;&#x2F;code&gt; やCSP調整が不要)&lt;&#x2F;li&gt;
&lt;li&gt;R2のストレージ無料枠(10GB)に収まる配信コスト&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に大きいのは2番目です。R2バケットは、公開設定を有効にしない限り外部から到達できるURLを持たず、フォントへのアクセス手段はWorkerからのR2 Bindingだけになります。S3 + CloudFrontでは、公開バケットへのアクセスをReferer条件で絞り込む必要がありました。R2では公開URLがそもそも存在しないため、アクセス元を判定する仕組み自体が要らなくなります。守るための要素が減ることは、設定ミスの余地が減ることでもあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;移行後の保護モデル&quot;&gt;移行後の保護モデル&lt;&#x2F;h2&gt;
&lt;p&gt;新しい構成では、フォントの保護を4つのレイヤーで担保しています。&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;th&gt;防ぐ脅威&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;バケット非公開&lt;&#x2F;td&gt;&lt;td&gt;r2.dev 無効・カスタムドメイン未割当・CORS なし&lt;&#x2F;td&gt;&lt;td&gt;バケット URL の直接スクレイプ、検索エンジンの索引&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;R2 Binding 経由のみ&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;[[r2_buckets]]&lt;&#x2F;code&gt; 宣言により同一 Cloudflare アカウント内に限定&lt;&#x2F;td&gt;&lt;td&gt;他アカウントや外部ネットワークからの参照&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;Worker が公開面を制限&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;fonts&#x2F;&amp;lt;file&amp;gt;&lt;&#x2F;code&gt; パスのみを公開し、不正なキーは弾く&lt;&#x2F;td&gt;&lt;td&gt;パストラバーサル、任意キーの READ、バケット列挙&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;長寿命クレデンシャル不在&lt;&#x2F;td&gt;&lt;td&gt;R2 API トークンを発行しない&lt;&#x2F;td&gt;&lt;td&gt;コミットや CI ログ経由のトークン漏洩&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;設計の本質は、ライセンス違反が最も起きやすい経路、つまり公開バケットのURLがクローラに拾われて検索結果に載ることを消す点にあります。閲覧者がDevToolsからフォントを保存する行為や、第三者サイトからのホットリンクは別レイヤーの問題で、WEBフォント配信の仕組み上、完全には防げません。必要ならWorkerにReferer許可リストを足すこともできますが、今回は入れていません。私が利用しているフォントのライセンスでは、ライセンシーのドメインから配信することが求められていて、リクエスト元の検査までは要件になっていないためです。ただし、これはフォントごとに異なります。CORSやドメイン制限を技術的保護措置としてEULAで義務づけているフォントもあるので、利用するフォントのライセンスは必ず確認してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Worker_と_R2_の構成&quot;&gt;Worker と R2 の構成&lt;&#x2F;h2&gt;
&lt;p&gt;実装は驚くほど小さく収まりました。まずR2バケットを作成します(ここでは &lt;code&gt;web-fonts&lt;&#x2F;code&gt; という名前にします)。公開設定は無効のままにし、S3と同じキー名でwoff2をアップロードします。あとはWorkerからbindingでつなぐだけです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;wrangler.toml&lt;&#x2F;code&gt; にR2バケットのbindingを宣言します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot; data-name=&quot;wrangler.toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;name&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 z-definition z-string z-string&quot;&gt; &amp;quot;blog&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;main&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 z-definition z-string z-string&quot;&gt; &amp;quot;src&#x2F;index.js&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;compatibility_date&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 z-definition z-string z-string&quot;&gt; &amp;quot;2026-02-17&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&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;assets&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;directory&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 z-definition z-string z-string&quot;&gt; &amp;quot;.&#x2F;public&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;binding&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 z-definition z-string z-string&quot;&gt; &amp;quot;ASSETS&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&quot;&gt;[[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;r2_buckets&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;binding&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 z-definition z-string z-string&quot;&gt; &amp;quot;FONTS&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;bucket_name&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 z-definition z-string z-string&quot;&gt; &amp;quot;web-fonts&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Worker本体は、&lt;code&gt;&#x2F;fonts&#x2F;&lt;&#x2F;code&gt; で始まるリクエストをR2に取り次ぎ、それ以外は静的アセットに渡すだけです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot; data-name=&quot;src&#x2F;index.js&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; FONTS_PREFIX&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;quot;&#x2F;fonts&#x2F;&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-keyword&quot;&gt;export default&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-storage z-modifier&quot;&gt;  async&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; fetch&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;req&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; env&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-storage z-type&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js z-source&quot;&gt;url)&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-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pathname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;startsWith&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-constant z-js&quot;&gt;(FONTS_PREFIX))&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-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; key&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; decodeURIComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pathname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;FONTS_PREFIX&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;length))&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; Only flat keys in R2 (no subdir, no traversal). Anything else falls&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; through to static assets — the theme also publishes under &#x2F;fonts&#x2F;.&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; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;includes&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;..&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;includes&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;FONTS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-storage z-type&quot;&gt;          const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;          obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;writeHttpMetadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;          headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Content-Type&amp;quot;&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;quot;font&#x2F;woff2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;          headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Cache-Control&amp;quot;&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;quot;public, max-age=31536000, immutable&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;          headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;ETag&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; obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js z-source&quot;&gt;httpEtag)&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;          return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt; headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&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;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;ASSETS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;fetch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&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;最後にCSSの参照先を書き換えます。&lt;code&gt;@font-face&lt;&#x2F;code&gt; の &lt;code&gt;src&lt;&#x2F;code&gt; は、これまでCloudFrontの絶対URLを指していましたが、同一オリジンの相対パス &lt;code&gt;&#x2F;fonts&#x2F;&lt;&#x2F;code&gt; に変わります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;css&quot; data-name=&quot;custom.css&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-keyword z-keyword&quot;&gt;@font-face&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-type z-property-name z-css&quot;&gt;  font-family&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 z-definition z-string z-string&quot;&gt; &amp;quot;WebFont&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-type z-property-name z-css&quot;&gt;  src&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-support z-function&quot;&gt; url&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;quot;&#x2F;fonts&#x2F;WebFont-Regular.woff2&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-misc&quot;&gt;    format&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;quot;woff2&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-type z-property-name z-css&quot;&gt;  font-display&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; swap&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-type z-property-name z-css&quot;&gt;  font-weight&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-constant z-numeric&quot;&gt; 400&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-type z-property-name z-css&quot;&gt;  font-style&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; normal&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;CSS内のすべての &lt;code&gt;@font-face&lt;&#x2F;code&gt; で、CloudFrontの絶対URLを &lt;code&gt;&#x2F;fonts&#x2F;&lt;&#x2F;code&gt; で始まる相対パスに置き換えます。デプロイはmainへのpushでGitHub Actionsが &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt; を実行する流れに乗せます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;つまずいた点&quot;&gt;つまずいた点&lt;&#x2F;h2&gt;
&lt;p&gt;デプロイ用のAPIトークンの権限不足でつまずきました。GitHub Actionsが使う &lt;code&gt;CLOUDFLARE_API_TOKEN&lt;&#x2F;code&gt; は旧構成(静的アセット配信のみ)のときに発行したもので、Workers Scriptsの編集権限しかありませんでした。R2 bindingを含むWorkerを &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt; すると、宣言したバケットの存在確認でR2のAPIを呼び出すため、初回のpushは &lt;code&gt;code: 10000 Authentication error&lt;&#x2F;code&gt; で失敗しました。&lt;&#x2F;p&gt;
&lt;p&gt;幸い、Cloudflare Workersのデプロイは原子的です。失敗時は旧Workerが稼働し続けるため、復旧作業中もサイトは旧CloudFront経由でフォントを配信し続け、見た目は保たれていました。&lt;&#x2F;p&gt;
&lt;p&gt;対応として、APIトークンにAccountスコープの &lt;code&gt;Workers R2 Storage: Edit&lt;&#x2F;code&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;th&gt;用途&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Account&lt;&#x2F;td&gt;&lt;td&gt;Workers Scripts: Edit&lt;&#x2F;td&gt;&lt;td&gt;Worker スクリプトのデプロイ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Account&lt;&#x2F;td&gt;&lt;td&gt;Workers R2 Storage: Edit&lt;&#x2F;td&gt;&lt;td&gt;R2 binding 宣言時のバケット存在確認&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Account&lt;&#x2F;td&gt;&lt;td&gt;Account Settings: Read&lt;&#x2F;td&gt;&lt;td&gt;アカウント情報の照会&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Zone&lt;&#x2F;td&gt;&lt;td&gt;Workers Routes: Edit&lt;&#x2F;td&gt;&lt;td&gt;カスタムルートの設定&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;User&lt;&#x2F;td&gt;&lt;td&gt;Memberships: Read&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;memberships&lt;&#x2F;code&gt; API の呼び出し&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;User&lt;&#x2F;td&gt;&lt;td&gt;User Details: Read&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;wrangler whoami&lt;&#x2F;code&gt; 相当の照会&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Cloudflare公式の「Edit Cloudflare Workers」テンプレートにはR2の権限が含まれていません。新しいbinding(R2 &#x2F; D1 &#x2F; KV &#x2F; Queuesなど)をWorkerに足すときは、デプロイ前にCIトークンの権限を見直すのが安全です。トークンを差し替えたあとは、失敗したジョブだけを再実行しました。&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-source&quot;&gt;DEPLOY_ID&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;gh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run list --branch main&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;  --workflow=&amp;quot;&amp;lt;デプロイ用ワークフロー名&amp;gt;&amp;quot; --limit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&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;  --json databaseId --jq &amp;#39;.[0].databaseId&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-entity z-name z-function&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; run rerun &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DEPLOY_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --failed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AWS_リソースの撤去&quot;&gt;AWS リソースの撤去&lt;&#x2F;h2&gt;
&lt;p&gt;R2配信が本番で安定したことを確認してから、AWS側を停止しました。撤去対象はCloudFrontディストリビューション、CloudFront Function、S3バケットの3つです。ディストリビューションIDは &lt;code&gt;aws cloudfront list-distributions&lt;&#x2F;code&gt;、バケット名は &lt;code&gt;aws s3 ls&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-source&quot;&gt;DIST_ID&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;quot;&amp;lt;対象ディストリビューションのID&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-source&quot;&gt;FUNCTION_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;quot;&amp;lt;Referer を検査していた CloudFront Function 名&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-source&quot;&gt;BUCKET&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;quot;&amp;lt;フォントを置いていた S3 バケット名&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CloudFrontディストリビューションは、いきなり削除できません。先に &lt;code&gt;Enabled = false&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-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront get-distribution-config --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&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-keyword z-operator&quot;&gt;  &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;dist-config.json&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;jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -r &amp;#39;.ETag&amp;#39; &#x2F;tmp&#x2F;dist-config.json&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; &#x2F;tmp&#x2F;dist-etag.txt&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;jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;.DistributionConfig | .Enabled = false&amp;#39; &#x2F;tmp&#x2F;dist-config.json&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-keyword z-operator&quot;&gt;  &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;dist-config-disabled.json&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront update-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&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;  --if-match &amp;quot;&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;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;dist-etag.txt&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-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;  --distribution-config &amp;quot;file:&#x2F;&#x2F;&#x2F;tmp&#x2F;dist-config-disabled.json&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;update-distribution&lt;&#x2F;code&gt; は &lt;code&gt;Status: InProgress&lt;&#x2F;code&gt; を返します。&lt;code&gt;Status: Deployed&lt;&#x2F;code&gt; に戻るまで伝播を待ちます(実測で約3分)。&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-keyword&quot;&gt;until&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-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront get-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&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;  --query &amp;#39;Distribution.Status&amp;#39; --output text&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-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Deployed&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; do&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;  sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 30&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;Deployed&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-source&quot;&gt;ETAG&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront get-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&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;  --query &amp;#39;ETag&amp;#39; --output text&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-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront delete-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --if-match &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$ETAG&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CloudFront Functionの削除では、&lt;code&gt;describe-function&lt;&#x2F;code&gt; で取得した現在のETagを &lt;code&gt;delete-function&lt;&#x2F;code&gt; に渡します。注意点として、FunctionはDEVELOPMENTとLIVEの2つのステージを持ち、両者を別々に更新しているとETagが食い違います。私の環境ではDEVELOPMENT側が新しく、&lt;code&gt;describe-function --stage DEVELOPMENT&lt;&#x2F;code&gt; で取ったETagでなければ &lt;code&gt;PreconditionFailed&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-source&quot;&gt;ETAG&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront describe-function --name &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$FUNCTION_NAME&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;  --stage DEVELOPMENT --query &amp;#39;ETag&amp;#39; --output text&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-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront delete-function --name &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$FUNCTION_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --if-match &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$ETAG&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後にS3バケットを空にして削除します。&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; s3 rm &amp;quot;s3:&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$BUCKET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --recursive&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; s3api delete-bucket --bucket &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$BUCKET&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ACM証明書は、CloudFrontのデフォルトドメイン(&lt;code&gt;*.cloudfront.net&lt;&#x2F;code&gt;)のまま運用していて発行していなかったため、削除対象はありませんでした。これでフォント配信に関わるAWSリソースはすべて無くなり、配信はR2経由に一本化されました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;移行して変わったこと&quot;&gt;移行して変わったこと&lt;&#x2F;h2&gt;
&lt;p&gt;移行の前後で、AWS側にあったCloudFrontディストリビューション、CloudFront Function、S3バケット、バケットポリシー、CORS設定がすべて消えました。残ったのはR2バケット1つと、ごく短いWorkerスクリプト1つです。&lt;&#x2F;p&gt;
&lt;p&gt;今回移したのはフォント一式というごく小さなリソースで、Cloudflareの無料枠の範囲で十分にまかなえています。コスト面より、管理対象のサービス数が減ったことのほうが効きます。フォント1種類のためにCloudFrontとS3とFunctionの3サービスを横断して設定を追っていた状態から、Cloudflareのダッシュボード内で完結する状態になりました。&lt;&#x2F;p&gt;
&lt;p&gt;今回はフォントが題材でしたが、結論はもっと一般的だと考えています。個人ブログのスタティックなリソースの置き場所としては、Amazon S3 + CloudFrontよりもCloudflare R2のほうが向いています。R2なら公開URLを持たせずにWorkerから読め、S3のように公開バケットを設定で囲い込む手間がいりません。ホスティングがCloudflareにあれば置き場も同じプラットフォームにまとまり、費用も無料枠と転送料無料で個人規模なら気になりません。&lt;&#x2F;p&gt;
&lt;p&gt;S3が劣るという話ではありません。ただ、個人ブログの規模で、すでにCloudflareを使っているなら、スタティックなリソースはR2に置くのが素直な選択だと思います。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-oac&quot;&gt;
&lt;p&gt;より確実な構成にするなら、S3バケットを非公開にしてOAC(Origin Access Control)経由でのみ読ませる方法もありました。ただしWEBフォントはページの一部としてブラウザに読み込まれる以上、閲覧者によるダウンロードまで完全に防ぐことはどのみちできません。完全な防御は不可能だという前提で、ある程度は妥協した構成でした。 &lt;a href=&quot;#fr-oac-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">ブログに最後まで残っていたAWSリソースは、有償WEBフォントの
配信でした。これをAmazon S3とCloudFrontからCloudflare R2へ
移した記録であり、個人ブログのスタティックなリソースを
どこに置くべきかを考える材料でもあります。
</summary>
        </entry><entry xml:lang="en">
        <title>ChatGPT Images 2.0と、ブログのカバー画像パイプライン更新</title>
        <published>2026-05-15T20:00:00+09:00</published>
        <updated>2026-05-15T20:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/05/chatgpt-images-2-0/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/05/chatgpt-images-2-0/</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;05&amp;#x2F;chatgpt-images-2-0&amp;#x2F;cover.webp?h=2ba98580c0d5e882e1a8&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;OpenAIは2026年4月21日、新しい画像生成モデルChatGPT Images 2.0を発表しました。API名は &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; で、開発者向けには5月初旬から開放されています。私のブログではカバー画像の自動生成に旧モデル &lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; を使っていたので、乗り換える価値があるかを調べた上で、今回のリリースに合わせて実際に移行しました。本稿では、新モデルで何が変わったか、料金へのインパクト、そして自分のブログでの乗り換え作業をまとめます。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&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;ChatGPT_Images_2.0で何が変わったか&quot;&gt;ChatGPT Images 2.0で何が変わったか&lt;&#x2F;h2&gt;
&lt;p&gt;ChatGPT Images 2.0の特徴は、画像生成に「考えてから描く」という工程が入ったことです。プロンプトを受け取ったあとに構図やレイアウトを推論で組み立て、必要に応じて自己検証を挟んでから描画に進みます。OpenAI自身は「Agentic image generation」と表現しており、テキストから画像へのワンショット変換とは異なる挙動を示します。&lt;&#x2F;p&gt;
&lt;p&gt;実務面で効いてくる改良点を並べると次のようになります。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;テキスト描画の精度向上&lt;&#x2F;dt&gt;
&lt;dd&gt;看板・図表・タイトルなど、画像内の文字を読める品質で出せるようになりました。印刷物にも耐える水準とされています。&lt;&#x2F;dd&gt;
&lt;dt&gt;ネイティブ2K解像度&lt;&#x2F;dt&gt;
&lt;dd&gt;2048x2048を素のままで生成でき、有料プランでは4Kまでのアップスケールが選べます。前世代の引き伸ばし感は減りました。&lt;&#x2F;dd&gt;
&lt;dt&gt;自由なアスペクト比&lt;&#x2F;dt&gt;
&lt;dd&gt;3:1から1:3までの範囲で、16の倍数を満たす任意のサイズを指定できます。固定プリセットから連続パラメータへの転換です。&lt;&#x2F;dd&gt;
&lt;dt&gt;マルチイメージのバッチ生成&lt;&#x2F;dt&gt;
&lt;dd&gt;&lt;code&gt;n=1〜8&lt;&#x2F;code&gt; でキャラクターやオブジェクトの一貫性を保ったまま、最大8枚を同時生成できます。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;なお「Thinking mode」と呼ばれる、Web検索を生成中に挟んで結果を補強する追加機能はChatGPT本体のPlus・Pro・Business・Enterpriseプランに限定されています。APIから素直に呼び出した場合に同等の挙動が得られるかは現時点で公開情報からは判然としません。日常的なカバー画像生成では恩恵が薄いため、本稿では深掘りしません。&lt;&#x2F;p&gt;
&lt;p&gt;合わせて、旧世代モデルのDALL·E 2およびDALL·E 3は2026年5月12日付で廃止されています。&lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; 自体の廃止は告知されていませんが、明確に前世代の位置づけになりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;料金面のインパクト&quot;&gt;料金面のインパクト&lt;&#x2F;h2&gt;
&lt;p&gt;OpenAIの画像APIは、出力トークンに対する従量課金($30.00&#x2F;100万トークン)を基準に、サイズと品質ごとに代表的な価格が公表されています。私のブログでは1536x1024&#x2F;高品質を使っていたので、その線で比較します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;解像度 &#x2F; 品質&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;gpt-image-1&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;gpt-image-2&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;差分&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1024x1024 &#x2F; high&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.167&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.211&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;+26%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1536x1024 &#x2F; high(旧設定)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.25&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.165&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;-34%&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1536x1024 &#x2F; medium&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.063&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.041&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;-35%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1536x1024 &#x2F; low&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.016&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.005&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;-69%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;興味深いのは、&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; では1024x1024より1536x1024のほうが安いという逆転が起きている点です。&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; は連続的なサイズ指定とトークンベースの課金に振り切ったため、画素数と価格の関係が必ずしも単調ではなくなりました。これは料金表というよりトークン課金の写像として読むべきもので、サイズによる単純な大小比較は通用しなくなっています。&lt;&#x2F;p&gt;
&lt;p&gt;絶対額で見ると、記事1本あたり$0.085ほどの削減です。年に50本書いても$4程度なので、コスト最適化自体が主目的にはなりません。ただし「安くなって性能が上がる」方向の更新であり、乗り換えを見送る理由はありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;output_format=webp_のバグ&quot;&gt;&lt;code&gt;output_format=webp&lt;&#x2F;code&gt; のバグ&lt;&#x2F;h2&gt;
&lt;p&gt;実装中に確認したところ、&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; は &lt;code&gt;output_format=webp&lt;&#x2F;code&gt; を指定しても、実際にはPNGデータを返してきます。レスポンスJSONには &lt;code&gt;&quot;output_format&quot;: &quot;webp&quot;&lt;&#x2F;code&gt; が含まれているものの、&lt;code&gt;b64_json&lt;&#x2F;code&gt; をデコードすると先頭が &lt;code&gt;89 50 4E 47 0D 0A 1A 0A&lt;&#x2F;code&gt; のPNGシグネチャになっています。&lt;&#x2F;p&gt;
&lt;p&gt;同一パラメータを &lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; に渡した場合は正しくWebPが返るため、現時点では &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; 固有の不具合と判断しています。&lt;&#x2F;p&gt;
&lt;p&gt;そのため、本記事で示すスクリプトではAPIレスポンスをPNGとして受け取り、内部で &lt;code&gt;cwebp -q 80&lt;&#x2F;code&gt; によりWebPへ再エンコードしています。呼び出し側インターフェースは変更せず、最終的には1536x864のWebPファイルを取得できます。&lt;&#x2F;p&gt;
&lt;p&gt;OpenAI側で修正された場合は、&lt;code&gt;output_format=webp&lt;&#x2F;code&gt; をそのまま利用し、内部変換ステップを削除する想定です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ブログのパイプラインを乗り換える&quot;&gt;ブログのパイプラインを乗り換える&lt;&#x2F;h2&gt;
&lt;p&gt;私のブログではカバー画像を &lt;code&gt;scripts&#x2F;generate-cover.sh&lt;&#x2F;code&gt; からOpenAI Image APIを叩いて生成しています。これまでは &lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; から1536x1024のPNGを受け取り、&lt;code&gt;cwebp -q 80&lt;&#x2F;code&gt; でWebPに変換して &lt;code&gt;cover.webp&lt;&#x2F;code&gt; を作っていました。新モデルへの移行で、このパイプラインが得る恩恵は大きく2点あります。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;画像精度の底上げ&lt;&#x2F;dt&gt;
&lt;dd&gt;テキスト描画・構図・解像度がモデルレベルで改善するため、カバー画像の見栄えが直接良くなります。&lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; とのAPI互換性が高く、エンドポイント・認証・レスポンス形式(&lt;code&gt;b64_json&lt;&#x2F;code&gt;)はそのまま使えるため、これだけなら &lt;code&gt;MODEL&lt;&#x2F;code&gt; 変数を &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; に書き換えれば享受できます。&lt;&#x2F;dd&gt;
&lt;dt&gt;画角の自由度&lt;&#x2F;dt&gt;
&lt;dd&gt;画角16:9で指定できるようになりました。&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; のサイズパラメータは「16の倍数」「総画素数65万〜829万」「縦横比3:1〜1:3」を満たす任意の値を受け付けるため、1536x864のような正確な16:9に直接出力できます。旧モデルのプリセット制約から3:2(1536x1024)に妥協していた本ブログでは、記事一覧の見栄えとX(旧Twitter)・はてなブックマークなどのSNSカードプレビューの収まりが、ようやく現代のプラットフォームと噛み合うようになりました。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&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;scripts&#x2F;generate-cover.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;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 z-definition z-string z-string&quot;&gt;&amp;quot;1536x864&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;MODEL&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;quot;gpt-image-2&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-source&quot;&gt;RESPONSE&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;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s&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&quot;&gt;  https:&#x2F;&#x2F;api.openai.com&#x2F;v1&#x2F;images&#x2F;generations&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;  -H &amp;quot;Content-Type: application&#x2F;json&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;  -H &amp;quot;Authorization: Bearer &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OPENAI_API_KEY&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;  -d &amp;quot;&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;jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -n&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;    --arg model &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MODEL&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;    --arg prompt &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$PROMPT&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;    --arg size &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$SIZE&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;    --arg quality &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$QUALITY&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-punctuation z-definition z-string z-string&quot;&gt;    &amp;#39;{model: $model, prompt: $prompt, n: 1,&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;      size: $size, quality: $quality}&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&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このスクリプトを呼び出している &lt;code&gt;article-cover&lt;&#x2F;code&gt; スキル(Claude Code用のカスタムコマンド)の全体は次のとおりです。記事の特定からフロントマター確認までを4ステップで定義しており、&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; への移行に際しての変更は不要でした。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot; data-name=&quot;.claude&#x2F;commands&#x2F;article-cover.md&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-entity z-name z-tag z-yaml&quot;&gt;description&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-string&quot;&gt; Generate a cover image for an article using OpenAI gpt-image-2 API. Read article content, craft a prompt, generate 1536x864 (16:9) WebP image.&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;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\31  z-markdown&quot;&gt;# Article Cover Image Generation&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-text&quot;&gt;Generate a cover image (cover.webp) for an article using OpenAI gpt-image-2 API.&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-heading z-markdown z-heading z-\32  z-markdown&quot;&gt;## Steps&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 1. Identify Target Article&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-text&quot;&gt;Ask the user which article to generate a cover image for.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Read the article content to understand the theme and key topics.&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 2. Craft Image Prompt&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-text&quot;&gt;Based on the article content:&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; Identify the core theme and visual concepts&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; Craft a gpt-image-2 prompt that captures the article&amp;#39;s essence&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; Show the prompt to the user for approval before generating&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 3. Generate 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;span class=&quot;z-text&quot;&gt;Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`.&#x2F;scripts&#x2F;generate-cover.sh`&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition&quot;&gt;```&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;.&#x2F;scripts&#x2F;generate-cover.sh \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  -p &amp;quot;&amp;lt;approved prompt&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-text&quot;&gt;  -o content&#x2F;blog&#x2F;YYYY&#x2F;MM&#x2F;slug&#x2F;cover.webp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition&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-text&quot;&gt;The script defaults to 1536x864 (16:9), high quality, and WebP output.&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 4. Verify Frontmatter&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-text&quot;&gt;Ensure the article frontmatter has:&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&quot;&gt;```&lt;&#x2F;span&gt;&lt;span class=&quot;z-fenced_code z-block z-language&quot;&gt;toml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;[extra]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;local_image = &amp;quot;cover.webp&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;social_media_card = &amp;quot;ogp.webp&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition&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;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;ChatGPT Images 2.0は、価格が下がり、解像度とアスペクト比の選択肢が広がった、素直なアップグレードでした。&lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; を呼んでいる既存コードであれば、&lt;code&gt;model&lt;&#x2F;code&gt; を差し替えるだけで動き始めます。&lt;&#x2F;p&gt;
&lt;p&gt;連続的なサイズ指定や推論を伴う構図設計といった点は、定型的なカバー画像生成だけでなく、SNS向け縦長フォーマットや図解付き画像など、これまで複数モデルを使い分けていた領域も &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; 1本に集約しうるポテンシャルを持ちます。エージェント型ワークフローからの呼び出しでも、複数枚の一貫した出力をシングルリクエストで得られる点が効いてきそうです。&lt;&#x2F;p&gt;
&lt;p&gt;しばらくこのパイプラインを運用してみて、生成品質や絵柄の傾向で気になる点、あるいは &lt;code&gt;output_format=webp&lt;&#x2F;code&gt; まわりの挙動に変化があれば、別途取り上げます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&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;openai.com&#x2F;index&#x2F;introducing-chatgpt-images-2-0&#x2F;&quot;&gt;OpenAI&lt;&#x2F;a&gt;.「Introducing ChatGPT Images 2.0」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.openai.com&#x2F;api&#x2F;docs&#x2F;models&#x2F;gpt-image-1&quot;&gt;OpenAI API Docs&lt;&#x2F;a&gt;.「GPT Image 1 Model」(価格比較用)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;openai.com&#x2F;api&#x2F;pricing&#x2F;&quot;&gt;OpenAI API Pricing&lt;&#x2F;a&gt;.「OpenAI API Pricing」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;techcrunch.com&#x2F;2026&#x2F;04&#x2F;21&#x2F;chatgpts-new-images-2-0-model-is-surprisingly-good-at-generating-text&#x2F;&quot;&gt;TechCrunch&lt;&#x2F;a&gt;.「ChatGPT&#x27;s new Images 2.0 model is surprisingly good at generating text」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;thenewstack.io&#x2F;chatgpt-images-20-openai&#x2F;&quot;&gt;The New Stack&lt;&#x2F;a&gt;.「With the launch of ChatGPT Images 2.0, OpenAI now &#x27;thinks&#x27; before it draws」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
</content>
        <summary type="html">OpenAIが2026年4月21日にリリースしたChatGPT Images 2.0は、画像生成に推論能力を組み込んだ新世代のモデルです。1536x864&#x2F;高品質で料金は約34%下がり、ネイティブ2K解像度や3:1から1:3までの自由なアスペクト比も使えるようになりました。本ブログのカバー画像生成パイプラインも、このタイミングで乗り換えました。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Platform on AWSに見る新時代のハイパースケーラー</title>
        <published>2026-05-13T20:00:00+09:00</published>
        <updated>2026-05-13T20:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/05/claude-platform-aws/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/05/claude-platform-aws/</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;05&amp;#x2F;claude-platform-aws&amp;#x2F;cover.webp?h=8abf7062e68c7aef84c7&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;2026年5月11日、AnthropicとAWSは「Claude Platform on AWS」を一般提供開始しました。Anthropic本家のMessages APIやConsoleの体験そのものを、AWSアカウントから直接利用できる新しい入口で、東京リージョンも初日から対応しています。ただし本稿で読み解きたいのは、機能の追加そのものではなく、この発表が示すAWSの立ち位置の構造的な変化です。Bedrockとの違い、Cloud 2.0レイヤーでの位置づけ、AWS提案の現場への影響という3つの角度から見ていきます。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&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;Claude_Platform_on_AWSとは何か&quot;&gt;Claude Platform on AWSとは何か&lt;&#x2F;h2&gt;
&lt;p&gt;新サービスの概要は次のとおりです。Anthropicが運用するClaude Platformそのものを、AWSアカウントの認証情報と請求経路を介して利用できるようにしたものです。利用者から見えるエンドポイントもSDKの作法も、Anthropic本家のそれとほぼ共通しています。&lt;&#x2F;p&gt;
&lt;p&gt;具体的には、SDKに &lt;code&gt;ANTHROPIC_BASE_URL=https:&#x2F;&#x2F;aws-external-anthropic.&amp;lt;region&amp;gt;.api.aws&lt;&#x2F;code&gt; と &lt;code&gt;anthropic-workspace-id&lt;&#x2F;code&gt; ヘッダーを設定するだけで、Anthropic向けに書いたコードがそのままAWS経路で動きます。認証はAWSのIAM資格情報で行ない、別途Anthropicアカウントを取る必要はありません。利用料はAWS Marketplace経由で計上され、Cost Explorerでモニタリングでき、Enterprise Discount ProgramなどのAWSコミット消化対象にもなります。&lt;&#x2F;p&gt;
&lt;p&gt;使える機能はAnthropic本家とほぼ同等です。Messages APIから最新のエージェント関連機能まで一通り揃い、モデルもClaude Opus 4.7、Sonnet 4.6、Haiku 4.5を同日提供しています。新モデルや新機能がリリース当日(Day-0)から使えるという点こそ、これまでBedrock側の取り込みを待たされてきた構図が崩れた、今回の本質的な変化です。&lt;&#x2F;p&gt;
&lt;p&gt;監査はCloudTrailのManagement Eventsがデフォルトで記録され、推論呼び出しそのものはオプションでData Eventsとして流せます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;Workspaceは、APIキー・権限・課金・月次上限を環境やチーム単位で分離できる、Anthropic Console固有の論理単位です。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;もう一点、Workspaceという新しい概念が入りました。これはプロジェクト・環境・チームを切り分けつつ請求単位も分けられるIAMリソースで、Anthropic Consoleにあるワークスペースの仕組みをAWS IAMの語彙で組み込んだものです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Bedrockと何が違うのか&quot;&gt;Bedrockと何が違うのか&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicのモデルならBedrock経由で既に使えるのに、なぜ別の経路を用意したのか。本サービスをBedrockと比較したときのPros&#x2F;Consは次のとおりです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;Pros&lt;&#x2F;dt&gt;
&lt;dd&gt;AWSの統制・監査基盤の上で、Anthropic本家とほぼ同等の機能と最新モデルをDay-0で使える。&lt;&#x2F;dd&gt;
&lt;dt&gt;Cons&lt;&#x2F;dt&gt;
&lt;dd&gt;データがAWS外で扱われるため別建てのデータ管理が必要になる。加えてClaude専用のため、マルチモデル戦略は取れない。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;機能面の違いを並べると次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;観点&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Amazon Bedrock&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Claude Platform on AWS&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;推論データの処理者・処理境界&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AWS(AWS境界内)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Anthropic(AWS境界外)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;新モデル・新機能の追随&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;数週〜数か月遅れ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Day-0で揃う&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;モデルベンダー多様性&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;多ベンダー(十数社)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Claudeのみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AWS IAM &#x2F; Marketplace &#x2F; CloudTrail&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合あり&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合あり&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;違いは大きく分けて、データの境界と機能の追随速度という2点に集約できます。&lt;&#x2F;p&gt;
&lt;p&gt;Bedrockの構造では、AWSが推論基盤までを自社で運用し、データ処理者としての責任を負います。推論はAWSのセキュリティ境界の内側で行われ、入力データはAnthropicへは共有されません。推論にAWSのデータ統制を要求するエンタープライズ用途に向いた構造です。&lt;&#x2F;p&gt;
&lt;p&gt;一方、Claude Platform on AWSは、認証と請求と監査こそAWSが提供しますが、推論サービス自体はAnthropicが運用する基盤で動きます。データはAWSのセキュリティ境界の外側、Anthropicの管理下で処理されます。この差はコンプライアンス上、本質的です。データレジデンシーやAWS境界内処理を契約で求めている組織には、Bedrockのほうが依然として現実解です。&lt;&#x2F;p&gt;
&lt;p&gt;逆に、Anthropicが最新モデルや新機能をリリースした瞬間からそれを使いたい組織には、Claude Platform on AWSが勝ります。Bedrockでは、Anthropic本家のAPIで先行した機能(extended thinkingやFiles APIなど)が、AWS側のコモディティ化を経て登場するまで数週間から数か月のラグが生じることも珍しくありませんでした。今回のサービスは、その間隙を埋める性格のものです。&lt;&#x2F;p&gt;
&lt;p&gt;選択軸が「データ境界と機能の速さ、どちらを優先するか」に整理されてきたことが分かります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AIサービスにおけるAWSの役回りの変化&quot;&gt;AIサービスにおけるAWSの役回りの変化&lt;&#x2F;h2&gt;
&lt;p&gt;ここからが本稿の本題です。新サービスを技術仕様として眺める以上に、AWSがどんな役回りを引き受けたのかという視点で見るほうが示唆に富みます。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Platform on AWSが構造的に行っているのは、レイヤーの分離です。推論というサービス本体はAnthropicの外部基盤に置きつつ、認証(IAM)、請求(Marketplace)、監査(CloudTrail)、コミット消化といった企業ガバナンスの足回りだけをAWSが提供しています。&lt;&#x2F;p&gt;
&lt;p&gt;この構造は、Cloudflare Workersに &lt;code&gt;ANTHROPIC_API_KEY&lt;&#x2F;code&gt; を環境変数で渡して、Anthropic本家のAPIを叩いているのと本質的に変わりません。違いは、認証がAPIキーではなくIAMで、請求がクレジットカードではなくAWS請求書で、ログがWorkers TraceではなくCloudTrailであることです。エンタープライズの調達と監査の要件を満たすかどうかという、その一点だけが違います。&lt;&#x2F;p&gt;
&lt;p&gt;ここでAWSが押さえている価値は、コンピュートやストレージではありません。請求と身元と監査ログを束ねる「企業の窓口」としての地位です。AWSはこれまで、Cloud 1.0期に積み上げた抽象化レイヤー、つまりEC2やS3やLambdaといったプリミティブで稼いできました。今回はそれと並行して、自社では運用していない外部の推論サービスの請求と統制を引き受けるという、新しい収益面を開いています。&lt;&#x2F;p&gt;
&lt;p&gt;これは戦略的譲歩なのか、新収益モデルなのか。私の見立ては、両面を同時に成立させる賢い設計、というところです。譲歩の側面はあります。AnthropicのモデルをBedrockに統合してきたこれまでの路線とは異なり、推論基盤の主導権をAnthropic側に残したまま窓口だけ引き受ける形だからです。一方でAWSは、Enterprise Discount Programの消化先を増やせますし、新モデル待ちでAWSを離れる顧客を引き留められます。失う主導権の代わりに、エンタープライズの窓口という地位を補強する取引です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloud_0.5&#x2F;1.0&#x2F;2.0で見るとどこに位置するか&quot;&gt;Cloud 0.5&#x2F;1.0&#x2F;2.0で見るとどこに位置するか&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;cloud2-0&#x2F;&quot;&gt;以前の記事&lt;&#x2F;a&gt;で、Cloudの時代区分を「Cloud 0.5(仮想化インフラ)」「Cloud 1.0(Cloud Native)」「Cloud 2.0(Agentic Cloud)」の3段で整理しました。Claude Platform on AWSはこの枠組みのどこに位置づけられるでしょうか。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;本記事における「Cloud 2.0」の定義: LLMエージェントがCloudのワークロードの主役となる新しいレイヤーを指す、本記事独自の用語として用います。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Cloud 1.0期のハイパースケーラーは、抽象化レイヤーの提供者でした。物理インフラを覆い隠して、IAMやVPCやマネージドサービスといったプリミティブを通じて開発者に売る役割です。AWSがその役割で群を抜いたことが、Cloud 1.0時代の覇権をもたらしました。&lt;&#x2F;p&gt;
&lt;p&gt;Cloud 2.0期に入ると、ワークロードの主役はLLMエージェントになります。エージェントは、推論基盤、軽量実行環境、永続記憶、版管理ストレージといったプリミティブを使い倒します。ここで重要なのは、これらのプリミティブを必ずしも一社で提供する必要はないという点です。エージェントは複数のサービス境界を越えて動きますし、エンタープライズが推論をAnthropicに、実行環境をCloudflareに、ストレージをAWSにというような組み合わせを選ぶことも当たり前になりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;そう考えると、前節で論じたAWSの役回り変化は、Cloud 2.0レイヤー全体に起きている地殻変動の一場面として位置づけられます。Cloud 1.0期に培った企業ガバナンス基盤を、自社で運用しない外部の推論サービスにも貸し出す。これが今、Cloud 2.0レイヤーでハイパースケーラーが取りうる役回りのひとつで、Bedrockを併存させているのは内製と外部窓口の両方をAWSが押さえにいくという意思の表れです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWS提案の現場で起きる変化&quot;&gt;AWS提案の現場で起きる変化&lt;&#x2F;h2&gt;
&lt;p&gt;ここから少し業界寄りの話です。AWSのソリューション提案を生業にしてきた人々への影響を見ておきます。&lt;&#x2F;p&gt;
&lt;p&gt;これまでのBedrock案件では、「Anthropic、OpenAI、Meta、Mistralを統一APIで使い分けられる」というマルチモデル統合の価値が前面に出てきました。データレジデンシーやIAM統合と並んで、Bedrockを選ぶ理由のひとつとして語られてきた論点です。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Platform on AWSの登場は、このうち「Anthropicの最新モデルを使いたい」という需要を、Bedrock以外で吸収できることを意味します。Claudeしか使わないユースケースに対しては、「Bedrockでマルチモデルを集約する」という売り文句の説得力が下がります。同じAWSの中に、Anthropic直叩きと変わらない経路が用意されたからです。&lt;&#x2F;p&gt;
&lt;p&gt;提案のロジックも組み替えが要ります。要件ごとの選択は次のように整理できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;データレジデンシーやAWS境界内処理が契約上の必須要件 → Bedrock&lt;&#x2F;li&gt;
&lt;li&gt;Day-0でClaudeの新機能を使いたい、またはWorkspace単位の請求分離が必要 → Claude Platform on AWS&lt;&#x2F;li&gt;
&lt;li&gt;複数モデルベンダーをユースケース別に使い分けたい → Bedrock&lt;&#x2F;li&gt;
&lt;li&gt;ClaudeとOpenAIの両方を本家経路で使いたい → BedrockとClaude Platform on AWSの併用&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;選択軸が一段細かくなりました。&lt;&#x2F;p&gt;
&lt;p&gt;元AWS ProServeの目で見ると、これは案件の議論を健全にする方向の変化です。Bedrockを「とりあえずの安全牌」として薦める提案には、本来の要件と噛み合わないものが含まれていました。選択肢が増えたことで、データ境界要件か機能の追随速度かを正面から議論できるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;逆に、SI側の付加価値の置き場所は前より難しくなります。「マルチモデル統合のための設計」だけでは差別化が薄まり、業務要件を踏まえてどちらの経路を選ぶか、両者をどう使い分けるかという、より上位の意思決定支援に価値が移っていきます。Cloud 1.0期にインフラ選定で稼いだロジックは、Cloud 2.0期には設計者・選定者の判断力という形に少しずつ姿を変えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Anthropicのキャパシティ戦略との符合&quot;&gt;Anthropicのキャパシティ戦略との符合&lt;&#x2F;h2&gt;
&lt;p&gt;最後に、Anthropic側からこの取引を眺めておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicは2026年に入ってから、AWSと$100Bを超える複数年コンピュート契約を交わし、5GW級のTrainium容量にコミットすると発表しています。一方でMicrosoft AzureやGoogle Cloudとも並行して提携を結んでおり、推論キャパシティを複数のハイパースケーラーに分散させる戦略を取っています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;TrainiumはAWSが自社開発するAI学習・推論用カスタムチップです。Nvidia GPUへの依存を減らす狙いがあり、Anthropicの大型契約はその外販ボリュームの一翼を担います。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;このキャパシティを最終的に消費するのは、世界中のエンタープライズが回す推論ワークロードです。Anthropic本家APIだけでは、その消費を支えるだけの調達経路を企業に提供しきれません。クレジットカードでの直接契約は、ガバナンスの観点でエンタープライズが選びにくい経路だからです。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Platform on AWSは、Anthropicからすれば「エンタープライズの調達窓口」を一気に拡張する装置です。AWSアカウントを持っている企業の調達担当は、新しいベンダーを通すことなく、既存のMarketplace経由でClaudeを使い始められます。Anthropicは推論基盤の主導権を保ったまま、AWSのエンタープライズ顧客基盤に直結できます。&lt;&#x2F;p&gt;
&lt;p&gt;AWS側から見れば、AnthropicがTrainiumに払うコンピュート料金が、別経路でエンタープライズ向けの推論売上として戻ってきます。Anthropicが請求の上流、AWSが下流という関係です。両者は競合ではなく、調達面で組み合っている構造になっています。&lt;&#x2F;p&gt;
&lt;p&gt;ここまで読むと、Claude Platform on AWSは単発のサービス発表というよりも、Anthropicの分散キャパシティ戦略とAWSの窓口ポジション戦略が噛み合った結果として出てきた仕組みであることが見えてきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Platform on AWSは、機能カタログの一行というよりも、ハイパースケーラーの役回りが変わりつつあることを示す構造的なサインだと感じています。&lt;&#x2F;p&gt;
&lt;p&gt;Bedrockがそうであるように、AWSは引き続き「自社の推論基盤を売る側」でもあります。同時に、外部ベンダーの推論サービスに対して「請求と身元と監査の窓口」を引き受ける役割も併せ持つようになりました。Cloud 1.0期に培った企業ガバナンスの足回りが、Cloud 2.0期では別のベンダーの実行レイヤーを支える土台として再利用されています。&lt;&#x2F;p&gt;
&lt;p&gt;エンタープライズの調達担当やSIの提案担当にとっては、選択肢が増えた分だけ判断軸を明確にする必要が出てきます。データ境界要件か、機能の追随速度か、ベンダー多様性か。それぞれの要件に対して、Bedrock、Claude Platform on AWS、あるいは両者の併用という選択を素直に評価できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;今後、同じ仕組みでOpenAIやGoogleがAWS上に乗ってくる可能性も含めて、ハイパースケーラーの窓口化はゆっくりと進む流れだと見ています。Cloud 2.0期にAWSがどの地位を確保するのか、その答えのひとつがこの発表に入っているのではないでしょうか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&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;aws.amazon.com&#x2F;blogs&#x2F;machine-learning&#x2F;introducing-claude-platform-on-aws-anthropics-native-platform-through-your-aws-account&#x2F;&quot;&gt;AWS Machine Learning Blog&lt;&#x2F;a&gt;.「Introducing Claude Platform on AWS, Anthropic&#x27;s native platform through your AWS account」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;claude-platform&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;.「Claude Platform on AWS」(製品ページ)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;about-aws&#x2F;whats-new&#x2F;2026&#x2F;05&#x2F;claude-platform-aws&#x2F;&quot;&gt;AWS What&#x27;s New&lt;&#x2F;a&gt;.「Claude Platform on AWS is now generally available」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;anthropic-amazon-compute&quot;&gt;Anthropic&lt;&#x2F;a&gt;.「Anthropic and Amazon expand collaboration for up to 5GW of Trainium compute」(2026年4月20日)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aboutamazon.com&#x2F;news&#x2F;company-news&#x2F;amazon-invests-additional-5-billion-anthropic-ai&quot;&gt;About Amazon&lt;&#x2F;a&gt;.「Amazon and Anthropic expand strategic collaboration」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
</content>
        <summary type="html">2026年5月11日にGAされたClaude Platform on AWSは、AnthropicのネイティブAPIをAWSアカウントから直接呼べる新サービスです。この発表が示すAWSの立ち位置の構造的な変化を、Bedrockとの違い、Cloud 2.0レイヤー、AWS提案現場の3つの角度から読み解きます。</summary>
        </entry><entry xml:lang="en">
        <title>rcloneとS3ライフサイクルで作る個人データのコールドアーカイブ</title>
        <published>2026-04-30T08:30:42+09:00</published>
        <updated>2026-05-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/rclone/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/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;04&amp;#x2F;rclone&amp;#x2F;cover.webp?h=549d1cce4801beb622f1&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&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;ドローンで撮りためた動画素材がNASの容量を圧迫してきたので、編集後はほとんど触らないものをAmazon S3に退避させる仕組みを作りました。手元から外しはするものの、まとめ直しのときに見返す可能性は残しておきたい、いわばコールドアーカイブの個人運用版です。&lt;&#x2F;p&gt;
&lt;p&gt;自宅はHome 5Gで上りが20〜30Mbpsと細いため、転送には &lt;code&gt;rclone&lt;&#x2F;code&gt; を使い、回線が太い場所にいるかどうかでパラメータを切り替えながらアップロードしています。さらに保管側はS3のライフサイクルで自動的にGlacier Deep Archiveに降格させ、月額数百円のレンジで運用できるようにしています。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、この「転送のチューニング」と「保管の自動化」の二段構えを、AWS側の設定からrcloneのオプション、最後にコスト試算まで通しでまとめます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜAmazon_S3を選んだか&quot;&gt;なぜAmazon S3を選んだか&lt;&#x2F;h2&gt;
&lt;p&gt;「眠らせておく置き場」に求める要件はおおむね以下のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;編集後はほとんどアクセスしないが、過去作をまとめ直すときに見返すことはある&lt;&#x2F;li&gt;
&lt;li&gt;手元のストレージやNASから退避させたい、しかし消したくはない&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;クラウド側の候補としてはDropboxやBoxのようなサブスクリプション型ストレージも挙がりましたが、構造的な違いから最終的にAmazon S3を選びました。観点ごとの比較は以下のとおりです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;料金構造&lt;&#x2F;dt&gt;
&lt;dd&gt;サブスク型は容量プラン単位の月額固定で、使っていない分にも払い続ける必要があります。S3は置いた分・使った分だけの従量課金で、「ほとんど触らないが消したくない」数百GBの素材を保管するだけなら割安に収まります。&lt;&#x2F;dd&gt;
&lt;dt&gt;ストレージクラス&lt;&#x2F;dt&gt;
&lt;dd&gt;サブスク型は内部的にHotストレージのみで、アクセス頻度の低いファイルでも単価は変わりません。S3はStandard &#x2F; Standard-IA &#x2F; Glacier &#x2F; Glacier Deep Archiveと複数階層があり、Deep Archiveまで落とせばStandardより一桁安い単価で保管できます。&lt;&#x2F;dd&gt;
&lt;dt&gt;運用の自動化&lt;&#x2F;dt&gt;
&lt;dd&gt;サブスク型はファイルの整理・移動・削除を手動で行う前提です。S3はライフサイクルで「3日後にDeep Archiveへ降格、2年後に削除」のようなルールを宣言的に書いておけるため、長期保管の管理コストもほぼかかりません。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;ひとつだけ運用上の注意点があります。S3にアップロード後すぐにNASから消してしまうと、S3が事実上の唯一コピーになります。バックアップの基本である3-2-1ルール（コピー3、媒体2、オフサイト1）の観点では、編集が完全に終わった素材であっても、NAS側を一定期間（例: 半年〜1年）残しておくと安全側に倒せます。私はNASの容量に余裕がある間は最近のフライトを残し、容量を圧迫してきたら古いものから順にNAS側を整理する運用にしています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rcloneとは&quot;&gt;rcloneとは&lt;&#x2F;h2&gt;
&lt;p&gt;S3へのアップロードツールとしては&lt;code&gt;rclone&lt;&#x2F;code&gt;を使用しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;rclone&lt;&#x2F;code&gt;は70以上のクラウドストレージに対応する汎用ファイル転送ツールです。S3・Google Drive・Dropbox・OneDrive・SFTP・WebDAVなどを統一的なコマンドで扱えます。rsyncのクラウド版というのが一番近い説明です。&lt;&#x2F;p&gt;
&lt;p&gt;これまではMacのGUIアプリ &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;panic.com&#x2F;transmit&#x2F;&quot;&gt;Transmit&lt;&#x2F;a&gt; や、コマンドラインの &lt;code&gt;s3cmd&lt;&#x2F;code&gt; を使っていました。日常的なファイル転送ではどちらも十分でしたが、今回のように回線が細く中断も起こり得る環境で大量にアップロードする用途では、&lt;code&gt;rclone&lt;&#x2F;code&gt; のほうが明確に向いていました。観点ごとの違いは以下のとおりです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;転送のチューニング&lt;&#x2F;dt&gt;
&lt;dd&gt;TransmitはGUIで直感的に扱える一方、並列度やチャンクサイズなどの細かい調整はできません。&lt;code&gt;s3cmd&lt;&#x2F;code&gt; もマルチスレッド転送や帯域制御は限定的です。&lt;code&gt;rclone&lt;&#x2F;code&gt; は並列度・チャンクサイズ・帯域上限・リトライまで細かく指定でき、細い回線でもスループットを引き出せます。&lt;&#x2F;dd&gt;
&lt;dt&gt;不安定な回線への耐性&lt;&#x2F;dt&gt;
&lt;dd&gt;&lt;code&gt;rclone&lt;&#x2F;code&gt; はETagによるチェックサム比較で同一ファイルの再転送をスキップでき、リトライも「ジョブ全体」と「個別HTTPリクエスト」の2階層で設定できます。中断・再開が前提のアーカイブ運用に向いた作りです。&lt;&#x2F;dd&gt;
&lt;dt&gt;対応バックエンドの広さ&lt;&#x2F;dt&gt;
&lt;dd&gt;&lt;code&gt;s3cmd&lt;&#x2F;code&gt; は名前のとおりS3専用です。&lt;code&gt;rclone&lt;&#x2F;code&gt; はS3以外にも多数のクラウドに同じインターフェースで対応するため、将来別のサービスに移行・併用する場合もコマンド体系を変えずに済みます。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;AWS側の設定&quot;&gt;AWS側の設定&lt;&#x2F;h2&gt;
&lt;p&gt;最初にAWS側で必要な準備を済ませておきます。具体的には、転送に使うIAMユーザーの権限と、保管ルールを定義するS3のライフサイクル設定の2点です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;IAMの権限設定&quot;&gt;IAMの権限設定&lt;&#x2F;h3&gt;
&lt;p&gt;S3バケットへのアクセス権を持つIAMユーザーを作成し、アクセスキーを発行します。ルートアカウントのキーは絶対に使わないでください。最小権限のIAMポリシー例は以下のとおりです（バケット名を &lt;code&gt;video-backup&lt;&#x2F;code&gt; とする場合）。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;iam-policy.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;Version&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;2012-10-17&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Statement&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;    {&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;Effect&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;Allow&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Action&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;s3:ListBucket&amp;quot;&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;quot;s3:GetBucketLocation&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Resource&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;arn:aws:s3:::video-backup&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Effect&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;Allow&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Action&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 z-definition z-string z-string&quot;&gt;        &amp;quot;s3:PutObject&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-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:GetObject&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-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:DeleteObject&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-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:AbortMultipartUpload&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-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:ListMultipartUploadParts&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Resource&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;arn:aws:s3:::video-backup&#x2F;*&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;s3:AbortMultipartUpload&lt;&#x2F;code&gt; はマルチパートアップロード失敗時のクリーンアップに必要です。これがないと中断したアップロードの残骸が課金対象として残り続けてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;ここまでの内容をAWS CLIで適用する手順は以下のとおりです。&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;# IAM ユーザーを作成&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam create-user --user-name rclone-backup&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;# 上記の iam-policy.json からポリシーを作成&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam create-policy&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&quot;&gt;  --policy-name VideoBackupPolicy&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&quot;&gt;  --policy-document file:&#x2F;&#x2F;iam-policy.json&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;ACCOUNT_ID&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sts get-caller-identity --query Account --output text&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-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam attach-user-policy&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&quot;&gt;  --user-name rclone-backup&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&quot;&gt;  --policy-arn arn:aws:iam::&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-source&quot;&gt;${ACCOUNT_ID}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:policy&#x2F;VideoBackupPolicy&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;# アクセスキーを発行（SecretAccessKey は一度しか表示されないので保管すること）&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam create-access-key --user-name rclone-backup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後のコマンドで返ってきた &lt;code&gt;AccessKeyId&lt;&#x2F;code&gt; と &lt;code&gt;SecretAccessKey&lt;&#x2F;code&gt; は、後段の &lt;code&gt;rclone config&lt;&#x2F;code&gt; でそのまま使います。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;S3ライフサイクルルール&quot;&gt;S3ライフサイクルルール&lt;&#x2F;h3&gt;
&lt;p&gt;長期アーカイブ用途では、ストレージクラスを段階的に下げて保管料を抑えたり、中断したマルチパートアップロードの残骸を自動で掃除するルールを入れておくと、安全かつ低コストで運用できます。以下は2つのルールを1ファイルで設定する例です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ルール1: アップロード後3日経過したオブジェクトをGlacier Deep Archiveに移し、2年（730日）後に削除する&lt;&#x2F;li&gt;
&lt;li&gt;ルール2: 7日以上完了していないマルチパートアップロードを中止してパートを削除する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;lifecycle.json&lt;&#x2F;code&gt; を用意します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;lifecycle.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;Rules&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;    {&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;ID&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;ArchiveAfter3DaysExpireAfter2Years&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Status&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;Enabled&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Filter&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;Transitions&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;        {&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;Days&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&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-punctuation&quot;&gt;          &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;StorageClass&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;DEEP_ARCHIVE&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Expiration&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;Days&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 730&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;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;ID&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;AbortIncompleteMultipartUploadAfter7Days&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Status&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;Enabled&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Filter&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;AbortIncompleteMultipartUpload&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;DaysAfterInitiation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 7&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;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;&#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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3api put-bucket-lifecycle-configuration&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&quot;&gt;  --bucket video-backup&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&quot;&gt;  --lifecycle-configuration file:&#x2F;&#x2F;lifecycle.json&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;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3api get-bucket-lifecycle-configuration --bucket video-backup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;設定にあたっての注意点は以下のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Filter: {}&lt;&#x2F;code&gt; はバケット全体が対象という意味。プレフィックスで絞るなら &lt;code&gt;&quot;Filter&quot;: {&quot;Prefix&quot;: &quot;video&#x2F;&quot;}&lt;&#x2F;code&gt; のように書く&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Days&lt;&#x2F;code&gt; はオブジェクトの作成日からの経過日数。ライフサイクルの判定はUTCの00:00に1日1回走るため、設定した翌日にすぐ動くわけではない&lt;&#x2F;li&gt;
&lt;li&gt;Glacier Deep Archiveは最安だが、復元に最大48時間（Bulkなら数時間）かかる。「もう見ない可能性が高いがゼロではない」素材向き&lt;&#x2F;li&gt;
&lt;li&gt;Deep Archiveは最低保管期間が180日。180日未満で削除や移動をすると残り日数分の料金が発生する。今回は作成3日後に移して2年後（DAに約720日滞在）に削除するため、最低保管期間は十分満たす&lt;&#x2F;li&gt;
&lt;li&gt;128KB未満の小さいオブジェクトはDeep Archiveへの移行対象外（移行してもStandardに留まる）。動画用途なら気にしなくて構わないが、混在バケットでは留意しておく&lt;&#x2F;li&gt;
&lt;li&gt;マルチパートアップロード残骸の削除ルールは、IAMポリシーの &lt;code&gt;s3:AbortMultipartUpload&lt;&#x2F;code&gt; とは別に必要。IAMはクライアント側が中止する権限、ライフサイクルはS3側が自動で中止してくれる仕組みなので、両方そろえておくのが望ましい状態&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;rcloneのインストールと設定&quot;&gt;rcloneのインストールと設定&lt;&#x2F;h2&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 rclone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;リモートの設定は &lt;code&gt;rclone config&lt;&#x2F;code&gt; を起動して対話的に進めます。新規リモート作成時に入力していく項目を抜粋すると以下のとおりです（&lt;code&gt;&amp;gt;&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-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; rclone config&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;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) New remote&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;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3-aws&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;Storage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3&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;provider&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; AWS&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;env_auth&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-false&quot;&gt; false&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;access_key_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; AKIA...&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;secret_access_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&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;region&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ap-northeast-1&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;endpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     （空欄でOK）&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;location_constraint&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ap-northeast-1&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;acl&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; private&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;storage_class&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; STANDARD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;設定ファイルは &lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;rclone.conf&lt;&#x2F;code&gt; に&lt;strong&gt;平文&lt;&#x2F;strong&gt;で保存されます。共用マシンでは取り扱いに注意してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rcloneの推奨パラメータ&quot;&gt;rcloneの推奨パラメータ&lt;&#x2F;h2&gt;
&lt;p&gt;自宅のHome 5G（上り20〜30Mbps）想定での起動例は以下のとおりです。&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;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&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&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&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&quot;&gt;  --s3-chunk-size 64M&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&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&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&quot;&gt;  --s3-no-check-bucket&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&quot;&gt;  --checksum&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&quot;&gt;  --progress&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&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&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&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&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&quot;&gt;  --log-file=rclone-&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;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&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&quot;&gt;  --log-level INFO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;S3では1ファイル内の並列度は &lt;code&gt;--s3-upload-concurrency&lt;&#x2F;code&gt; が直接コントロールするため、&lt;code&gt;--multi-thread-streams&lt;&#x2F;code&gt; は併用しません。両方指定しても効果が二重に効くわけではなく、メモリ使用量だけが増えてしまうので、&lt;strong&gt;S3 バックエンドでは &lt;code&gt;--s3-upload-concurrency&lt;&#x2F;code&gt; に一本化&lt;&#x2F;strong&gt; します。回線が太い環境（オフィス・コワーキングスペース等で上り100Mbps以上）では &lt;code&gt;--transfers 4&lt;&#x2F;code&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;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;--transfers&lt;&#x2F;td&gt;&lt;td&gt;1〜2（細回線）&#x2F; 4（太回線）&lt;&#x2F;td&gt;&lt;td&gt;同時に転送するファイル数。Home 5G のような上り20〜30Mbps の環境では 1〜2 のほうがファイルの完了が早く、リトライ時の損失も小さい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--s3-chunk-size&lt;&#x2F;td&gt;&lt;td&gt;64M&lt;&#x2F;td&gt;&lt;td&gt;マルチパートアップロードの1パートのサイズ。デフォルト 5M を動画用途では 64M〜128M に。メモリ使用量が &lt;code&gt;chunk_size × upload_concurrency × transfers&lt;&#x2F;code&gt; で増える点に注意&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--s3-upload-concurrency&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;1ファイル内で同時にアップロードするパート数&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--s3-no-check-bucket&lt;&#x2F;td&gt;&lt;td&gt;有効&lt;&#x2F;td&gt;&lt;td&gt;バケット存在チェックをスキップ。最小権限 IAM ではデフォルトのままだと起動時のチェックがエラーになることがある&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--checksum&lt;&#x2F;td&gt;&lt;td&gt;有効&lt;&#x2F;td&gt;&lt;td&gt;ETag 比較で同一ファイルの再転送をスキップ。サイズと更新時刻だけのデフォルトより確実&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--retries&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;ジョブ全体のリトライ回数&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--low-level-retries&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;個別 HTTP リクエストのリトライ回数&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--progress (-P)&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;--log-file&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;rclone-$(date +%Y%m%d-%H%M%S).log&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ログをファイルに残しておくとエラー追跡や再開判断に役立つ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--log-level&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;INFO&lt;&#x2F;code&gt;（デバッグ時 &lt;code&gt;DEBUG&lt;&#x2F;code&gt;）&lt;&#x2F;td&gt;&lt;td&gt;ログレベル&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--bwlimit&lt;&#x2F;td&gt;&lt;td&gt;状況に応じて&lt;&#x2F;td&gt;&lt;td&gt;上限を制限（例: &lt;code&gt;10M&lt;&#x2F;code&gt;）。&lt;code&gt;--bwlimit &quot;08:00,512k 18:00,off&quot;&lt;&#x2F;code&gt; のように時刻指定で時間帯ごとに切り替えも可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ライフサイクルでDeep Archiveに降格したオブジェクトに対して、&lt;code&gt;rclone copy&lt;&#x2F;code&gt; で同名ファイルを再アップロードしようとすると、内部で実行されるGET（既存ファイルとのチェックサム比較）がDeep Archiveオブジェクトに対しては失敗します。同じパスに同名ファイルを再投入する用途がある場合は、&lt;code&gt;--immutable&lt;&#x2F;code&gt;（同名ファイルが既に存在したら転送をスキップしてエラーにしない）か &lt;code&gt;--no-traverse&lt;&#x2F;code&gt;（既存ファイルとの比較をしない）を併用するか、そもそも保存先のキー命名でタイムスタンプを含めて衝突を避けます。今回の動画アーカイブのようにファイル名がフライト日時で一意な場合は、特別な対策は不要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macで中断させない方法&quot;&gt;macで中断させない方法&lt;&#x2F;h2&gt;
&lt;p&gt;長時間の転送中にmacOSがスリープに入ると転送が止まります。&lt;code&gt;caffeinate&lt;&#x2F;code&gt; を使ってシステムスリープを抑止しながら実行します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;&lt;code&gt;caffeinate&lt;&#x2F;code&gt; は macOS に標準で含まれるコマンドです。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&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;caffeinate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -i rclone copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&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&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&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&quot;&gt;  --s3-chunk-size 64M&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&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&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&quot;&gt;  --s3-no-check-bucket&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&quot;&gt;  --checksum&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&quot;&gt;  --progress&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&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&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&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&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&quot;&gt;  --log-file=rclone-&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;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&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&quot;&gt;  --log-level INFO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;主なオプションは以下のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;&#x2F;code&gt; システムのアイドルスリープを防止（プロセスが終わるまで有効）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;&#x2F;code&gt; ディスプレイのスリープも防止（不要なら省略）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;&#x2F;code&gt; AC電源接続時のみスリープ防止&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-u -t 3600&lt;&#x2F;code&gt; 指定秒数だけスリープ防止（プロセスを伴わない用途）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;caffeinate&lt;&#x2F;code&gt; を前置すると、そのコマンドが終了するまで自動でスリープ抑止が解除されます。バックグラウンドで動かす場合は &lt;code&gt;nohup caffeinate -i rclone copy ... &amp;amp;&lt;&#x2F;code&gt; のようにすれば、ターミナルを閉じても継続します（ログは &lt;code&gt;--log-file&lt;&#x2F;code&gt; に必ず残しておきます）。&lt;&#x2F;p&gt;
&lt;p&gt;蓋を閉じてもスリープさせたくない場合は &lt;code&gt;caffeinate&lt;&#x2F;code&gt; だけでは不十分なことがあるので、事前に以下を実行しておくか、別途 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;apps.apple.com&#x2F;app&#x2F;amphetamine&#x2F;id937984704&quot;&gt;Amphetamine&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;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pmset -a disablesleep&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 z-definition z-comment z-comment&quot;&gt;   # 蓋を閉じてもスリープしない（作業後は0に戻す）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;認証情報の管理を1Password_CLIに移す（2026-05-05更新）&quot;&gt;認証情報の管理を1Password CLIに移す（2026-05-05更新）&lt;&#x2F;h2&gt;
&lt;p&gt;ここまでの設定では &lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;rclone.conf&lt;&#x2F;code&gt; にAWSのアクセスキーが平文で残ります。dotfilesで同期したり共用マシンに置く運用では避けたいので、認証情報を &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.1password.com&#x2F;docs&#x2F;cli&#x2F;&quot;&gt;1Password CLI&lt;&#x2F;a&gt; (&lt;code&gt;op&lt;&#x2F;code&gt;) に移し、&lt;code&gt;op run&lt;&#x2F;code&gt; で実行時に環境変数として注入する構成も用意しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;rclone.conf&lt;&#x2F;code&gt; 側はキーを書かず、&lt;code&gt;env_auth = true&lt;&#x2F;code&gt; にしてAWS標準の認証情報チェーン（環境変数→&lt;code&gt;~&#x2F;.aws&#x2F;credentials&lt;&#x2F;code&gt;→IAMロール）から都度取得する動作に変えます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot; data-name=&quot;~&#x2F;.config&#x2F;rclone&#x2F;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-entity z-name z-section z-group-title z-ini&quot;&gt;s3-aws&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-other z-definition z-ini&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; s3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;provider&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; AWS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;env_auth&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; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;region&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; ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;location_constraint&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; ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;acl&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; private&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;storage_class&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; STANDARD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;発行済みのキーは1Passwordに保管します。&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;op&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; item create --category=&amp;quot;API Credential&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&quot;&gt;  --vault=Private&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;  --title=&amp;quot;rclone-backup-aws&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;  username=&amp;quot;AKIA...&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;  credential=&amp;quot;...&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;参照用のenvテンプレートを &lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&lt;&#x2F;code&gt; として配置します。&lt;code&gt;rclone.conf&lt;&#x2F;code&gt; と同じディレクトリで管理でき、値ではなく &lt;code&gt;op:&#x2F;&#x2F;...&lt;&#x2F;code&gt; の参照しか書かれないため、dotfilesに含めて同期しても問題ありません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;~&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;AWS_ACCESS_KEY_ID&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;op:&#x2F;&#x2F;Private&#x2F;rclone-backup-aws&#x2F;username&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;AWS_SECRET_ACCESS_KEY&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;op:&#x2F;&#x2F;Private&#x2F;rclone-backup-aws&#x2F;credential&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;実行時は &lt;code&gt;op run --env-file&lt;&#x2F;code&gt; でラップし、&lt;code&gt;op&lt;&#x2F;code&gt; が1Passwordから値を取り出して環境変数として注入します。先述の起動例は以下のように書き換わります。&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;op&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; run --env-file=&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&amp;quot; -- rclone copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&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&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&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&quot;&gt;  --s3-chunk-size 64M&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&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&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&quot;&gt;  --s3-no-check-bucket&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&quot;&gt;  --checksum&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&quot;&gt;  --progress&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&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&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&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&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&quot;&gt;  --log-file=rclone-&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;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&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&quot;&gt;  --log-level INFO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;caffeinate&lt;&#x2F;code&gt; と組み合わせる場合は、&lt;code&gt;caffeinate&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-entity z-name z-function&quot;&gt;caffeinate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -i op run --env-file=&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&amp;quot; -- rclone copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&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&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&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&quot;&gt;  --s3-chunk-size 64M&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&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&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&quot;&gt;  --s3-no-check-bucket&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&quot;&gt;  --checksum&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&quot;&gt;  --progress&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&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&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&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&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&quot;&gt;  --log-file=rclone-&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;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&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&quot;&gt;  --log-level INFO&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;rcloneのチューニングとS3のライフサイクルを組み合わせて、個人データのコールドアーカイブを構築する構成をまとめました。回線の細さに左右されず転送を完了させ、長期保管のコストはストレージクラスの自動降格で抑える、という二段構えです。&lt;&#x2F;p&gt;
&lt;p&gt;参考として、私の運用パターン（月3フライト × 1回20GB = 月60GB）で運用した場合の年度ごとの料金見積もりは以下のようになります。3日後にGlacier Deep Archiveへ降格、2年で削除するライフサイクルを前提としています。NASにローカルコピーを保持しているため、S3のStandard滞在は最小限に切り詰めています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;左記は保管料のみ。取り出す場合には別途料金が発生します。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&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;
    xychart-beta
title &quot;年度ごとのS3保管料金（千円）&quot;
x-axis [&quot;1年目&quot;, &quot;2年目&quot;, &quot;3年目&quot;, &quot;4年目&quot;, &quot;5年目&quot;]
y-axis &quot;料金（千円）&quot; 0 --&gt; 7
bar [1.6, 4.2, 5.5, 5.5, 5.5]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;1〜2年目はDeep Archive側に毎年720GBずつ積み上がるため線形に増加し、3年目以降は毎月のアップロード分と削除分が釣り合って定常状態に入り、年額 ¥5,500程度・累積保管量約1.5TBで頭打ちになります。月額換算すると ¥460程度で、Standard滞在を3日に切り詰めることで、料金のほぼ全てがDeep Archiveの単価で支配される構成です。料金は1ドル=¥150換算、AWSの公開価格（ap-northeast-1、執筆時点）に基づく概算なので、実費は為替・価格改定・取り出し料金で変動します。&lt;&#x2F;p&gt;
&lt;p&gt;この設計の枠組みは、データ特性に合わせて他の用途にも応用できます。私は同じS3アカウントでLogic Proの楽曲プロジェクト（月4曲、1曲500MB）も管理しており、こちらは「再編集の可能性が長く残る」という性質に合わせて、Standard滞在を1年・削除を10年に設定しています。&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;Std→DA&lt;&#x2F;th&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;60 GB&lt;&#x2F;td&gt;&lt;td&gt;3日&lt;&#x2F;td&gt;&lt;td&gt;2年&lt;&#x2F;td&gt;&lt;td&gt;¥5,500&lt;&#x2F;td&gt;&lt;td&gt;1.5 TB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;楽曲プロジェクト&lt;&#x2F;td&gt;&lt;td&gt;2 GB&lt;&#x2F;td&gt;&lt;td&gt;1年&lt;&#x2F;td&gt;&lt;td&gt;10年&lt;&#x2F;td&gt;&lt;td&gt;¥1,900&lt;&#x2F;td&gt;&lt;td&gt;240 GB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;両方合算しても月額 ¥620程度、合計約1.7TBです。データの性格に応じてライフサイクルを分ければ、同じ仕組みで複数の用途を最適化できます。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ドローンの動画素材やLogic Proの楽曲データなど、編集後はほとんど触らないが消したくないデータの「眠らせ場所」を、Amazon S3とrcloneで構築した記録です。細回線でも止まらない転送のチューニングから、Glacier Deep Archiveを使った長期保管のコスト設計まで、二段構えでまとめました。
</summary>
        </entry><entry xml:lang="en">
        <title>Cloudflare Agents Week 2026が告げるCloud 2.0時代: エンタープライズの主戦場が移る</title>
        <published>2026-04-27T07:00:13+09:00</published>
        <updated>2026-04-27T07:00:13+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/cloud2-0/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/cloud2-0/</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;04&amp;#x2F;cloud2-0&amp;#x2F;cover.webp?h=aa99350328ab1f917f77&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Cloudflareは2026年4月13日〜17日に「Agents Week 2026」を開催して、10個以上の新機能を一気に発表しました。新機能の多くが、LLMエージェント(Claude Codeのような「目的を与えられたら、自律的に考え道具を使いタスクを完遂するLLMを使った仕組み」)に関連したものです。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflareがエージェント向けプラットフォームのロードマップを一気に開示しきった印象的な5日間でした。&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;Cloud_2.0の時代&quot;&gt;Cloud 2.0の時代&lt;&#x2F;h2&gt;
&lt;p&gt;今回の発表をまとめて眺めると、Cloudの変遷は次のように整理できます。「Cloud x.0」という言い回しが使い古されているのは承知の上で、それでも今回の地殻変動を端的に表すのに「Cloud 2.0」はちょうど良い言葉だと感じています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;本記事における「Cloud 2.0」の定義: LLMエージェントがCloudのワークロードの主役となる新しいレイヤーを指す、本記事独自の用語として用います。過去に同じ表記が別の意味で使われてきた経緯がありますが、本記事の主張とは無関係です。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;世代&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;呼称&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;本質的な役割&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;操作主体 (Who)&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;主な関心事・技術&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud 0.5&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;仮想化インフラ&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;「場所」の移動&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;インフラ担当者 (手動)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;リフト＆シフト、VM、データセンターの仮想化&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud 1.0&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud Native&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;「構造」の最適化&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;開発者 (コード&#x2F;API)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;マネージドサービス、K8s、サーバレス、IaC&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud 2.0&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Agentic Cloud&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;「意思」の自律化&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;AIエージェント&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;自律的な推論、長期記憶、Tool Use、動的リソース制御&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;3つの世代を「場所→構造→意思」の流れで並べると、世代が進むごとに操作主体が一段上のレイヤーへ移っていくことが見えてきます。Cloud 0.5でインフラ担当者がVMを操作し、Cloud 1.0で開発者がAPIやIaC越しにマネージドサービスを操作してきたところに、Cloud 2.0ではLLMエージェント自身がインフラを叩く側に立ちます。今のエンタープライズが向き合っているのは、「LLMエージェントをいかに効率よく稼働させるか」を中心に据えた新しいITインフラストラクチャーの設計です。&lt;&#x2F;p&gt;
&lt;p&gt;ひとつ前提を強調しておきます。Cloud 2.0はCloud 1.0を置き換えるものではありません。銀行の勘定系、ECのバックエンド、SaaSの基盤といった既存のワークロードは、引き続きCloud 1.0のプリミティブの上で動き続けます。Cloud 2.0はその上に積み上がる新しいレイヤーとして立ち上がり、エージェントが必要に応じて下のCloud 1.0のアプリを呼び出すこともある、という関係です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;LLMエージェントとは&quot;&gt;LLMエージェントとは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;LLMエージェントとは、目的を与えられたら自分で考え道具を使いタスクを完遂するLLMを用いた仕組み&lt;&#x2F;strong&gt;です。聞かれたことに答えるだけのチャットボットと違い、ゴールに向かって自分で手を動かしていきます。具体的にはAnthropicのClaude CodeやClaude Coworkのようなサービスです。&lt;&#x2F;p&gt;
&lt;p&gt;より正確に整理すると、エージェントは主に以下の4つの要素で構成されるシステムと定義されることが多いです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;脳 (Brain &#x2F; Planning)&lt;&#x2F;dt&gt;
&lt;dd&gt;LLM本体です。与えられた大きな目標を、実行可能な小さなステップ(サブタスク)に分解します。過去の失敗から学び、計画を修正する能力もここに含まれます。&lt;&#x2F;dd&gt;
&lt;dt&gt;記憶 (Memory)&lt;&#x2F;dt&gt;
&lt;dd&gt;会話の文脈や現在の作業手順を保持する短期記憶と、外部データベース(RAGなど)を活用して膨大な情報を必要に応じて取り出す長期記憶の二段構えです。&lt;&#x2F;dd&gt;
&lt;dt&gt;道具の使用 (Tool Use &#x2F; Action)&lt;&#x2F;dt&gt;
&lt;dd&gt;エージェントの大きな特徴です。LLMはテキストを生成するだけでなく、Web検索で最新情報を取得し、コード実行で計算やデータ分析を行ない、API連携でメール送信・カレンダー予約・ファイル操作といった外部ツールを呼び出します。&lt;&#x2F;dd&gt;
&lt;dt&gt;認識と判断 (Perception &amp; Reflection)&lt;&#x2F;dt&gt;
&lt;dd&gt;実行した結果が正しかったか、目標に近づいているかを自己評価し、次の行動を決定します。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;この4要素は、計画→実行→評価のループを回しながら、共通の記憶を参照・更新する形で連動します。&lt;&#x2F;p&gt;
&lt;p&gt;ChatGPTをはじめとするLLMが登場したとき、企業はいかにこれを業務システム(アプリケーション)に取り込むかを検討しました。RAGによる社内ナレッジ検索、お問い合わせの自動応答、議事録の要約など、LLMをアプリケーションの中の一機能として組み込む方向です。&lt;&#x2F;p&gt;
&lt;p&gt;しかしその方向での検討は正しい解ではありませんでした。LLMがアプリケーションを含めたさまざまな道具を使い、人間に成り代わって判断しながら業務を行なう。そういう世界が見えてきたのです。LLMを部品として埋め込む構図から、LLMが部品を使う側に立つ構図への反転です。&lt;&#x2F;p&gt;
&lt;p&gt;この転換の背景には、Anthropicが2024年11月に公開したMCP (Model Context Protocol) で得られた「LLMを外と繋げば爆発的に生産性が上がる」という体験があります。Claude Codeはこの延長線上で、もっとカジュアルにLLMに外の道具を使わせればMCPより更に効果的であるということを実証してみせました。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、既存の業務システムは無くなりません。LLMエージェントから利用される対象になります。アプリケーションは引き続きそこに存在しますが、操作する主体が人間からエージェントに移る、という関係です。前節の表で操作主体をAIエージェントに置いたのは、まさにこの転換を指しています。&lt;&#x2F;p&gt;
&lt;p&gt;使われ方の面でも構造が変わります。Cloud 1.0までのアプリケーションは「1つのアプリが多数のユーザを捌く」one-to-manyの前提で設計されてきました。コードは共通で、水平スケールでスループットを上げ、コストはユーザ数に対してサブリニアに伸びる構造です。エージェントはこれを反転させ、1ユーザ(あるいは1タスク)に対して専用の実行環境を割り当てるone-to-oneのモデルになります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;軸&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cloud 1.0 アプリ&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;LLMエージェント&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;実行モデル&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;one-to-many&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;one-to-one&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ユーザ間で共有&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ユーザごとに専用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;コスト構造&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;サブリニア&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ほぼリニア&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;この「1ユーザに専用環境」という前提が、次節で見るインフラ要件の起点になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloud_2.0で必要なインフラ機能&quot;&gt;Cloud 2.0で必要なインフラ機能&lt;&#x2F;h2&gt;
&lt;p&gt;前節で整理したLLMエージェントの4要素と、ユーザ1人に1つの実行環境を割り当てるone-to-oneのモデル。この2つを起点にすると、Cloud 2.0レイヤーが要求するインフラ機能は素直に導けます。&lt;&#x2F;p&gt;
&lt;p&gt;エージェントが実行時に取る活動を一段ずつ分解していくと、それぞれに対応するインフラ機能が見えてきます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;エージェントの活動&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;求められるインフラ機能&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;LLMの推論を回し続ける(脳・認識)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;複数モデルを切り替えられる統合推論レイヤー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AIが書いたコードを安全に走らせる(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ミリ秒で立ち上がる軽量実行環境&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;長尺タスクやコーディング作業を進める(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続的なフル機能Linux環境&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;社内DBや業務APIに到達する(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位のプライベートネットワーク&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Webアプリを操作する(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;マネージドなブラウザ自動化&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;大量のコードを生成・分岐・統合する(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Git互換の版管理ストレージ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;状態と過去のやり取りを保持する(記憶)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;コンテキスト外で保持できる永続記憶レイヤー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ここで効いてくるのがone-to-oneのモデルです。1ユーザに1つの専用実行環境を割り当てるため、表に並べた各機能は「同時に大量に立ち上げ、短時間で捨てる」パターンに耐える必要があります。Cloudflareがブログ「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;welcome-to-agents-week&#x2F;&quot;&gt;Welcome to Agents Week&lt;&#x2F;a&gt;」で示した試算が分かりやすい例です。米国だけで1億人を超えるナレッジワーカーがそれぞれ数個のエージェントを15%の同時実行率で動かすと、同時セッション数は約2400万、CPU 1基あたり25〜50ユーザを想定すると米国分だけで50万〜100万CPU相当の容量が必要になる、という見積もりです。one-to-many前提の最適化のままでは、この規模には到底届きません。&lt;&#x2F;p&gt;
&lt;p&gt;つまりCloud 2.0レイヤーで必要なのは、上の表に並べたプリミティブを、one-to-oneでも破綻しないコスト構造で提供できるインフラです。次節では、このレイヤーで誰がどう動いているかを見ていきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloud_2.0で変わる力関係&quot;&gt;Cloud 2.0で変わる力関係&lt;&#x2F;h2&gt;
&lt;p&gt;CloudflareはAgents Week 2026の発表で、前節で挙げたCloud 2.0要件のすべてに対応するサービスを揃えました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;要件(前節の表)&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cloudflareサービス&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Agents Weekでの発表&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合推論レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AI Gateway&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;拡張(14社・70モデル、Workers AIバインディング追加)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;軽量実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Dynamic Workers&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;今回発表の目玉。2026年3月24日に有料ユーザーへopen beta開放&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続Linux環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Sandboxes&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;GA昇格(active CPU pricing、Outbound Workers等を追加)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位プライベートネットワーク&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Cloudflare Mesh&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;新規発表&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;ブラウザ自動化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Browser Run&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;旧Browser Renderingを改名。Live View等を追加&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;版管理ストレージ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Artifacts&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;新規ローンチ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続記憶レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Agent Memory&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;プライベートベータ発表&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;7要件すべてが新規発表・GA昇格・拡張のいずれかに該当します。Agents Week 2026は、Cloudflareがこのレイヤーへの準備を一気に完了させたイベントとして位置づけられます。&lt;&#x2F;p&gt;
&lt;p&gt;次に、Cloud 1.0を制覇した3強(AWS、Google Cloud、Microsoft Azure)にCloudflareを加えて、同じ7要件のものさしで判定します。判定の3条件は次のとおりです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;GA: 一般提供されており、誰でも利用できる(プライベートベータや「未公開」は除外)&lt;&#x2F;li&gt;
&lt;li&gt;エージェント特化: 汎用クラウドサービスの流用ではなく、エージェント向けに設計されている&lt;&#x2F;li&gt;
&lt;li&gt;統合プラットフォーム配下: 各社の「エージェントクラウド」ブランドや統合プラットフォームの一部として提供されている&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;3条件すべてを満たせば○、preview&#x2F;beta段階なら△、該当サービスなし・汎用流用・受付終了なら×、と判定します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;要件&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Cloudflare&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Google Cloud&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Microsoft Azure&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;AWS&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合推論レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;軽量実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続Linux環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位プライベートネットワーク&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;ブラウザ自動化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;版管理ストレージ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続記憶レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;判定の根拠とした各社のエージェント特化プラットフォーム&#x2F;主要サービスは次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;要件&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cloudflare&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Google Cloud&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Microsoft Azure&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;AWS&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合推論レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AI Gateway&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Model Garden&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure AI Foundry Models&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Amazon Bedrock&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;軽量実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Dynamic Workers&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Cloud Run &#x2F; Vertex AI Agent Engine&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure Container Apps&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Runtime&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続Linux環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Sandboxes&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Code Interpreter&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure Container Apps&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Code Interpreter&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位プライベートネットワーク&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Cloudflare Mesh&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;VPC + Vertex AI Agent Engine&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure Private Link + AI Search&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(PrivateLink等の汎用流用)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;ブラウザ自動化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Browser Run&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Browser Tool&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(エージェント特化サービス未確認)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Browser&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;版管理ストレージ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Artifacts&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(該当サービス未確認)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(該当サービス未確認)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(該当サービス未確認)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続記憶レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Agent Memory&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Agent Engine Memory Bank&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure AI Foundry Memory&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Memory&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;7要件のものさしで眺めると、Google Cloudはエージェント特化のサービスを最も成熟させています。CloudflareはAgents Week 2026で全領域を埋め、×は出していません。Microsoft Azureはエージェント特化の統合プラットフォームとしてはpreview段階のサービスが多い印象です。AWSはBedrock AgentCoreファミリー(Runtime &#x2F; Memory &#x2F; Code Interpreter &#x2F; Browser &#x2F; Gateway &#x2F; Identity &#x2F; Policy &#x2F; Evaluations &#x2F; Observability)でレイヤー横断のサービスを揃えています。特に2026年4月にAgentCore BrowserがOS-levelアクションを追加したことで、ブラウザ自動化は他社と並ぶ水準に到達しています。一方で、エージェント単位のプライベートネットワークとGit互換の版管理ストレージという2領域では、AgentCoreファミリーに対応するプリミティブが現時点で確認できません。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflareがone-to-one前提の課金モデル(Dynamic Workersのper-load課金、Sandboxesのactive CPU pricing)とisolateベースのms起動を統合的に提供しているのに対し、AWSはAgentCore側で個別プリミティブを揃える方向で追いついている段階です。Cloud 1.0期に確立した汎用プリミティブ(EC2、Lambda、VPC、IAM)はone-to-many前提で設計されていたため、one-to-oneのワークロードに対しては個別最適の積み上げで対応している、と位置づけられます。&lt;&#x2F;p&gt;
&lt;p&gt;Cloud 1.0時代、CDNとセキュリティのベンダーとして3強の外側に置かれていたCloudflareが、Cloud 2.0レイヤーでは3強と肩を並べる側へ上がってきました。Cloud 1.0はAWSが制覇したレイヤーでしたが、Cloud 2.0ではプレイヤーの力関係がリセットされるステージです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;主戦場は業務リエンジニアリングへ&quot;&gt;主戦場は業務リエンジニアリングへ&lt;&#x2F;h2&gt;
&lt;p&gt;エンタープライズはCloud 1.0の世界を捨てる必要はありません。基幹システムやSaaSバックエンドはAWS中心の運用を続ければよく、その領域でのインフラ・アーキテクチャの設計力はこれからも継続して必要です。&lt;&#x2F;p&gt;
&lt;p&gt;ただしCloud 2.0レイヤーは別の判断軸で組む必要があります。Cloud 1.0期に確立したベンダー選定の前提がそのままでは通じないからです。前節で見たとおり、Cloud 2.0ではGCPが先行、Cloudflareが追いつき、AzureとAWSは個別サービスを揃えつつも統合プラットフォームとしては道半ばです。「Cloud 1.0と同じベンダーで揃える」という発想を出発点にすると、コスト構造とプリミティブの噛み合わせで不利な選択を踏みやすくなります。&lt;&#x2F;p&gt;
&lt;p&gt;そしてCloud 2.0レイヤーで主戦場になるのは、インフラ・アーキテクチャではありません。プラットフォーム側がプリミティブを統合提供している以上、何をどう組み合わせるかが大きな差別化要因にはなりません。&lt;&#x2F;p&gt;
&lt;p&gt;ここで主戦場となるのは、業務プロセスをエージェント向けに再設計し、エージェントのスキルとして実装できる人材です。Cloud 1.0時代に「AWS特化のインフラ設計者」が握っていた価値の中心は、Cloud 2.0では「業務とエージェントの間を設計できる人」に移ります。&lt;&#x2F;p&gt;
&lt;p&gt;エンタープライズが今着手すべきは、エージェントが代替・補強できる業務プロセスの棚卸しと、それをエージェントに落とし込むケイパビリティの社内構築です。Cloud 2.0プラットフォームの選定は、その準備の一部であって目的ではありません。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&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;blog.cloudflare.com&#x2F;welcome-to-agents-week&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Welcome to Agents Week」(米国ナレッジワーカー試算の出典)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;agents-week-in-review&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Building the agentic cloud — Agents Week in Review」(発表総まとめ)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;changelog&#x2F;post&#x2F;2026-03-24-dynamic-workers-open-beta&#x2F;&quot;&gt;Cloudflare Developers&lt;&#x2F;a&gt;.「Dynamic Workers open beta」(2026年3月24日open beta開放)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;sandbox-ga&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Agents have their own computers with Sandboxes GA」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;browser-run-for-ai-agents&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Browser Run for AI Agents」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;introducing-agent-memory&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Introducing Agent Memory」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;press&#x2F;press-releases&#x2F;2026&#x2F;cloudflare-launches-mesh-to-secure-the-ai-agent-lifecycle&#x2F;&quot;&gt;Cloudflare Press&lt;&#x2F;a&gt;.「Cloudflare Launches Mesh」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;model-context-protocol&quot;&gt;Anthropic&lt;&#x2F;a&gt;.「Model Context Protocol」(2024年11月公開)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;bedrock&#x2F;agentcore&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;.「Amazon Bedrock AgentCore」(Runtime &#x2F; Memory &#x2F; Code Interpreter &#x2F; Browser &#x2F; Gateway &#x2F; Identity &#x2F; Policy &#x2F; Evaluations &#x2F; Observability)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;about-aws&#x2F;whats-new&#x2F;2026&#x2F;04&#x2F;agentcore-browser-os-actions&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;.「AgentCore Browser adds OS-level interactions」(2026年4月8日)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
</content>
        <summary type="html">Cloudflareが2026年4月に開催した「Agents Week 2026」では、Cloud 2.0時代の到来が見えてきました。Cloud 1.0で築いた優位がCloud 2.0レイヤーには引き継がれない構造と、エンタープライズが向き合う変化を考えます。
</summary>
        </entry><entry xml:lang="en">
        <title>個人視点で見るAWSのAIサービスの10年</title>
        <published>2026-04-22T10:20:00+09:00</published>
        <updated>2026-04-22T10:20:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/aws-ai-twilight/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/aws-ai-twilight/</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;04&amp;#x2F;aws-ai-twilight&amp;#x2F;cover.webp?h=f94bf393c7b53cec294a&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&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;かつてAWSのAIは、IAMキー1本と数行のコードで遊べる個人開発者の場所でした。LLM時代の2026年、そこで何が起きたのかを個人の視点から辿ります。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;AWSのAIサービスが革新的だった頃&quot;&gt;AWSのAIサービスが革新的だった頃&lt;&#x2F;h2&gt;
&lt;p&gt;2018年頃の話です。当時、商用AIの旗手とされていたIBM Watsonは、私が直接触れた範囲では期待を裏切る場面が多く、宣伝の勢いと現場感覚のズレが徐々に目立ち始めていた頃でした。&lt;&#x2F;p&gt;
&lt;p&gt;一方、2015年にGoogleが公開したTensorFlowは急速に普及し、「大量のデータを用意して学習させれば、自分の問題を解けるモデルがそのうち作れる」という楽観論も開発者側で盛り上がっていました。ただ、データ収集、アノテーション、訓練用のGPU確保、学習済みモデルのホスティング。どれも個人で完走するには重く、絵に描いた餅で終わることも多かったのが実情です。&lt;&#x2F;p&gt;
&lt;p&gt;そんな中で登場したAWSのAIサービス群は、本当に革新的でした。データを集める必要も、モデルを訓練する必要も、推論用のサーバーを用意する必要もありません。IAMキーと数行のコードさえあれば、訓練済みモデルをAPIとして叩ける。自前の機械学習パイプラインを丸ごとスキップできる衝撃は、今振り返っても大きかったと思います。&lt;&#x2F;p&gt;
&lt;p&gt;翻訳で言えば、DeepLのPro APIが登場したばかりで、Google翻訳APIは法人契約の印象が強く、個人が気軽に叩けるクラウド翻訳APIはAmazon Translateくらいしかありませんでした。&lt;code&gt;curl&lt;&#x2F;code&gt;で一発叩くだけでなく、ちょっとしたCLIツールを自作することも多く、その一例として、私自身もIBM時代にAmazon Translateをバックエンドに採用した社内向けラッパーツールを書いたことがあります。このツールはWord・Excel・PowerPointのファイルを日英相互翻訳していました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;個人ユーザーにはLLMで十分な時代&quot;&gt;個人ユーザーにはLLMで十分な時代&lt;&#x2F;h2&gt;
&lt;p&gt;かつてのAWSには、機械学習をブラックボックスのまま呼び出せるAPI群がきれいに揃っていました。翻訳はTranslate、画像解析はRekognition、自然言語処理はComprehend、帳票はTextract、音声合成はPolly。自前で学習データを集める必要はなく、IAMキーと数行のコードさえあれば機能を呼び出せました。この「気軽さ」こそが、当時の個人開発者にとっての魅力でした。&lt;&#x2F;p&gt;
&lt;p&gt;ところが今、同じ機能の大半はLLMに直接投げれば済むようになりました。&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;LLM時代の代替&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Amazon Translate&lt;&#x2F;td&gt;&lt;td&gt;ニューラル機械翻訳API（多言語対応）&lt;&#x2F;td&gt;&lt;td&gt;GPT&#x2F;Claude&#x2F;Geminiに訳文を直接依頼。DeepL Pro APIも成熟&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Rekognition&lt;&#x2F;td&gt;&lt;td&gt;画像・動画解析（物体検出、顔認識、モデレーション、テキスト検出）&lt;&#x2F;td&gt;&lt;td&gt;ビジョン対応LLM（GPT-4o、Claude、Gemini）に画像を渡して記述や抽出を頼む&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Comprehend&lt;&#x2F;td&gt;&lt;td&gt;自然言語処理（エンティティ抽出、感情分析、キーフレーズ抽出、言語判定）&lt;&#x2F;td&gt;&lt;td&gt;同じ処理をLLMへの1プロンプトで任せる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Textract&lt;&#x2F;td&gt;&lt;td&gt;書類のOCRとフォーム・表の構造化抽出&lt;&#x2F;td&gt;&lt;td&gt;ビジョン対応LLMに直接PDF・画像を渡して構造化JSONを返させる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Polly&lt;&#x2F;td&gt;&lt;td&gt;ニューラル音声合成（TTS）&lt;&#x2F;td&gt;&lt;td&gt;OpenAI TTS、ElevenLabs、Gemini Native Speechなど生成AI系音声モデル&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;個人のツールや単発のトランザクションで、わざわざ用途別のAPIを選んで使う意味は、ほとんど残っていません。画像の内容を説明してほしければ、ClaudeやGPTに画像をそのまま渡せば事足ります。領収書から項目を抜き出したいときも、PDFをLLMに渡してJSONで返すよう頼めば済みます。APIの名前を覚え、サービスごとに異なる出力フォーマットを吸収する手間と比べて、LLMに自然言語で頼む方が圧倒的に速いからです。&lt;&#x2F;p&gt;
&lt;p&gt;もっとも、これはあくまで個人開発者のツールや単発利用の話です。エンタープライズの大量処理では、これらのAPIは現在もLLMパイプラインの前処理部品として現役です。例えば、TextractでPDFを構造化してからLLMに渡す、Translateで多言語テキストを統一する、ComprehendでPIIをマスクしてから生成系に流すといった使い方が典型です。&lt;&#x2F;p&gt;
&lt;p&gt;理由は、個人利用では意識する必要のない要件が企業では避けられないからです。LLMは同じ入力でも出力が揺れ、ハルシネーションを起こし、大量処理ではトークン課金が嵩みます。一方、Textractのような専用APIは決定的な出力を返し、料金もページ単価で桁違いに安く、出力形式が固定なので監査ログやSLA契約にも馴染みます。個人の単発処理ではこれらの差が表面化しないため、LLM直叩きの手軽さが勝るのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWSのLLMはエンタープライズのために&quot;&gt;AWSのLLMはエンタープライズのために&lt;&#x2F;h2&gt;
&lt;p&gt;前節で見たように、かつてのAIサービスは個人視点ではLLMに置き換えられました。ではAWSはこの流れにどう応えたのでしょうか。自前で競争力のあるLLMを持たないAWSが出した答えは、外部のモデル提供者を集めて統一APIで呼び出せるようにしたBedrockでした。&lt;&#x2F;p&gt;
&lt;p&gt;2026年4月時点では、Anthropic (Claude) を筆頭に、Amazon自社のNovaとTitan、Meta (Llama)、Mistral、OpenAI、DeepSeek、Cohere、AI21 Labsなど、十数社・100モデル超が並びます。OpenAIのオープンウェイトモデル（gpt-oss系）までBedrockから呼べるようになったのは2025年の大きな動きでした。モデルの厚みだけを見れば、単一ベンダーの直接APIよりも広い選択肢が用意されているとも言えます&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-converse-1&quot;&gt;&lt;a href=&quot;#fn-converse&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;ただ、Bedrockの価値の本体はモデル選択の自由そのものではなく、&lt;strong&gt;AWSの枠組みへ組み込まれていること&lt;&#x2F;strong&gt;にあります。既存のIAMポリシーで権限を統制でき、VPCエンドポイントでインターネットを経由せず呼び出せ、CloudTrailで全ての呼び出しを監査でき、利用料はAWSの単一請求にまとまります。データが既にS3にある組織では、そこからRetrieval Augmented Generationへ繋ぐ道もBedrockの中で完結します。既にAWS上に業務基盤がある企業にとっては、こうした統合こそがBedrockを選ぶ最大の理由です。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、個人開発者がBedrockを介する恩恵はほとんど残っていません。新モデルの到達はAnthropicやOpenAIの直接APIより遅れることが多く、IAMやリージョンの設定、モデルアクセス申請といったセットアップの重さも、APIキー1本で始められる本家との差としてのしかかります。かつてIAMキーと数行のコードから始められたAWS AIサービスの気軽さは、LLM時代には失われたと言って良いでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、AWSがLLM時代に出した答えは、AWSを既に使っている企業への最適化でした。AWSが誰を主な顧客として見ているのか、この選択そのものが物語っています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;個人から見たAWSのAIは、この10年で位置づけを大きく変えました。IAMキーと数行のコードで訓練済みモデルを叩ける気軽さは、LLMの登場によって個人視点では蒸発しています。翻訳、画像解析、帳票処理のいずれも、ClaudeやGPTに直接渡す方が速く柔軟で、専用APIを選ぶ理由はほとんど残っていません。&lt;&#x2F;p&gt;
&lt;p&gt;LLM時代の本命であるBedrockも、個人開発者にとっては分が悪い選択肢です。その価値はIAM&#x2F;VPC&#x2F;監査&#x2F;単一請求といった統合レイヤーにあり、新モデル到達は直接APIより遅れ、セットアップも重く、モデル選択肢の広さも個人が手軽に享受できる形にはなっていません。&lt;&#x2F;p&gt;
&lt;p&gt;個人向けの例外として、コード補完のAmazon Q Developerには無料枠があります。しかし実際の現場ではGitHub Copilot、Cursor、Claude Codeが競合し、Q Developerがデフォルトに選ばれる場面はほとんど見かけません。AWSが個人向け枠を用意している事実と、個人がそこを選んでいない事実は両立しています。&lt;&#x2F;p&gt;
&lt;p&gt;AWSのAIは個人から離れたわけではなく、&lt;strong&gt;個人が期待する形では競争に勝てていない&lt;&#x2F;strong&gt;、というのが正直な現状でしょう。Bedrock、SageMaker、Q Businessといった現在のAI製品群は、企業の業務システムと不可分な形で組み立てられています。かつてAWSにあった「IAMキーと数行のコードで叩ける個人の遊び場」としての姿は、もう見つけにくくなっています。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-converse&quot;&gt;
&lt;p&gt;こういった機能説明を読むと「Bedrockではマルチモデルを統一したインターフェイスで扱える」と期待するかも知れません。たしかにBedrockには統一メッセージ形式でモデル差し替えを可能にするConverse APIもあります。ただし、モデルごとに対応したプロンプトチューニングは必要ですし挙動もモデルごとに異なるため、Converse APIだから簡単に差し替え可能と言うわけではありません。また、当然ながらモデル固有機能は利用できません。 &lt;a href=&quot;#fr-converse-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">かつて「IAMキー1本で訓練済みAPIを叩ける気軽さ」が魅力だったAWSのAI。LLM時代に個人視点で何が残っているかを、BedrockとAmazon Q Developerまで含めて観察します。</summary>
        </entry><entry xml:lang="en">
        <title>DALL-E 3 が消える日に備えて移行した</title>
        <published>2026-04-09T00:00:00+00:00</published>
        <updated>2026-04-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/dalle3-to-gpt-image-mini/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/dalle3-to-gpt-image-mini/</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;04&amp;#x2F;dalle3-to-gpt-image-mini&amp;#x2F;cover.webp?h=2287a707721d15e344d2&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;OpenAIから以下のメールが届きました。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;As part of our continuous upgrade process, we are deprecating the following models on May 12, 2026:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Dall-e-2&lt;&#x2F;li&gt;
&lt;li&gt;Dall-e-3&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Ahead of the shutdown timeline, we encourage you to explore gpt-image-1.5 or gpt-image-1-mini, our latest flagship models.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;DALL-E 3は、OpenAIが2023年にリリースしたテキストをもとに画像を生成するAIモデルです。プロンプトを与えるだけで高品質な画像を生成でき、API経由でプログラムへ組み込めるため、画像生成の自動化に広く使われてきました。&lt;&#x2F;p&gt;
&lt;p&gt;このブログでは、記事のカバー画像をDALL-E 3 APIで生成しています。Claude Codeのスキル（&lt;code&gt;&#x2F;article-cover&lt;&#x2F;code&gt;）からシェルスクリプトを呼び出し、記事の内容に合った画像を自動生成してカバーに使う仕組みです。2026年5月12日にDALL-E 3が廃止されると、この仕組みが動かなくなります。廃止まで約1ヶ月しかないので、早速対応しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;移行先の選定&quot;&gt;移行先の選定&lt;&#x2F;h2&gt;
&lt;p&gt;メールで案内された後継モデルはgpt-image-1.5（高品質・高コスト）とgpt-image-1-mini（コスト効率重視）の2つです。他のサービスも検討しましたが、まだOpenAIにチャージが残っているので、画像生成については、当面OpenAIを使い続けることとしました。ブログのカバー画像は記事の雰囲気を伝えるためのもので、写真レベルの精度は求めていません。コストと品質のバランスから &lt;strong&gt;gpt-image-1-mini&lt;&#x2F;strong&gt; を選びました。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、DALL-E 3との間にいくつかの仕様差があります。最も大きな変化はサポートされる画像サイズです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;DALL-E 3&lt;&#x2F;th&gt;&lt;th&gt;gpt-image-1-mini&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1792x1024（16:9）&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;1536x1024（3:2）&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1024x1792&lt;&#x2F;td&gt;&lt;td&gt;1024x1536&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1024x1024&lt;&#x2F;td&gt;&lt;td&gt;1024x1024&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;これまで使っていた画角16:9の画像は新モデルでは非対応です。
最も近い横長サイズは1536x1024で、アスペクト比が16:9から3:2に変わります。16:9はモニターや動画で標準的な比率ですが、3:2はフィルムカメラ（35mm）由来の伝統的な比率です。このブログではCSSの &lt;code&gt;object-fit&lt;&#x2F;code&gt; でカバー画像を表示しているため表示上の問題はありませんが、ちょっと間が抜けた感じになります。&lt;&#x2F;p&gt;
&lt;p&gt;品質パラメータも名前が変わりました。DALL-E 3の &lt;code&gt;standard&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;hd&lt;&#x2F;code&gt; に対して、gpt-image-1-miniでは &lt;code&gt;low&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;medium&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;high&lt;&#x2F;code&gt; の3段階です。従来の &lt;code&gt;hd&lt;&#x2F;code&gt; に相当するのは &lt;code&gt;high&lt;&#x2F;code&gt; になります。&lt;&#x2F;p&gt;
&lt;p&gt;課金モデルも異なります。DALL-E 3は「1枚いくら」のシンプルな定額課金でしたが、新モデルはトークンベースの課金に変わっています。画像は内部的にトークンに変換され、入力（プロンプト）と出力（生成画像）のトークン数に応じて課金されます。実際の1枚あたりの費用を比較すると以下のとおりです（横長サイズ）。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Quality&lt;&#x2F;th&gt;&lt;th&gt;DALL-E 3（1792x1024）&lt;&#x2F;th&gt;&lt;th&gt;gpt-image-1-mini（1536x1024）&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Low&lt;&#x2F;td&gt;&lt;td&gt;--&lt;&#x2F;td&gt;&lt;td&gt;$0.006&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Medium&lt;&#x2F;td&gt;&lt;td&gt;$0.120&lt;&#x2F;td&gt;&lt;td&gt;$0.015&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;High&lt;&#x2F;td&gt;&lt;td&gt;$0.120&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;$0.052&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;High品質で比較すると、&lt;strong&gt;1枚あたり $0.120 → $0.052 で約57%のコスト削減&lt;&#x2F;strong&gt;になります。Medium品質なら $0.015で87%削減です。参考までに、上位モデルgpt-image-1.5のHighは1536x1024で約 $0.250と、DALL-E 3の2倍以上です。
ブログのカバー画像用途ではgpt-image-1-miniで十分だと割切りました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;スクリプトの改修&quot;&gt;スクリプトの改修&lt;&#x2F;h2&gt;
&lt;p&gt;このブログでは、カバー画像の生成に以下のシェルスクリプトを使っています。
プロンプトと出力先を引数で受け取り、OpenAIの画像生成APIを呼び出して画像を保存するシンプルなスクリプトです。
DALL-E 3を使っていたものを、gpt-image-1-miniを使うよう修正しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;scripts&#x2F;generate-cover.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;span class=&quot;z-support z-function z-builtin&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -euo pipefail&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;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 z-definition z-string z-string&quot;&gt;&amp;quot;1536x1024&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;QUALITY&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;quot;high&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;MODEL&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;quot;gpt-image-1-mini&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;# ... 引数パース省略 ...&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;RESPONSE&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;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s&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&quot;&gt;  https:&#x2F;&#x2F;api.openai.com&#x2F;v1&#x2F;images&#x2F;generations&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;  -H &amp;quot;Content-Type: application&#x2F;json&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;  -H &amp;quot;Authorization: Bearer &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OPENAI_API_KEY&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;  -d &amp;quot;&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;jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -n&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;    --arg model &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MODEL&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;    --arg prompt &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$PROMPT&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;    --arg size &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$SIZE&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;    --arg quality &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$QUALITY&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-punctuation z-definition z-string z-string&quot;&gt;    &amp;#39;{model: $model, prompt: $prompt, n: 1,&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;      size: $size, quality: $quality}&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&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# gpt-image-1-mini returns b64_json; fall back to URL for other models&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;B64&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;$RESPONSE&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; jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -r &amp;#39;.data[0].b64_json &#x2F;&#x2F; empty&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;URL&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;$RESPONSE&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; jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -r &amp;#39;.data[0].url &#x2F;&#x2F; empty&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-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; -n&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;$B64&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&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$B64&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; base64&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -d&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-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;$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-keyword&quot;&gt;elif&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; -n&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;$URL&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-entity z-name z-function&quot;&gt;  curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -s &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; -o &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$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-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;移行にあたって変更したのは以下の点です。&lt;&#x2F;p&gt;
&lt;p&gt;まず、モデル名・サイズ・品質の3パラメータを変更しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;diff&quot; data-name=&quot;scripts&#x2F;generate-cover.sh&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-deleted z-diff&quot;&gt;SIZE=&amp;quot;1792x1024&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;span class=&quot;z-markup z-deleted z-diff&quot;&gt;QUALITY=&amp;quot;hd&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;span class=&quot;z-markup z-deleted z-diff&quot;&gt;MODEL=&amp;quot;dall-e-3&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;span class=&quot;z-markup z-inserted z-diff&quot;&gt;SIZE=&amp;quot;1536x1024&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;span class=&quot;z-markup z-inserted z-diff&quot;&gt;QUALITY=&amp;quot;high&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;span class=&quot;z-markup z-inserted z-diff&quot;&gt;MODEL=&amp;quot;gpt-image-1-mini&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;APIエンドポイント（&lt;code&gt;&#x2F;v1&#x2F;images&#x2F;generations&lt;&#x2F;code&gt;）とリクエスト形式は同じなので、パラメータの変更だけで済むと思っていましたが、もう1点変更が必要でした。&lt;&#x2F;p&gt;
&lt;p&gt;DALL-E 3はレスポンスで画像のURLを返していましたが、gpt-image-1-miniは&lt;strong&gt;base64エンコードされた画像データ&lt;&#x2F;strong&gt;を直接返します。そのため、レスポンス処理をURLダウンロードからbase64デコードへ変更しました。&lt;code&gt;b64_json&lt;&#x2F;code&gt; と &lt;code&gt;url&lt;&#x2F;code&gt; の両方へ対応したので、将来モデルを切り替えてもこの部分は変更不要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;DALL-E 3の廃止に伴い、ブログのカバー画像生成をgpt-image-1-miniに移行しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;サイズが16:9（1792x1024）から3:2（1536x1024）に変わった&lt;&#x2F;li&gt;
&lt;li&gt;課金モデルが定額からトークンベースに変わった&lt;&#x2F;li&gt;
&lt;li&gt;費用はHigh品質で約57%削減&lt;&#x2F;li&gt;
&lt;li&gt;レスポンス形式がURLからbase64に変わった&lt;&#x2F;li&gt;
&lt;li&gt;スクリプトの変更は最小限&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この記事のカバー画像もgpt-image-1-miniで生成しています。実のところ微妙です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;DALL-E 3と比べると間の抜けた絵になっている。&lt;&#x2F;li&gt;
&lt;li&gt;画角が3:2も間延びして微妙&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;しばらく様子を見て、満足できなければgpt-image-1に差し替えるかも知れません。
また、画角についても、変形かクロップで16:9に変更することも考えるかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;OpenAIのモデル廃止は突然来るものなので、同様にDALL-E 3を使っているプロジェクトがあれば、5月12日までに移行しておくことをおすすめします。&lt;&#x2F;p&gt;
</content>
        <summary type="html">OpenAIからDALL-E 3廃止の通知を受け、ブログのカバー画像生成スクリプトをgpt-image-1-miniに移行しました。サイズや課金モデルの変化、費用比較についてまとめます。
</summary>
        </entry><entry xml:lang="en">
        <title>Claude が Claude を設計する時代に私たちは何を考えるべきか</title>
        <published>2026-04-09T07:23:22+09:00</published>
        <updated>2026-04-09T07:23:22+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/no-coding-anymore/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/no-coding-anymore/</id>
        
            <content type="html">&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;no-coding-anymore&amp;#x2F;cover.webp?h=dfc871a65d2d9acd0ab6&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;p&gt;ここ数日Claudeを起動するとほぼ毎日のようにアップデートが走ってるなと思っていましたが、
Anthropic CEOの発言を聞いて納得です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ClaudeはClaude自身が開発している？&quot;&gt;ClaudeはClaude自身が開発している？&lt;&#x2F;h2&gt;
&lt;p&gt;以下はAnthropic CEOのDario Amodeiの発言です。&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-media-max-width=&quot;560&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Anthropic CEO: &lt;br&gt;&lt;br&gt;“ I have engineers within anthropic who don’t write any code, they just let Claude write the code and they edit it and look it over”&lt;br&gt;&lt;br&gt;“At anthropic writing code means designing the next version of Claude it self, so we essentially have Claude designing the next… &lt;a href=&quot;https:&#x2F;&#x2F;t.co&#x2F;kK8D7JlKzB&quot;&gt;https:&#x2F;&#x2F;t.co&#x2F;kK8D7JlKzB&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;t.co&#x2F;ygIvHkKNHf&quot;&gt;pic.twitter.com&#x2F;ygIvHkKNHf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&amp;mdash; CG (@cgtwts) &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;cgtwts&#x2F;status&#x2F;2038234212160119034?ref_src=twsrc%5Etfw&quot;&gt;March 29, 2026&lt;&#x2F;a&gt;&lt;&#x2F;blockquote&gt; &lt;script async src=&quot;https:&#x2F;&#x2F;platform.twitter.com&#x2F;widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;&#x2F;script&gt;
&lt;blockquote&gt;
&lt;p&gt;I have engineers within Anthropic who say, &quot;I don&#x27;t write any code. I don&#x27;t write any code anymore.
I just let Claude write the code and I edit it or I look it over.&quot; And of course, at Anthropic,
writing code means designing the next version of Claude itself. So we essentially have Claude
designing the next version of Claude itself, not completely, not in all ways, but in many ways.
That loop starts to close very fast. And so I look at this and I say, &quot;Wow, this is exciting.
It&#x27;s incredible what we can do with the world. But also, it&#x27;s really speeding up a lot. And I&#x27;m just
not sure we have that much time.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Anthropicのエンジニアはすでにコードを書くことをせず編集や確認のみで、Claude自身が次のClaudeを設計し開発しているという発言です。
しかも、&lt;q&gt;That loop starts to close very fast&lt;&#x2F;q&gt;（このループは非常に速く閉じつつある）ということです。
事実、52日間で50以上の新機能が追加されたと報じられています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AI_Safetyへの懸念&quot;&gt;AI Safetyへの懸念&lt;&#x2F;h2&gt;
&lt;p&gt;Darioの発言は「私たちに残された時間がそれほど多くないのではないか」で終わっています。&lt;&#x2F;p&gt;
&lt;p&gt;これは、AIが人類の存在を脅かすというような極端な話ではなく、安全な形でAIを社会に統合するための制度設計・技術的安全策・国際的な合意形成などに使える時間のことを指していると思います。&lt;&#x2F;p&gt;
&lt;p&gt;ClaudeがClaude自身を設計するというフィードバックループが閉じると、AIの能力向上が自己加速的になります。
これまでは人間がAIの安全性やガバナンスの枠組みを整えていましたが、このフィードバックループでAIの開発がどんどん加速していった場合にAIの能力が想定されているガードレールの先に行ってしまうかもしれないということでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicが「Responsible Scaling Policy」を掲げ安全性研究へ力を入れているのも、AIが十分に高度になったとき悪用されたり意図しない動作をしたりするリスクに対して社会やルールがまだ追いついていないという問題意識からでしょう。そして、フィードバックループによりその危機感は高まっているということです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Darioの発言で印象的なのは、AIがAI自身を設計するというループがすでに回り始めているという点です。これは未来の話ではなく、今Anthropicの中で起きていることです。自分自身を振り返っても、昨年Claude Codeを本格的に使い出してからは構想・仕様・アーキテクチャまでが自分の仕事で、設計以降はClaude Codeへ任せるようになりました。開発の現場はすでに変わっています。&lt;&#x2F;p&gt;
&lt;p&gt;問題は、このフィードバックループが閉じるほどAIの進化が加速し、安全策や社会制度を整える時間が縮んでいくことです。技術の恩恵を享受しながらも、そのスピードに見合ったガードレールをどう引くのか。AIを使う側の一人として、この問いを意識し続けることが大事だと感じています。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropic CEOが語った「エンジニアはもうコードを書かない」という現実。Claudeが次のClaudeを設計するフィードバックループの加速と、AI Safetyの時間的猶予について考えます。
</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(4) — 現代でも有用なパターンとまとめ</title>
        <published>2026-04-06T08:06:00+09:00</published>
        <updated>2026-04-06T08:06:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/04-essential-patterns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/04-essential-patterns/</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;04&amp;#x2F;gof-design-patterns&amp;#x2F;04-essential-patterns&amp;#x2F;cover.webp?h=625c502b1c7f13dd5ea6&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&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;h2 id=&quot;前回までの振り返り&quot;&gt;前回までの振り返り&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;01-paradigm-shift&#x2F;&quot;&gt;第1回&lt;&#x2F;a&gt;では、OOPのパラダイムシフトとGoFデザインパターンの誕生、そしてGo言語による脱OOPの流れを振り返りました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;02-unnecessary-patterns&#x2F;&quot;&gt;第2回&lt;&#x2F;a&gt;では、Go言語の3つの設計方針がGoFの23パターンのうち10パターンを不要にしたことを検証しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;03-useful-patterns&#x2F;&quot;&gt;第3回&lt;&#x2F;a&gt;では、残る13パターンのうち、言語機能として取り込まれたIteratorと、現代の設計手法により非推奨となったSingletonを検討しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&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;OOPの制約への処方箋（第2回）&lt;&#x2F;td&gt;&lt;td&gt;Template Method, Factory Method, Abstract Factory, Bridge, Prototype, Memento, Strategy, Command, Visitor, Observer&lt;&#x2F;td&gt;&lt;td&gt;不要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;言語機能として吸収（第3回）&lt;&#x2F;td&gt;&lt;td&gt;Iterator&lt;&#x2F;td&gt;&lt;td&gt;意識不要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;設計手法の進化で非推奨（第3回）&lt;&#x2F;td&gt;&lt;td&gt;Singleton&lt;&#x2F;td&gt;&lt;td&gt;非推奨&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;本記事では、残る11のパターンがなぜ現代でも有用なのかを分析し、シリーズ全体の結論としてデザインパターンの本質的価値を考察します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現代でも有用なパターン&quot;&gt;現代でも有用なパターン&lt;&#x2F;h2&gt;
&lt;p&gt;残る11のパターンは、継承と参照セマンティクスのいずれにも依存していません。ここまで見てきたパターンがOOPの言語メカニズムへの処方箋だったのに対し、これらはOOPとは無関係に存在する、ソフトウェア設計の普遍的な課題を解決するものです。つまり、GoFの23パターンの中にはOOPの処方箋と、言語に依存しない設計の原則「ソフトウェアアーキテクチャの原則」が混在していたのです。&lt;&#x2F;p&gt;
&lt;p&gt;生き残ったパターンを、その理由ごとに分類します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;小さな部品を合成して大きな振る舞いを作る&quot;&gt;小さな部品を合成して大きな振る舞いを作る&lt;&#x2F;h3&gt;
&lt;p&gt;Go言語の設計思想「継承より合成（composition over inheritance）」と直結する分類です。小さな部品を組み合わせて複雑な構造や振る舞いを構築するという原則は、プログラミングパラダイムを問わず有効です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Composite&lt;&#x2F;strong&gt; — 再帰的なツリー構造を合成し、個々の要素と合成要素を同一視する。ファイルシステムやUIコンポーネントなど、階層構造を持つあらゆる領域で使われる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Decorator&lt;&#x2F;strong&gt; — 既存の機能に新しい責務を動的に重ね合わせる。Go言語では&lt;code&gt;http.Handler&lt;&#x2F;code&gt;をラップするミドルウェアパターンとして標準的に使われている&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Chain of Responsibility&lt;&#x2F;strong&gt; — 処理を連鎖させ、リクエストを適切なハンドラに委譲する。Go言語のHTTPミドルウェアチェーンそのもの&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Builder&lt;&#x2F;strong&gt; — 複雑なオブジェクトを段階的に構築する。Go言語ではfunctional optionsパターンとして定着している&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;コンポーネント間の境界を制御する&quot;&gt;コンポーネント間の境界を制御する&lt;&#x2F;h3&gt;
&lt;p&gt;ソフトウェアの規模が大きくなると、コンポーネント間の依存関係やインターフェースの不一致が複雑さの主要因になります。この問題に対処するパターンは、言語やパラダイムに関係なく必要です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adapter&lt;&#x2F;strong&gt; — 互換性のないインターフェース同士を橋渡しする。外部ライブラリやレガシーシステムとの統合で常に必要になる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Facade&lt;&#x2F;strong&gt; — 複雑なサブシステムに対して統一的な窓口を提供する。Go言語ではパッケージの公開APIを絞ることで自然に実現される&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Proxy&lt;&#x2F;strong&gt; — 対象へのアクセスを制御する代理を提供する。遅延初期化、アクセス制御、ログ記録など用途が幅広い&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Mediator&lt;&#x2F;strong&gt; — 多対多のオブジェクト間の相互作用を仲介者に集約し、疎結合にする。イベントバスやメッセージブローカーの設計に通じる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;状態に応じて振る舞いを切り替える&quot;&gt;状態に応じて振る舞いを切り替える&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;State&lt;&#x2F;strong&gt; — 内部状態に応じてオブジェクトの振る舞いを変更する。Go言語ではStateインターフェースを定義し、状態ごとに異なる型で実装する。有限状態マシンの設計に直結する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;特定領域の問題を解決する&quot;&gt;特定領域の問題を解決する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flyweight&lt;&#x2F;strong&gt; — 多数の細粒度オブジェクトの共有によりメモリ使用量を削減する。文字列のインターン化やキャッシュなど、メモリ最適化が必要な場面で有効&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Interpreter&lt;&#x2F;strong&gt; — 言語の文法を定義し解釈する。DSL（ドメイン固有言語）や設定ファイルのパーサー、式評価エンジンなど、特定の用途で使われる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ_—_デザインパターンの本質的価値とは何だったのか&quot;&gt;まとめ — デザインパターンの本質的価値とは何だったのか&lt;&#x2F;h2&gt;
&lt;p&gt;GoFの功績は、コード内で繰り返し現れるパターンに名前を付け、&lt;strong&gt;開発者の共通言語&lt;&#x2F;strong&gt;を確立したことにあります。「ここはObserverで」「Adapterを挟もう」と言えば設計意図が伝わる。この語彙の確立は、ソフトウェア開発の生産性に大きく貢献しました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、本記事の分析が示すように、GoFの23パターンには性質の異なる2種類のものが混在していました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;実装の工夫&lt;&#x2F;strong&gt; : パラダイムシフトを起こしたばかりのOOPの未成熟さをカバーするもの。継承の副作用を管理するTemplate MethodやVisitor、参照セマンティクスを補完するPrototypeやMemento。これらはOOPという特定のパラダイムの制約の中で必要だった処方箋であり、パラダイムが変われば不要になるもの。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;普遍的な設計原則&lt;&#x2F;strong&gt; - 合成による構築、境界の制御など設計のベストプラクティス。CompositeやDecorator、AdapterやFacadeは、OOPとは無関係に、ソフトウェアの複雑さに対処するためのアーキテクチャの知恵。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;GoFの問題は、この2つがあまり区別されず、同列にカタログ化されたことです。そして当時、OOPが成熟した段階を経験したプログラマが少なかったことも相まって、GoFは必要以上に神格化されました。
本来はコードレベルの実装パターンであるにもかかわらず、当時は業務システムのアーキテクチャを語る場面でGoFのパターン名が持ち出されるような頓珍漢なエンジニアさえ出現しました。デザインパターンは「設計パターン」と訳されますが、実態は「コードパターン」であったことに留意すべきです。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語が示したのは、OOPの制約に起因するパターンは言語設計で解消できるということです。そして残った11のパターンこそが、GoFの本質的な遺産「言語やパラダイムを超えた設計原則」だったと言えます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、この結論すら永続的なものではありません。Rustの列挙型とパターンマッチングはStateパターンを言語機能として吸収しつつありますし、名前付き引数やデフォルト値を持つ言語ではBuilderの必要性が薄れます。今日「普遍的な設計原則」に見えるものも、将来の言語やパラダイムの進化によって、さらに整理されていく可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;デザインパターンの本質的な価値は、23のカタログそのものにはありませんでした。ソフトウェアの複雑さに名前を付け、共有可能な知識として体系化しようとした試み「その営み」こそが、GoFの真の貢献だったのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;本シリーズで取り上げたGoFの23パターンすべてをGo言語で実装したサンプルコードを公開しています。&lt;&#x2F;p&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;gof-go-samples&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;
</content>
        <summary type="html">連載最終回。GoFの23パターンのうち、OOPに依存しない11のパターンは現代でも有用です。なぜ生き残ったのかを分析し、デザインパターンの本質的価値を考察します。</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(3) — 言語に吸収されたパターンと非推奨のSingleton</title>
        <published>2026-04-02T10:15:00+09:00</published>
        <updated>2026-04-02T10:15:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/03-useful-patterns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/03-useful-patterns/</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;04&amp;#x2F;gof-design-patterns&amp;#x2F;03-useful-patterns&amp;#x2F;cover.webp?h=ab1a8a011510459a068c&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&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;h2 id=&quot;前回までの振り返り&quot;&gt;前回までの振り返り&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;01-paradigm-shift&#x2F;&quot;&gt;第1回&lt;&#x2F;a&gt;では、手続き型プログラミングからOOPへのパラダイムシフト、その中でGoFデザインパターンが「OOPでよいコードを書くためのお手本」として体系化された経緯を振り返りました。そして現代では、OOPの中核 — クラス継承、型階層、参照セマンティクス — を意図的に排除したGo言語が登場し、新たなパラダイムシフトが起きていることを確認しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;02-unnecessary-patterns&#x2F;&quot;&gt;第2回&lt;&#x2F;a&gt;では、Go言語の3つの設計方針がGoFの23パターンのうち10パターンを不要にしたことを検証しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Go言語の設計方針&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;Template Method, Factory Method, Abstract Factory, Bridge&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;参照セマンティクスではなく値セマンティクスをデフォルトに&lt;&#x2F;td&gt;&lt;td&gt;Prototype, Memento&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるように&lt;&#x2F;td&gt;&lt;td&gt;Strategy, Command, Visitor, Observer&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;これらはOOPの制約の中で生まれた処方箋であり、制約そのものを取り除いたGo言語では必要なくなったものでした。では、残る13パターンはどうでしょうか。本記事では、言語機能として取り込まれたものと、設計手法の進化で非推奨となったものを検討します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;言語機能として取り込まれたパターン&quot;&gt;言語機能として取り込まれたパターン&lt;&#x2F;h2&gt;
&lt;p&gt;デザインパターンの中には、その有用性が広く認められた結果、現代の言語では標準的な機能として取り込まれたものがあります。デザインパターンが語られた当時はOOPがまだ成熟しておらず、これらの機能をユーザーで実装していたとも言えます。これらのパターンは「不要になった」のではなく、「わざわざパターンとして意識する必要がなくなった」と言えます。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語も例外でなく、言語仕様としてこれらのパターンを取り込んでいます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;コレクションの内部構造を公開せずに要素を走査する&quot;&gt;コレクションの内部構造を公開せずに要素を走査する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Iterator&lt;&#x2F;strong&gt; — イテレータオブジェクトを別途定義し、&lt;code&gt;hasNext()&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;next()&lt;&#x2F;code&gt;のようなインターフェースを実装する必要があった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;『&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;4bW36Po&quot;&gt;Java言語で学ぶデザインパターン入門&lt;&#x2F;a&gt;第3版』(結城浩著)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-affiliate-1&quot;&gt;&lt;a href=&quot;#fn-affiliate&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;のIteratorパターンのサンプルコードを見てみます。本棚（BookShelf）に本（Book）を格納し、イテレータで順に取り出すという例です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;Book.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Book&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-storage z-modifier z-storage z-type&quot;&gt;    private String&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&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-storage z-modifier&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&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;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; name&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-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&quot;&gt; name&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public String&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getName&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;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;BookShelf.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;Iterator&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-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Iterable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; books&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-storage z-modifier z-storage z-type&quot;&gt;    private int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; last&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;&#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-modifier&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelf&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;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; maxsize&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-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt; new Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;maxsize&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getBookAt&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;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; index&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;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; appendBook&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;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; book&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-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;last&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-source&quot;&gt; book&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;        last&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&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-storage z-modifier z-storage z-type&quot;&gt;    public int&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getLength&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;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; last&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-storage z-type z-annotation&quot;&gt;    @Override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; iterator&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;        return new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelfIterator&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-this&quot;&gt;this&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;BookShelfIterator.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;Iterator&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;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;NoSuchElementException&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-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BookShelfIterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&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-storage z-modifier z-storage z-type&quot;&gt;    private int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; index&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-storage z-modifier&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelfIterator&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;BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; bookShelf&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-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;bookShelf&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; bookShelf&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-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index&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;&#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;span class=&quot;z-punctuation z-definition z-annotation z-storage z-type z-annotation&quot;&gt;    @Override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public boolean&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; hasNext&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-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index &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; bookShelf&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;getLength&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;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; true&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-keyword&quot;&gt; else&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;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; false&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;span class=&quot;z-punctuation z-definition z-annotation z-storage z-type z-annotation&quot;&gt;    @Override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; next&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-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-entity z-name z-function&quot;&gt;hasNext&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;            throw new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; NoSuchElementException&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-storage z-type&quot;&gt;        Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&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; bookShelf&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;getBookAt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index&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;        index&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-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;Main.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;Iterator&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-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&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-storage z-modifier z-storage z-type&quot;&gt;    public static void&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;span class=&quot;z-storage z-type&quot;&gt;String&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; 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;span class=&quot;z-storage z-type&quot;&gt;        BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelf&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;4&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;        bookShelf&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;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&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;quot;Around the World in 80 Days&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-source&quot;&gt;        bookShelf&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;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&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;quot;Bible&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-source&quot;&gt;        bookShelf&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;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&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;quot;Cinderella&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-source&quot;&gt;        bookShelf&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;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&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;quot;Daddy-Long-Legs&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;        &#x2F;&#x2F; 明示的にIteratorを使う方法&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; it&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; bookShelf&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;iterator&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;        while&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;it&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;hasNext&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-storage z-type&quot;&gt;            Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&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; it&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;next&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;            System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&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;println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&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;getName&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-source&quot;&gt;        System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&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;println&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;        &#x2F;&#x2F; 拡張for文を使う方法&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-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&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;            System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&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;println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&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;getName&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-source&quot;&gt;        System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&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;println&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;!-- author-approved: MIT License sample code credit --&gt;
&lt;p&gt;上記Javaコードは結城浩氏によるサンプルコード（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.hyuki.com&#x2F;dp&#x2F;&quot;&gt;MIT License&lt;&#x2F;a&gt;、Copyright (c) 2001,2004,2021 結城浩 &#x2F; Hiroshi Yuki）です。&lt;&#x2F;p&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;4つのファイル、約80行のコードが必要です。&lt;code&gt;BookShelfIterator&lt;&#x2F;code&gt;クラスが走査の状態（現在のインデックス）を管理し、&lt;code&gt;hasNext()&lt;&#x2F;code&gt;と&lt;code&gt;next()&lt;&#x2F;code&gt;のインターフェースを実装しています。&lt;code&gt;BookShelf&lt;&#x2F;code&gt;は&lt;code&gt;Iterable&amp;lt;Book&amp;gt;&lt;&#x2F;code&gt;を実装し、&lt;code&gt;iterator()&lt;&#x2F;code&gt;メソッドでイテレータを生成します。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語で同じBookShelfを書くとどうなるでしょうか。Go 1.23で導入されたrange-over-function（&lt;code&gt;iter.Seq&lt;&#x2F;code&gt;）を使うと、Javaと同等のカスタムコレクションを以下のように実装できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot; data-name=&quot;main.go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;package&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; main&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;import&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;quot;fmt&amp;quot;&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;quot;iter&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&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;    Name&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&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;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&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;    books&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-type&quot;&gt;Book&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;span class=&quot;z-keyword&quot;&gt;func&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;s &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-type&quot;&gt;BookShelf&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; Append&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;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Book&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;    s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&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; append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&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;&#x2F;span&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-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;s &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-type&quot;&gt;BookShelf&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; All&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-type&quot;&gt; iter&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-type&quot;&gt;Seq&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-type&quot;&gt;Book&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;    return func&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;yield&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&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-type&quot;&gt;Book&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; bool&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;        for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&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-keyword z-operator&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;yield&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&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;                return&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;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;span class=&quot;z-keyword&quot;&gt;func&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;    shelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;BookShelf&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;    shelf&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;Append&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-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&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;quot;Around the World in 80 Days&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-source&quot;&gt;    shelf&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;Append&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-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&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;quot;Bible&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-source&quot;&gt;    shelf&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;Append&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-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&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;quot;Cinderella&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-source&quot;&gt;    shelf&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;Append&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-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&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;quot;Daddy-Long-Legs&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-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; shelf&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;All&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;        fmt&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;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Javaでは&lt;code&gt;Iterable&lt;&#x2F;code&gt;インターフェース、&lt;code&gt;Iterator&lt;&#x2F;code&gt;実装クラス、&lt;code&gt;hasNext()&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;next()&lt;&#x2F;code&gt;メソッドの3層が必要でした。Go言語では&lt;code&gt;iter.Seq&lt;&#x2F;code&gt;型の関数を1つ返すだけで済みます。イテレータの状態管理（インデックスの保持、終端判定）はクロージャが担い、専用のクラスを書く必要がありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現代の設計手法により非推奨となったパターン&quot;&gt;現代の設計手法により非推奨となったパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;インスタンスが1つだけであることを保証する&quot;&gt;インスタンスが1つだけであることを保証する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Singleton&lt;&#x2F;strong&gt; — クラスのインスタンスが1つだけであることを保証し、グローバルなアクセス手段を提供する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;典型的な例として、アプリケーションの設定情報（Config）をSingletonで管理するケースを見てみます。Go言語で実装した例です。&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;var&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;    instance&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-type&quot;&gt;Config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    once&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;     sync&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-type&quot;&gt;Once&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;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&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;    DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&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;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; GetConfig&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-entity z-name z-type&quot;&gt;Config&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;    once&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;Do&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&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;        port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&quot;&gt; strconv&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;Atoi&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;os&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;Getenv&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;quot;DB_PORT&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-source&quot;&gt;        instance&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; = &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Config&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;            DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&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;Getenv&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;quot;DB_HOST&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-source&quot;&gt;            DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; port&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;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; instance&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;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&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-keyword&quot;&gt;func&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;r &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-type&quot;&gt;UserRepository&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; FindByID&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;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&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-entity z-name z-type&quot;&gt;User&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; error&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; どこからでもGetConfig()でアクセスできる&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    config&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; GetConfig&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;    dsn&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; fmt&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;Sprintf&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;quot;%s:%d&#x2F;mydb&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; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBPort&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; ...&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;Configのようなオブジェクトは、システムにインスタンスを1つだけ持つのが都合よいものです。そのため、このような実装が広く行われていました。
しかし、テストのシーンを考えると、このパターンは問題があります。
&lt;code&gt;UserRepository&lt;&#x2F;code&gt;は&lt;code&gt;Config&lt;&#x2F;code&gt;に依存していますが、その依存は関数の引数に現れません。
テスト時に本番と異なる設定を注入することも困難です。&lt;&#x2F;p&gt;
&lt;p&gt;Singletonは、OOPの副作用とは無関係に、現代の多くの設計指針で非推奨とされるパターンです。問題の本質は「インスタンスが1つ」であることではなく、「グローバルなアクセス手段を提供する」という点にあります。&lt;code&gt;GetConfig()&lt;&#x2F;code&gt;のようなグローバル関数を通じてどこからでもアクセスできることが、隠れた依存関係を生み、テスト時のモック差し替えを困難にします。&lt;&#x2F;p&gt;
&lt;p&gt;注意すべきは、「ライフサイクルとしてのシングルトン」まで否定しているわけではないことです。DIコンテナがオブジェクトのスコープをシングルトンとして管理すること（SpringのデフォルトスコープやGoのfxにおけるライフサイクル管理など）は、依存関係が明示的である限り問題ありません。非推奨なのは、GoFが定義した「グローバルアクセスを提供するパターンとしてのSingleton」です。&lt;&#x2F;p&gt;
&lt;p&gt;現代では、依存性の注入（Dependency Injection）がこの問題に対するより優れた解法として確立されています。必要な依存を明示的に引数として渡すことで、グローバル状態を排除し、テスト容易性と可読性を確保します。同じ設計をDIで書くと次のようになります。&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;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&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;    DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&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;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&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;    config&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&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;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; NewUserRepository&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;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&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-entity z-name z-type&quot;&gt;UserRepository&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;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; config&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;&#x2F;span&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-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;r &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-type&quot;&gt;UserRepository&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; FindByID&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;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&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-entity z-name z-type&quot;&gt;User&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; error&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;    dsn&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; fmt&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;Sprintf&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;quot;%s:%d&#x2F;mydb&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; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBPort&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; ...&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;span class=&quot;z-keyword&quot;&gt;func&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;    config&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-type&quot;&gt; Config&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;        DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&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;Getenv&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;quot;DB_HOST&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-source&quot;&gt;        DBPort&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; 3306&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-source&quot;&gt;    repo&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; NewUserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&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; ...&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;UserRepository&lt;&#x2F;code&gt;が何に依存しているかが&lt;code&gt;NewUserRepository&lt;&#x2F;code&gt;の引数として明示されています。テスト時には異なる&lt;code&gt;Config&lt;&#x2F;code&gt;を渡すだけで済みます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;本記事では、GoFの残り13パターンのうち2つを検討しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Iterator&lt;&#x2F;strong&gt; — 言語機能として吸収され、パターンとして意識する必要がなくなった&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Singleton&lt;&#x2F;strong&gt; — OOPの副作用とは無関係に、グローバル状態という本質的な問題から非推奨となった。依存性の注入（DI）がより優れた解法として確立されている&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;次回は、残る11のパターンがなぜ現代でも有用なのかを分析し、シリーズ全体の結論としてデザインパターンの本質的価値を考察します。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-affiliate&quot;&gt;
&lt;p&gt;このリンクはAmazonアソシエイトのリンクです。 &lt;a href=&quot;#fr-affiliate-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">GoFの残り13パターンのうち、Iteratorは言語機能として吸収され、Singletonは現代の設計手法により非推奨となりました。それぞれの経緯をGo言語のコードとともに検討します。</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(2) — Go言語で不要になったパターン</title>
        <published>2026-04-01T10:00:00+09:00</published>
        <updated>2026-04-01T10:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/02-unnecessary-patterns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/02-unnecessary-patterns/</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;04&amp;#x2F;gof-design-patterns&amp;#x2F;02-unnecessary-patterns&amp;#x2F;cover.webp?h=395d88df7f249e0311f1&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&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;h2 id=&quot;前回の振り返り&quot;&gt;前回の振り返り&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;01-paradigm-shift&#x2F;&quot;&gt;前回&lt;&#x2F;a&gt;は、OOPが手続き型プログラミングからのパラダイムシフトとして登場した経緯、OOPの設計ノウハウを体系化したGoFデザインパターンが広く受け入れられた歴史、そして現代ではOOPの中核を意図的に排除したGo言語が登場したことを振り返りました。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語の設計方針は、OOPとの対比で次の3点に集約されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;クラス継承を排除し、合成（composition）と暗黙的インターフェースで代替した&lt;&#x2F;li&gt;
&lt;li&gt;参照セマンティクスではなく値セマンティクスをデフォルトにした&lt;&#x2F;li&gt;
&lt;li&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるようにした&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この設計方針を踏まえて、GoFの23パターンをGo言語の視点から再検討してみましょう。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「クラス継承」の副作用への処方箋だったパターン&quot;&gt;「クラス継承」の副作用への処方箋だったパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;OOP「クラス継承」がもたらしたもの&quot;&gt;OOP「クラス継承」がもたらしたもの&lt;&#x2F;h3&gt;
&lt;p&gt;ソフトウェアの保守性と拡張性を担保するために、「&lt;strong&gt;既存のコードを変更せずに機能を拡張する&lt;&#x2F;strong&gt;」という原則 — 開放閉鎖原則（Open-Closed Principle）が求められてきました。手続き型言語では、機能を追加するたび既存コードへ分岐を追加するしかなく、変更が既存の動作を壊すリスクが常にありました。OOPはこの課題に対して、&lt;strong&gt;クラス継承&lt;&#x2F;strong&gt;という新たなメカニズムで解決を図りました。基底クラスを定義し、サブクラスで振る舞いをオーバーライドすることで、既存コードに手を加えずに機能を拡張します。これがOOPの基本戦略でした。&lt;&#x2F;p&gt;
&lt;p&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; — Java等では1つのクラスしか継承できない。拡張の方向が1軸に制限される&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;ul&gt;
&lt;li&gt;&lt;strong&gt;Template Method&lt;&#x2F;strong&gt; — 親クラスでアルゴリズムの骨格を定義し、サブクラスで具体的なステップをオーバーライドする。継承による骨格と詳細の分離を体系化したもの&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Factory Method&lt;&#x2F;strong&gt; — オブジェクトの生成をサブクラスに委ねることで、生成ロジックの拡張を継承で管理する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Abstract Factory&lt;&#x2F;strong&gt; — 関連するオブジェクト群の生成を抽象クラスの階層で管理する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Bridge&lt;&#x2F;strong&gt; — 抽象クラスの階層と実装クラスの階層を分離し、それぞれ独立して拡張可能にする。継承階層を2つに分けることで拡張の柔軟性を確保する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらはいずれも「継承をどう使えば安全に拡張できるか」を体系化したものであり、継承というメカニズムが前提にあって初めて意味を持つパターンです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Go言語の解法_—_継承のない拡張性&quot;&gt;Go言語の解法 — 継承のない拡張性&lt;&#x2F;h3&gt;
&lt;p&gt;Go言語はこの問題の連鎖に対して、根本的に異なる道を選びました。クラス継承を排除し、&lt;strong&gt;暗黙的インターフェースと合成（composition）&lt;&#x2F;strong&gt; によって開放閉鎖原則を実現しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;暗黙的インターフェース&lt;&#x2F;strong&gt; — &lt;code&gt;implements&lt;&#x2F;code&gt;の宣言が不要で、メソッドのシグネチャが合致すれば自動的にインターフェースを満たす。既存の型に触れることなく、新しいインターフェースへ適合させられる。つまり、既存コードを変更せず新しい抽象に対応できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;合成（composition）&lt;&#x2F;strong&gt; — 構造体の埋め込み（embedding）により、既存の型を変更せずに振る舞いを追加できる。継承のような親子の密結合が生まれず、拡張しても既存コードへの影響がない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;継承の副作用が存在しないため、その副作用を管理するためのデザインパターンも必要ありません。これらのパターンが「Go言語では成立しない」のは、解決すべき問題が言語設計の時点で回避されているからです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「参照セマンティクス」を補完するパターン&quot;&gt;「参照セマンティクス」を補完するパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;「参照セマンティクス」がもたらしたもの&quot;&gt;「参照セマンティクス」がもたらしたもの&lt;&#x2F;h3&gt;
&lt;p&gt;OOPの多くの言語は参照セマンティクス&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-reference-semantics-1&quot;&gt;&lt;a href=&quot;#fn-reference-semantics&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を採用しています。これはOOPの設計思想と深く結びついています。OOPでは「このオブジェクトとあのオブジェクトは同一か」というオブジェクトの同一性（identity）が重要であり、基底クラスの参照を通じて派生クラスのメソッドを呼び出すポリモーフィズムも参照なしでは成立しません。参照セマンティクスはOOPにとって必然的な選択でした。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、参照セマンティクスは副作用も伴います。変数に代入してもオブジェクト自体はコピーされず、同じ実体を指す参照が増えるだけです。C言語でいえば、すべての変数がポインタ経由でデータにアクセスしているようなものであり、手続き型言語のグローバル変数と同様に「どこで変更されるか追跡できない」という課題をオブジェクト単位で持ち込んでしまいます。この性質がオブジェクトの複製や状態の保存・復元を厄介な問題にし、それを解決するためのデザインパターンが必要でした。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語は値セマンティクス&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-value-semantics-1&quot;&gt;&lt;a href=&quot;#fn-value-semantics&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を採用しています。OOPを捨てたことで、参照をデフォルトにする必要がなくなりました。値セマンティクスは並行処理の安全性（ゴルーチン間でコピーを渡せば共有状態が減る）と予測可能性（代入の振る舞いが明示的で単純）をもたらします。参照が必要な場合は、ポインタで明示的に指定します。&lt;&#x2F;p&gt;
&lt;p&gt;この「&lt;strong&gt;デフォルトは値、参照が必要なら明示せよ&lt;&#x2F;strong&gt;」という設計方針は、Go言語独自のものではありません。Rustはムーブセマンティクスをデフォルトとし参照は&lt;code&gt;&amp;amp;&lt;&#x2F;code&gt;で明示します。Swiftは構造体（struct）を値型とし、Appleは構造体の使用を推奨しています。OOP以降の現代的な言語設計に共通するトレンドです。&lt;&#x2F;p&gt;
&lt;p&gt;この値セマンティクスにより、以下のパターンが解決しようとした問題は大幅に簡素化されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;既存オブジェクトをコピーして新しいオブジェクトを生成する&quot;&gt;既存オブジェクトをコピーして新しいオブジェクトを生成する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prototype&lt;&#x2F;strong&gt; — 参照セマンティクスの世界では、オブジェクトの「正しいコピー」を作ること自体が設計上の課題であり、Clone()メソッドの実装やプロトタイプ登録といった仕組みが必要だった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語では、構造体の代入がそのままコピーです。&lt;code&gt;b := a&lt;&#x2F;code&gt;と書けばフィールドがすべて複製されます。ポインタを含む構造体の深いコピーには注意が必要ですが、パターンとしての仕組みは不要です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;オブジェクトの内部状態を保存し復元する&quot;&gt;オブジェクトの内部状態を保存し復元する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memento&lt;&#x2F;strong&gt; — Originator（状態を持つ対象）、Memento（保存された状態）、Caretaker（保存を管理する者）の3者構造で、カプセル化を壊さずに状態を保存・復元する仕組みを実現していた&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語では、構造体をそのままコピーすればスナップショットになります。&lt;code&gt;saved := currentState&lt;&#x2F;code&gt;で保存、&lt;code&gt;currentState = saved&lt;&#x2F;code&gt;で復元です。OOPが苦心した「カプセル化を維持しつつ状態を外部に保存する」という問題自体が、値セマンティクスによって解消されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「振る舞い」をオブジェクトに包む制約への処方箋だったパターン&quot;&gt;「振る舞い」をオブジェクトに包む制約への処方箋だったパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;「すべてがオブジェクト」がもたらしたもの&quot;&gt;「すべてがオブジェクト」がもたらしたもの&lt;&#x2F;h3&gt;
&lt;p&gt;OOPの「すべてがオブジェクト」という原則は、データと振る舞いを一体化することで、手続き型言語のようにデータと関数がバラバラに散らばる問題を解消しました。統一的なモデルで設計を語れることは、OOPの大きな功績です。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、ソフトウェアでは要件の変化や文脈の違いに応じて、データはそのままに処理だけを差し替える場面が頻繁に発生します。同じデータを異なる基準でソートしたい、同じリクエスト処理を本番ではDB接続、テストではモックに差し替えたい、といった場面です。OOPの「すべてがオブジェクト」という原則は、このような振る舞いだけを渡したい場面でも、それをオブジェクト（クラス）に包むことを強制しました。関数を1つ渡したいだけなのに、インターフェースを定義し、具象クラスを実装し、そのインスタンスを生成する。この儀式が、以下のパターンを生みました。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語では、第一級関数であり、チャネルとゴルーチンが言語に組み込まれています。振る舞いをオブジェクトに包む必要がなくなったことで、これらのパターンは不要になりました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;アルゴリズムを動的に切り替える&quot;&gt;アルゴリズムを動的に切り替える&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Strategy&lt;&#x2F;strong&gt; — Strategyインターフェースを定義し、各アルゴリズムを具象クラスとして実装し、コンテキストオブジェクトに注入するという手順が必要だった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Javaでは、ソート順を差し替えるだけでもインターフェースと具象クラスが必要です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&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; Strategyインターフェース&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; SortStrategy&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-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sort&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;int&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; data&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;&#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; 具象クラス：昇順&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; AscendingSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; SortStrategy&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-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sort&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;int&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; data&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-comment z-comment&quot;&gt; &#x2F;* 昇順ソート *&#x2F;&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;&#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; 具象クラス：降順&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; DescendingSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; SortStrategy&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-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sort&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;int&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; data&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-comment z-comment&quot;&gt; &#x2F;* 降順ソート *&#x2F;&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;&#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; コンテキストクラス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Sorter&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-storage z-modifier z-storage z-type&quot;&gt;    private SortStrategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; strategy&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-entity z-name z-function&quot;&gt;    Sorter&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;SortStrategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; strategy&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-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;strategy&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; strategy&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; execute&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;int&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; data&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;        strategy&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;sort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 使用側&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Sorter&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Sorter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; AscendingSort&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;s&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;execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&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;Go言語では第一級関数をサポートしています。ソート処理を行う関数が、ソート順を関数として受け取るだけで済みます。&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; ソート順を関数として受け取る。クラスもインターフェースも不要&lt;&#x2F;span&gt;&lt;&#x2F;span&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; executeSort&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;data&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;int&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; less&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&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;i&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; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&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; bool&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;    sort&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;Slice&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; less&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;&#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; 関数を変数に代入するだけで「具象クラス」に相当する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;ascending&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&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;i&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; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&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; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;j&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;descending&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&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;i&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; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&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; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&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;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;j&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;&#x2F;&#x2F; 使用側&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;executeSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ascending&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;Javaでは振る舞いを差し替えるためにインターフェース、具象クラス、コンテキストクラスの3層が必要でした。Go言語では関数を引数として渡すだけで同じことが実現できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;操作の実行・取り消し・キューイングを可能にする&quot;&gt;操作の実行・取り消し・キューイングを可能にする&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Command&lt;&#x2F;strong&gt; — リクエストをオブジェクトとしてカプセル化し、操作をデータとして扱えるようにしていた&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語では関数とクロージャがCommandオブジェクトの役割を果たします。関数をスライスに格納してキューイングする、クロージャで実行時のコンテキストを閉じ込める、といった操作が言語機能として自然に書けます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;データ構造に新しい操作を追加する&quot;&gt;データ構造に新しい操作を追加する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visitor&lt;&#x2F;strong&gt; — データ構造に対する操作を追加したいとき、操作をVisitorオブジェクトに包み、ダブルディスパッチ（accept&#x2F;visit）で呼び出す必要があった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語ではtype switchにより、型に応じた処理分岐を直接記述できます。操作をオブジェクトに包む必要も、ダブルディスパッチのような間接的な仕組みも不要です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;オブジェクトの状態変化を通知する&quot;&gt;オブジェクトの状態変化を通知する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observer&lt;&#x2F;strong&gt; — Subject&#x2F;Observerインターフェースを定義し、登録・通知・解除のメカニズムを実装する必要があった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;エラーイベントが発生したら、ログ出力とアラート送信の2つの処理に通知する例で対比してみます。
Javaでは、Observerインターフェースの定義、Subject（EventSource）への登録メカニズム、通知ループの実装が必要です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&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; Observerインターフェース&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Observer&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-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; update&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;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&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;&#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; 具象クラス：ログ出力&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; LogObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Observer&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-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; update&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;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&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;        System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&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;println&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;quot;Logger: &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-source&quot;&gt; event&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 具象クラス：アラート送信&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; AlertObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Observer&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-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; update&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;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&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-entity z-name z-function&quot;&gt;        sendAlert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;event&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Subject：Observerの登録と通知を管理する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; EventSource&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-storage z-modifier z-storage z-type&quot;&gt;    private List&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt; new ArrayList&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&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 class=&quot;z-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; addObserver&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;Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; o&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&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;add&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;o&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-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; notifyObservers&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;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&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;        for&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;Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; o&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&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;            o&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;update&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;event&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;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;&#x2F;&#x2F; 使用側：Observerを登録し、イベントを通知する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;EventSource&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; source&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; EventSource&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;source&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;addObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; LogObserver&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;source&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;addObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; AlertObserver&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;source&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;notifyObservers&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;quot;error occurred&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;Go言語では、チャネルとゴルーチンがこの役割を担います。Observerをチャネルのスライスで管理し、動的に登録できます。&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; チャネル：Observerへの通知経路をスライスで管理&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;observers&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-keyword z-storage z-type&quot;&gt;chan string&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;&#x2F;&#x2F; Observer登録：チャネルを作成し、ゴルーチンで待ち受ける&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;logCh&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; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;chan string&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;observers&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; append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; logCh&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;go func&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;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; logCh&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;        fmt&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;Println&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;quot;Logger:&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; event&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;span class=&quot;z-source&quot;&gt;alertCh&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; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;chan string&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;observers&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; append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; alertCh&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;go func&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;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; alertCh&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-entity z-name z-function&quot;&gt;        sendAlert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;event&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 全Observerに通知&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; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&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;    ch&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;error occurred&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Javaではインターフェース定義、登録メカニズム、通知ループが必要でした。Go言語ではチャネルが型安全な通知メカニズムとなり、ゴルーチンが通知を受け取る側の並行処理を自然に表現します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;本記事では、Go言語の3つの設計方針がGoFのデザインパターンをどのように不要にしたかを確認しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Go言語の設計方針&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;Template Method, Factory Method, Abstract Factory, Bridge&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;参照セマンティクスではなく値セマンティクスをデフォルトに&lt;&#x2F;td&gt;&lt;td&gt;Prototype, Memento&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるように&lt;&#x2F;td&gt;&lt;td&gt;Strategy, Command, Visitor, Observer&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;これらのパターンが不要になったのは、パターンの設計思想が間違っていたからではありません。OOPの制約の中で生まれた処方箋が、制約そのものを取り除いたGo言語では必要なくなった、ということです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、GoFの23パターンすべてがOOPの制約に起因するわけではありません。次回は、言語やパラダイムに依存しない普遍的な設計原則として、現代でも有用なパターンを検討します。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-reference-semantics&quot;&gt;
&lt;p&gt;参照セマンティクス（reference semantics）とは、変数への代入がオブジェクトの参照（ポインタ）をコピーする振る舞いのこと。代入先を変更すると、元のオブジェクトも影響を受ける。Java、Pythonなどが採用している（C#はクラスが参照型、構造体が値型と区別している）。 &lt;a href=&quot;#fr-reference-semantics-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-value-semantics&quot;&gt;
&lt;p&gt;値セマンティクス（value semantics）とは、変数への代入がデータそのものをコピーする振る舞いのこと。代入先を変更しても、元のデータには影響しない。Go言語の構造体やC言語の構造体が採用している。 &lt;a href=&quot;#fr-value-semantics-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">GoFの23パターンをGo言語の視点から再検討します。クラス継承の副作用への処方箋だったもの、参照セマンティクスを補完するもの、振る舞いをオブジェクトに包む制約への処方箋だったもの。</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(1) — OOPのパラダイムシフトとGoFの誕生</title>
        <published>2026-04-01T05:58:00+09:00</published>
        <updated>2026-04-01T05:58:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/01-paradigm-shift/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/01-paradigm-shift/</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;04&amp;#x2F;gof-design-patterns&amp;#x2F;01-paradigm-shift&amp;#x2F;cover.webp?h=3fe18a08fd8d2440cfce&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&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;自宅の本棚の整理をしていて、『&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;4bW36Po&quot;&gt;Java言語で学ぶデザインパターン入門&lt;&#x2F;a&gt;第2版』(結城浩著)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-affiliate-1&quot;&gt;&lt;a href=&quot;#fn-affiliate&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を見つけました。「今どきJava言語かね」
と思い調べてみると、5年程前に第3版が出版されていました。&lt;&#x2F;p&gt;
&lt;p&gt;「そう言えば、今どきの言語でデザインパターンってどうなんだ？」と考察していました。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、なぜ脱オブジェクト指向プログラミング（以降、OOP）のパラダイムシフトが起きたのか、そしてGoFの23のデザインパターンをGo言語ではどう扱うべきかを検討し考察してみます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;手続き型プログラミングの限界&quot;&gt;手続き型プログラミングの限界&lt;&#x2F;h2&gt;
&lt;p&gt;1960年代から1980年代にかけて、ソフトウェア開発の主流は手続き型プログラミングでした。C言語やFortranに代表されるこのパラダイムでは、データと手続き（関数）は分離して管理されます。プログラムの規模が小さいうちは問題になりませんが、規模が大きくなるにつれて、どの関数がどのデータを操作するのかを追跡することが困難になっていきました。&lt;&#x2F;p&gt;
&lt;p&gt;当時仕事ではメインフレーム中心で私の職場ではPL&#x2F;Iを使っていましたが、規模を大きくしないためかバッチ指向のデザインが好まれていました。
そのため1つ1つは短いプログラムですが、内部ではグローバル変数への依存、関数間の暗黙的なデータ受け渡しが行われていました。そして短いプログラムでも、結局ファイルを介してバッチストリーム全体がストレージ共有をしているので、変更の影響範囲が予測できないという問題が深刻化しました。&lt;&#x2F;p&gt;
&lt;p&gt;やがて、1990年代に入るとWindows&#x2F;Macintoshに加えて、IBMのOS&#x2F;2、SunやHPのワークステーションが業務で使えるレベルのシステムとなり、「ダウンサイジング」の波が業務アプリケーションの世界にも押し寄せました。この問題はさらに致命的になりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OOPというパラダイムシフト&quot;&gt;OOPというパラダイムシフト&lt;&#x2F;h2&gt;
&lt;p&gt;OOP（オブジェクト指向プログラミング）は、手続き型プログラミングにおけるデータと手続きの分離がもたらす複雑さに対するパラダイムシフトでした。データとそれを操作する手続きを「オブジェクト」として一体化し、カプセル化によって内部状態を保護する。オブジェクト間はメッセージパッシングで協調し、継承によってコードを再利用する。Simula（1967年）で芽生え、Smalltalk（1980年）で確立されたこの思想は、1990年代にC++やJavaの普及とともに主流となりました。&lt;&#x2F;p&gt;
&lt;p&gt;OOPの普及を決定づけたのは、ダウンサイジングがもたらしたGUIクライアントの台頭です。Windowsの普及により、ソフトウェアはウィンドウ、ボタン、メニューといった視覚的な部品で構成されるようになりました。これらのUI部品は、状態を持ち、イベントに応答し、階層的に組み合わされる — まさにオブジェクトとしてモデル化するのに適した対象でした。GUIツールキットはOOPの実践的な成功例となり、OOPこそがソフトウェア開発の正しいアプローチであるという認識を広めました。&lt;&#x2F;p&gt;
&lt;p&gt;一方でOOPは、カプセル化、継承、ポリモーフィズムという新しい概念を持ち込んだために、手続き型言語で機能分割しかやって来なかった当時の開発者たちに「OOPではどうコードを書くべきなのか」と悩ませることになりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;GoFデザインパターンの誕生&quot;&gt;GoFデザインパターンの誕生&lt;&#x2F;h2&gt;
&lt;p&gt;この状況の中で、1994年にGoF（Gang of Four）&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-gof-1&quot;&gt;&lt;a href=&quot;#fn-gof&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;が『&lt;strong&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;&#x2F;strong&gt;』を出版しました。GoFはオブジェクト指向設計で繰り返し現れる23のパターンを、生成（Creational）5種、構造（Structural）7種、振舞（Behavioral）11種の3つに分類して体系化しました。これらのパターンは、当時の開発者にとって「OOPでよいコードを書くためのお手本」として受け入れられました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&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;Creational（生成）&lt;&#x2F;td&gt;&lt;td&gt;Abstract Factory&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;Builder&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;Factory Method&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;Prototype&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;Singleton&lt;&#x2F;td&gt;&lt;td&gt;インスタンスが1つだけであることを保証&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Structural（構造）&lt;&#x2F;td&gt;&lt;td&gt;Adapter&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;Bridge&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;Composite&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;Decorator&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;Facade&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;Flyweight&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;Proxy&lt;&#x2F;td&gt;&lt;td&gt;他のオブジェクトへのアクセス制御する代理オブジェクト&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Behavioral（振舞）&lt;&#x2F;td&gt;&lt;td&gt;Chain of Responsibility&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;Command&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;Interpreter&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;Iterator&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;Mediator&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;Memento&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;Observer&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;State&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;Strategy&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;Template Method&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;Visitor&lt;&#x2F;td&gt;&lt;td&gt;データ構造と処理を分離し、新しい処理を追加しやすくする&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;新たなパラダイムシフト_—_なぜGoogleはOOPを捨てたのか&quot;&gt;新たなパラダイムシフト — なぜGoogleはOOPを捨てたのか&lt;&#x2F;h2&gt;
&lt;p&gt;GoFが出版されてから10年以上が経った2007年、Googleの中で新しい言語の設計が始まりました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-go-creators-1&quot;&gt;&lt;a href=&quot;#fn-go-creators&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;新言語の開発に踏み切った背景には、GoogleのC++コードベースの深刻な問題がありました。数百万行規模のコードではビルドに数十分から数時間を要し、複雑な依存関係の管理は開発者の大きな負担になっていました。C++の持つ豊富な機能 — テンプレート、多重継承、演算子オーバーロード — は、大規模なチーム開発においてコードの可読性を損ない、新しいメンバーの参入障壁を高めていました。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語の設計者たちが出した答えは、複雑さを足すのではなく引くことでした。2009年にオープンソースとして公開されたGo言語は、OOPの中核を意図的に排除し、代わりに以下の設計方針を採用しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;クラス継承を排除し、合成（composition）と暗黙的インターフェースで代替した&lt;&#x2F;li&gt;
&lt;li&gt;参照セマンティクスではなく値セマンティクスをデフォルトにした&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-semantics-1&quot;&gt;&lt;a href=&quot;#fn-semantics&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるようにした&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;確かに近年はC++&#x2F;JavaのようなOOPでなく、次のような言語を選択するシーンが私自身も増えています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Python — クラスも書けるが、関数だけでも十分に実用的&lt;&#x2F;li&gt;
&lt;li&gt;Ruby — 実は言語設計は徹底的にOOP（全てがオブジェクト）。ただし実際の使われ方は柔軟&lt;&#x2F;li&gt;
&lt;li&gt;JavaScript — そもそもクラスベースではなくプロトタイプベース。ES6のclassは後付けの構文糖&lt;&#x2F;li&gt;
&lt;li&gt;TypeScript — JavaScriptに型を足したもの。OOPと関数型のどちらでも自然に書ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらはOOPですがマルチパラダイムで、OOPじゃないパラダイムでもコードが書けます。&lt;&#x2F;p&gt;
&lt;p&gt;では、Go言語はOOPなのでしょうか。Go言語にはメソッドやインターフェースがあり、カプセル化も実現できます。しかし、クラスや継承はありません。Go言語のFAQでは「Yes and no」と回答されています。Go言語はOOPの有用な部分（カプセル化、多態性）を残しつつ、複雑さの元凶（継承、型階層）を切り捨てた言語です。上記のような言語からさらにOOPを薄めたものと言えます。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語の登場は、OOPに続く新たなパラダイムシフトの象徴です。&lt;&#x2F;p&gt;
&lt;p&gt;ここで1つの疑問が浮かびます。GoFのデザインパターンは「OOPでよいコードを書くためのお手本」として受け入れられました。しかし、Go言語はそのOOPの中核 — 継承、型階層、参照セマンティクス — を排除しています。もしGoFのパターンが本当にOOPの仕組みに依存したものであるなら、Go言語ではそれらのパターンは成立しないはずです。逆に、パターンの中に言語やパラダイムに依存しない普遍的な設計原則が含まれているなら、Go言語でも形を変えて生き残るはずです。&lt;&#x2F;p&gt;
&lt;p&gt;次回は、GoFの23のパターンをGo言語の視点から1つずつ再検討し、この仮説を検証していきます。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-affiliate&quot;&gt;
&lt;p&gt;このリンクはAmazonアソシエイトのリンクです。 &lt;a href=&quot;#fr-affiliate-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-gof&quot;&gt;
&lt;p&gt;Gang of Four（GoF）は、Erich Gamma、Richard Helm、Ralph Johnson、John Vlissidesの4人の通称。 &lt;a href=&quot;#fr-gof-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-go-creators&quot;&gt;
&lt;p&gt;主導したのはRob Pike（UNIXやPlan 9の開発者）、Ken Thompson（UNIXの共同開発者）、Robert Griesemerの3人です。 &lt;a href=&quot;#fr-go-creators-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-semantics&quot;&gt;
&lt;p&gt;参照セマンティクス（reference semantics）とは、変数への代入がオブジェクトの参照（ポインタ）をコピーする振る舞いのこと。値セマンティクス（value semantics）とは、変数への代入がデータそのものをコピーする振る舞いのこと。 &lt;a href=&quot;#fr-semantics-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">手続き型からOOPへのパラダイムシフト、そしてOOPの不完全さから生まれたGoFデザインパターン。なぜGoogleはOOPを捨ててGo言語を作ったのか。その背景を整理します。</summary>
        </entry><entry xml:lang="en">
        <title>「AIを使え」の先にある本当の問題 ── エンジニア育成のパラドックス</title>
        <published>2026-03-24T00:00:00+00:00</published>
        <updated>2026-03-24T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/ai-workforce-design-paradox/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/ai-workforce-design-paradox/</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;03&amp;#x2F;ai-workforce-design-paradox&amp;#x2F;cover.webp?h=89b26b81d4428bd72bde&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;はじめに_──_「AIを使わない人は出世できない」の違和感&quot;&gt;はじめに ── 「AIを使わない人は出世できない」の違和感&lt;&#x2F;h2&gt;
&lt;p&gt;最近、AI時代のキャリアに関する記事を立て続けて目にしました。AccentureのCEOは「AIを使わない社員は昇進できない」と断言しており、New York Timesはプログラマーの仕事が根底から変わりつつある現場をルポルタージュしています。一方で、AIがジュニアポジションそのものを消滅させているという報道もあります。&lt;&#x2F;p&gt;
&lt;p&gt;どれも的を射ていますが、どれも問題の核心を突いていない気がしています。&lt;&#x2F;p&gt;
&lt;p&gt;ソフトウェアエンジニアとして30年以上コードを書いてきた立場から言えば、「AIを使える人」ではなく、「AIを前提とした開発プロセスを設計できる人」でなければ、もはや価値を発揮できないと考えています。そして、その人材をどう育てるかという問いに、誰もまだ答えを出せていません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Accenture_CEOの発言_──_正しいが、すでに一歩遅い&quot;&gt;Accenture CEOの発言 ── 正しいが、すでに一歩遅い&lt;&#x2F;h2&gt;
&lt;p&gt;2025年、AccentureのCEOであるJulie Sweetは、AI活用を昇進の条件とする方針を明確に打ち出しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;finance.yahoo.com&#x2F;news&#x2F;want-promotion-accenture-ceo-says-063000196.html&quot;&gt;
&lt;p&gt;&quot;If you want to get promoted, you&#x27;ve got to do the things that we do.&quot;&lt;&#x2F;p&gt;
&lt;footer&gt;— Julie Sweet, CEO of Accenture（2025年、Yahoo Finance）&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;AIを使わない社員は昇進させない。3年かけて技術を浸透させた上での方針だといいます。Accentureは30億ドル規模のAI投資と8万人のAI人材育成を進めており、経営者としての本気度は疑いようがありません。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、CEOの発言そのものは「AIを使え」という号令です。問題は、AIツールを日常的に「使う」こと自体が、もはやスキルと呼ぶには陳腐化しつつあるということです。ChatGPTにプロンプトを投げて回答を得ることは、すでにエンジニアに限らず多くの人が日常的にやっています。上手なプロンプトを書くことが評価されたのは数年前です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;問われるべきは「AIを使えるか」ではなく、「AIを組み込んだ開発プロセスを設計できるか」です。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;プロンプトを書く能力ではありません。開発チーム全体のワークフローの中で、どこにAIを配置し、どこに人間の判断を残し、どのような検証プロセスを組むかを設計する能力。それこそが、今後のソフトウェア開発における差別化要因になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;New_York_Timesが描いた現場_──_「判断する仕事」への転換&quot;&gt;New York Timesが描いた現場 ── 「判断する仕事」への転換&lt;&#x2F;h2&gt;
&lt;p&gt;2026年3月、Clive ThompsonはNew York Times Magazineで、AIによってプログラマーの仕事がどう変わったかを70人以上の開発者への取材を通じて描きました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2026&#x2F;03&#x2F;12&#x2F;magazine&#x2F;ai-coding-programming-jobs-claude-chatgpt.html&quot;&gt;
&lt;p&gt;&quot;A coder is now more like an architect than a construction worker.&quot;&lt;&#x2F;p&gt;
&lt;footer&gt;— Boris Cherny, Head of Claude Code, Anthropic（2026年3月12日、The New York Times Magazine）&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;開発者の仕事は「コードを書く」から「判断する」へと移行しています。AnthropicのClaude Code責任者であるBoris Cherny自身、コードベースへの貢献の100%をClaudeに書かせているといいます。Googleでは30人必要だったチームが3–6人で済むようになりました。Amazonでは、以前8時間かかったデバッグをAIが15分で完了させました。&lt;&#x2F;p&gt;
&lt;p&gt;ここで重要なのは、生産性が上がったのは単にAIツールを「使った」からではないということです。&lt;strong&gt;AIエージェントをどう配置し、どう監督し、どう検証するかという「開発プロセスの設計」が的確だったからこそ、生産性が劇的に向上しました。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Googleのプロダクト担当シニアディレクターであるRyan Salvaは、ソフトウェア開発におけるAI活用についてこう語っています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2026&#x2F;03&#x2F;12&#x2F;magazine&#x2F;ai-coding-programming-jobs-claude-chatgpt.html&quot;&gt;
&lt;p&gt;&quot;As an engineer, I care less that the models are really good at producing the right result the first time. I care much more that there are validation steps in place so that it eventually gets the perfect or the right answer.&quot;&lt;&#x2F;p&gt;
&lt;footer&gt;— Ryan Salva, Senior Director of Product, Google（2026年3月12日、The New York Times Magazine）&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;AIの出力を最初から信用するのではなく、検証ステップを設計すること。これはまさに「AIを使う」ではなく「AIを前提とした開発プロセスの設計」の話です。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、ここで見落としてはならない点があります。ソフトウェア開発は、検証という観点ではきわめて恵まれた分野です。ユニットテスト、インテグレーションテスト、CI&#x2F;CDパイプラインといったテスティングの仕組みが充実しており、「Test First」という手法が業務として浸透して20年以上経っています。つまり、AIの出力を機械的に検証するインフラが、すでに存在しているのです。&lt;&#x2F;p&gt;
&lt;p&gt;それでも、Salvaが言うような「検証ステップを設計する」ことができるエンジニアは限られています。テストを書くことと、何をテストすべきかを設計することは、まったく別の能力です。これだけ検証の仕組みが整った分野ですら、この状況なのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;消えるジュニアポジション_──_育成のパラドックス&quot;&gt;消えるジュニアポジション ── 育成のパラドックス&lt;&#x2F;h2&gt;
&lt;p&gt;ここまでなら「AIを前提とした開発プロセスの設計力を身につけよう」で話は終わります。しかし、CNBCの2025年11月の報道が、もっと根深い問題を突きつけています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.cnbc.com&#x2F;2025&#x2F;11&#x2F;20&#x2F;why-ai-may-kill-career-advancement-for-many-young-workers.html&quot;&gt;
&lt;p&gt;Companies are replacing entry-level jobs with artificial intelligence — and, in the process, are upending the traditional route to career advancement for many young, white-collar workers.&lt;&#x2F;p&gt;
&lt;footer&gt;— CNBC（2025年11月20日）&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;New York Timesの記事でも、Stanford Digital Economy LabのErik Brynjolfssonの研究が引用されています。AI露出度の高い職種における若手プログラマーの雇用は2022年以降16%減少した一方、ベテランプログラマーの雇用には有意な減少がありませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;ここに&lt;strong&gt;育成のパラドックス&lt;&#x2F;strong&gt;があります。&lt;&#x2F;p&gt;
&lt;p&gt;「AIを前提とした開発プロセスの設計力」は、高次のスキルです。それは長年の実務経験を通じて、何が良いコードで何が悪いコードかを判断できるようになって初めて身につきます。New York Timesの記事で、Point Health A.I.のエンジニアPia Torainはこう証言しています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2026&#x2F;03&#x2F;12&#x2F;magazine&#x2F;ai-coding-programming-jobs-claude-chatgpt.html&quot;&gt;
&lt;p&gt;&quot;I realized that it was just four months that I was prompting hundreds, 500 prompts a day, that I started to lose my ability to code.&quot;&lt;&#x2F;p&gt;
&lt;footer&gt;— Pia Torain, Software Engineer, Point Health A.I.（2026年3月12日、The New York Times Magazine）&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;わずか4ヶ月のAI依存で、コーディング能力が衰えたといいます。入社2年目の若手エンジニアの証言です。&lt;&#x2F;p&gt;
&lt;p&gt;整理するとこうなります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;AIを前提とした開発プロセスの設計力を持つエンジニアが求められている&lt;&#x2F;li&gt;
&lt;li&gt;その能力には、実務で培った深い判断力が必須である&lt;&#x2F;li&gt;
&lt;li&gt;しかし、判断力を養うためのジュニアポジション自体がAIに置き換えられている&lt;&#x2F;li&gt;
&lt;li&gt;さらに、AIに頼りすぎると既存のスキルすら失われる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;つまり、&lt;strong&gt;「判断する力」を育てる場が消えつつあるのに、「判断する力」がこれまで以上に求められている&lt;&#x2F;strong&gt;。これが育成のパラドックスです。&lt;&#x2F;p&gt;
&lt;p&gt;もちろん、シミュレーション環境での訓練やAIの出力を教材として活用する新しい学習方法も模索されています。しかし、それらはまだ実証段階であり、従来の「実務を通じた学び」に代わるものとして確立されたとは言えません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;30年コードを書いてきた者として&quot;&gt;30年コードを書いてきた者として&lt;&#x2F;h2&gt;
&lt;p&gt;私はエンジニアとして30年以上コードを書いてきました。日本のIT業界では、ある程度の経験を積むとコーディングから離れ、PMやアーキテクトを目指すのが「正しいキャリアパス」とされてきました。コードは単価の安い若手やベンダー、海外リソースが書くもの。上流工程に行くことが「上がり」だという空気です。&lt;&#x2F;p&gt;
&lt;p&gt;私はその空気に抗ってきました。コードが書けないPMやアーキテクトに、本当に正しい判断ができるのか。お客様の業務を理解するのは当然ですが、その前提としてエンジニアとしてのスキルが必要で、それはPowerPointを操る能力ではないはずです。だから意図的に、自分の手でコードを書き続ける仕事が来るように動いてきました。&lt;&#x2F;p&gt;
&lt;p&gt;振り返ると、これは育成のパラドックスに対する、個人レベルでの答えの1つだったのかもしれません。&lt;strong&gt;判断力の源泉となるスキルを、意図的に手放さない。&lt;&#x2F;strong&gt; 組織がどう評価しようと、自分の判断力を支える基盤を維持し続けるという選択です。&lt;&#x2F;p&gt;
&lt;p&gt;New York Timesの記事で、Point Healthの共同創業者Rachel Gollubはこう語っています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2026&#x2F;03&#x2F;12&#x2F;magazine&#x2F;ai-coding-programming-jobs-claude-chatgpt.html&quot;&gt;
&lt;p&gt;&quot;People were all like, &#x27;You&#x27;re losing all your ability to code.&#x27;&quot;&lt;&#x2F;p&gt;
&lt;footer&gt;— Rachel Gollub, Co-founder, Point Health（2026年3月12日、The New York Times Magazine）&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;新しい抽象化が登場するたびに「能力を失う」と言われてきました。しかし今回の問題は、過去の抽象化とは本質的に異なります。PythonがC言語を置き換えたとき、メモリ管理のスキルは不要になりましたが、代わりにPythonのスキルが求められました。学ぶべき対象が変わっただけです。&lt;&#x2F;p&gt;
&lt;p&gt;今回起きているのは &lt;strong&gt;「スキルを学ぶプロセスそのものの消滅」&lt;&#x2F;strong&gt; です。しかし、組織的な解がまだ見えない以上、個人としてできることは同じなのだろうと思います。AIが書いたコードを判断するために、自分自身がコードを書く力を意図的に維持し続けること。それは30年前にPMへの「上がり」を拒んだのと、構造としては同じ選択です。&lt;&#x2F;p&gt;
&lt;p&gt;だから、この時代にエンジニアを目指す若い人に伝えたいことがあります。AIを使うことは構いません。しかし、自力で開発できる力は必ず身につけてください。会社がその機会を与えてくれることを期待してはいけません。ジュニアポジションが消えているなら、自分で作ればいいのです。個人開発でもOSSへの貢献でも、コードを書く機会はいくらでもあります。会社の育成制度に自分のキャリアを委ねること自体が、もはやリスクです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;では、どうするか&quot;&gt;では、どうするか&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;組織としては、エンジニア育成の設計そのものを変える必要があります。&lt;&#x2F;strong&gt; ジュニアの仕事が「コードを書く」から「AIの出力を検証する」に変わるなら、検証力を体系的に鍛える仕組みが必要です。「AIを使え」という号令だけでは、中長期的にAIの出力を正しく判断できるエンジニアが枯渇するリスクを孕んでいます。ただし、その具体的な方法論は、正直に言えばまだ誰も確立できていません。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;一方、エンジニア個人としては、答えは明快です。&lt;&#x2F;strong&gt; 前のセクションで書いた通り、自分の手でコードを書く力を維持し続けること。AIを使うことと、AIなしでも書ける力を持つことは矛盾しません。会社の育成制度がこのパラドックスに追いつくのを待っている余裕はないのです。&lt;&#x2F;p&gt;
&lt;p&gt;New York TimesのAnil Dashの言葉が示唆的です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2026&#x2F;03&#x2F;12&#x2F;magazine&#x2F;ai-coding-programming-jobs-claude-chatgpt.html&quot;&gt;
&lt;p&gt;&quot;In coding, L.L.M.s take away the drudgery and leave the human, soulful parts to you.&quot;&lt;&#x2F;p&gt;
&lt;footer&gt;— Anil Dash, Programmer and Tech Executive（2026年3月12日、The New York Times Magazine）&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;コーディングにおいて、LLMは退屈な作業を奪い、人間的で魂のある部分を残してくれる。美しい言葉です。しかし、その「魂のある部分」を担える人間を、どう育てるのでしょうか。退屈な作業を経験せずに、魂のある判断ができるようになるのでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;この問いに対する答えが、AI時代のソフトウェア開発における最も重要な課題だと、私は考えています。&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;The New York Times Magazine. &quot;Coding After Coders: The End of Computer Programming as We Know It&quot; &lt;code&gt;https:&#x2F;&#x2F;www.nytimes.com&#x2F;2026&#x2F;03&#x2F;12&#x2F;magazine&#x2F;ai-coding-programming-jobs-claude-chatgpt.html&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Yahoo Finance. &quot;Accenture CEO says failure to use AI will cost workers a promotion—or their job&quot; &lt;code&gt;https:&#x2F;&#x2F;finance.yahoo.com&#x2F;news&#x2F;want-promotion-accenture-ceo-says-063000196.html&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;CNBC. &quot;Why AI may kill career advancement for many young workers&quot; &lt;code&gt;https:&#x2F;&#x2F;www.cnbc.com&#x2F;2025&#x2F;11&#x2F;20&#x2F;why-ai-may-kill-career-advancement-for-many-young-workers.html&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">ジュニアポジションがAIに置き換えられる今、エンジニアの「判断する力」を育てる場が消えつつあるのに「判断する力」がこれまで以上に求められる。30年コードを書き続けてきた筆者が、この育成のパラドックスについて考察します。</summary>
        </entry><entry xml:lang="en">
        <title>無料で始める Cloudflare セキュリティ対策</title>
        <published>2026-03-23T00:00:00+00:00</published>
        <updated>2026-03-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/cloudflare-free-security/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/cloudflare-free-security/</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;03&amp;#x2F;cloudflare-free-security&amp;#x2F;cover.webp?h=9bfc915254c8cd5bf47d&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;公開翌日に何が起きたか&quot;&gt;公開翌日に何が起きたか&lt;&#x2F;h2&gt;
&lt;p&gt;先日の記事で紹介した生成AIを使った&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ask.codedchords.dev&quot;&gt;Ask&lt;&#x2F;a&gt; ページを公開した翌日、CloudflareのObservabilityを確認したところ、攻撃と思われるリクエストが並んでいました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET &#x2F;.env&lt;&#x2F;code&gt; — 環境変数ファイルの探索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;checkout&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;plans&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;signup&lt;&#x2F;code&gt; — SaaS系パスの総当たり&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;wp-login&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;wp-admin&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;xmlrpc.php&lt;&#x2F;code&gt; — WordPress管理画面の探索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;api&#x2F;v1&#x2F;stripe&#x2F;config.js&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;api&#x2F;v2&#x2F;payment&#x2F;keys.js&lt;&#x2F;code&gt; — 決済APIの設定ファイル探索（Stripeはオンライン決済プラットフォーム）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;config.php&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;api&#x2F;system&#x2F;info&lt;&#x2F;code&gt; — サーバー情報の収集&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;主にWordPressなどのCMSやStripeなどの決済サービスを狙ったスキャンです。静的サイト＋Workerという構成なのでそんなサービスは乗せていないのですが。公開されているエンドポイントに対してよく狙われる既知のパスを片っ端から叩いているのでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;実害はありませんが、放置するのも気持ちが悪いですし、Workers AIのNeuronsを無駄に消費されるのは避けたいところです。Cloudflareの無料プランのセキュリティ機能で対策しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策1:_Bot_Fight_Mode&quot;&gt;対策1: Bot Fight Mode&lt;&#x2F;h2&gt;
&lt;p&gt;最も手軽な対策です。Cloudflareダッシュボードの &lt;strong&gt;Security &amp;gt; Bots&lt;&#x2F;strong&gt; から、ワンクリックで有効化できます。&lt;&#x2F;p&gt;
&lt;p&gt;Bot Fight ModeはCloudflareが持つボットの行動パターンデータベースを使い、自動化されたアクセスを検出して計算コストの高いチャレンジを返します。検索エンジンのクローラーなど検証済みの正当なボットは通過させる仕組みです。&lt;&#x2F;p&gt;
&lt;p&gt;設定はON&#x2F;OFFだけで、細かなチューニングは有料プラン（Super Bot Fight Mode）の機能になります。それでも、汎用的なスキャンボットの大半はこれで弾けます。&lt;&#x2F;p&gt;
&lt;p&gt;注意点として、Bot Fight Modeは外部サービスからのWebhookやRSSリーダーのフィード取得など、正当な自動アクセスもブロックする場合があります。無料プランではWAFルールによるバイパス（Skip）ができないため、これらのサービスに影響が出た場合はBot Fight Mode自体を無効にする必要があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策2:_WAF_カスタムルール&quot;&gt;対策2: WAF カスタムルール&lt;&#x2F;h2&gt;
&lt;p&gt;Bot Fight Modeをすり抜けるアクセスに対しては、WAF（Web Application Firewall）のカスタムルールで対処します。無料プランでは5つまでルールを作成できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ルール1:_許可パスの制限（ホワイトリスト）&quot;&gt;ルール1: 許可パスの制限（ホワイトリスト）&lt;&#x2F;h3&gt;
&lt;p&gt;最も効果が高いルールを最優先に配置します。ask.codedchords.devは &lt;code&gt;&#x2F;&lt;&#x2F;code&gt;（フロントエンド）と &lt;code&gt;&#x2F;api&#x2F;&lt;&#x2F;code&gt;（Workers API）しか使わないので、それ以外を全てブロックします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;Expression&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(http.host eq &amp;quot;ask.codedchords.dev&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;and not (http.request.uri.path eq &amp;quot;&#x2F;&amp;quot; or http.request.uri.path contains &amp;quot;&#x2F;api&#x2F;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Actionは &lt;strong&gt;Block&lt;&#x2F;strong&gt;、Place atは &lt;strong&gt;First&lt;&#x2F;strong&gt; に設定します。&lt;&#x2F;p&gt;
&lt;p&gt;「正当なパスだけを許可する」ホワイトリスト方式なので、攻撃者がどんなパスを試してもすり抜けられません。ただし、対象サイトの構成を把握している必要があります。新しいパスを追加した際にルールの更新を忘れると自分自身のコンテンツがブロックされるため、サイト構成を変更したらルールも見直してください。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ルール2:_スキャンパスの遮断（ブラックリスト）&quot;&gt;ルール2: スキャンパスの遮断（ブラックリスト）&lt;&#x2F;h3&gt;
&lt;p&gt;ルール1はaskサブドメイン限定なので、ドメイン全体に適用する汎用ルールも設定します。WordPressやphpMyAdminなど、よく狙われるパスへのアクセスを一括でブロックします。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security &amp;gt; Security rules &amp;gt; Create rule&lt;&#x2F;strong&gt; から、以下のExpressionを設定します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;Expression&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(http.request.uri.path contains &amp;quot;.env&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-login&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-admin&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;xmlrpc.php&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;phpmyadmin&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-content&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-includes&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Actionは &lt;strong&gt;Block&lt;&#x2F;strong&gt; です。&lt;&#x2F;p&gt;
&lt;p&gt;このルールはサイトの構成に依存しないため、Cloudflareで管理しているドメイン全体に適用できます。WordPressを使っていないサイトであれば、デメリットはありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策3:_Rate_Limiting&quot;&gt;対策3: Rate Limiting&lt;&#x2F;h2&gt;
&lt;p&gt;Bot Fight ModeとWAFルールを通過したリクエストに対する最後の砦です。同一IPからの過剰なリクエストを制限します。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security &amp;gt; Security rules &amp;gt; Rate limiting rules&lt;&#x2F;strong&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;対象&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;http.host eq &quot;ask.codedchords.dev&quot;&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;IP&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;レート&lt;&#x2F;td&gt;&lt;td&gt;10リクエスト &#x2F; 10秒&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Action&lt;&#x2F;td&gt;&lt;td&gt;Block（10秒間）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;無料プランではRate Limitingルールは1つまで、ブロック期間は最大10秒という制約があります。大規模な攻撃には有料プランのRate Limiting（より長いブロック期間、より多くのルール）が必要ですが、スキャンボット対策としては十分です。上記の設定値は一例です。ページ内のリソース数や想定されるアクセスパターンに応じて調整してください。&lt;&#x2F;p&gt;
&lt;p&gt;なお、今回はWorkers側にも &lt;code&gt;&#x2F;api&#x2F;ask&lt;&#x2F;code&gt; エンドポイントに対して同一IP 60秒間10リクエストの制限を入れています。CloudflareのRate Limitingはインフラ層での粗いフィルタリング、Workers側はアプリケーション層での細かな制御という役割分担です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3層防御の全体像&quot;&gt;3層防御の全体像&lt;&#x2F;h2&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;th&gt;役割&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;第1層&lt;&#x2F;td&gt;&lt;td&gt;Bot Fight Mode&lt;&#x2F;td&gt;&lt;td&gt;既知のボットパターンを自動検出&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;第2層&lt;&#x2F;td&gt;&lt;td&gt;WAF カスタムルール&lt;&#x2F;td&gt;&lt;td&gt;不正なパス・不要なパスを遮断&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;第3層&lt;&#x2F;td&gt;&lt;td&gt;Rate Limiting&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;いずれもCloudflareの無料プランで利用でき、設定はダッシュボードからの操作だけで完結します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;これらの設定を適用した直後から、Observability上でスキャン系のリクエストがブロックされていることを確認できました。Workers AIのNeuronsが無駄に消費されることもなくなっています。&lt;&#x2F;p&gt;
&lt;p&gt;個人サイトであっても、公開すればスキャンボットは来ます。「小規模だから狙われない」ということはありません。ボットは規模を問わず、見つけたエンドポイントを片っ端から叩きます。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflareを使っているなら、無料プランの範囲でもBot Fight Mode、WAFカスタムルール、Rate Limitingの3つを設定するだけで、大半の自動化されたスキャンは防げます。設定にかかる時間は10分程度です。特にWorkers AIやAPIエンドポイントを公開している場合は、不要なリクエストによるリソース消費を防ぐためにも早めの対策をおすすめします。&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;developers.cloudflare.com&#x2F;bots&#x2F;get-started&#x2F;free&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Bot Fight Mode&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;waf&#x2F;custom-rules&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Custom rules&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;waf&#x2F;rate-limiting-rules&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Rate limiting rules&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">個人ブログにAI Chat機能を追加した翌日、スキャンボットの集中アクセスを確認しました。Cloudflareの無料プランだけで実施できるBot Fight Mode、WAFカスタムルール、Rate Limitingの3つの対策を紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>Cloudflare Workers AI + Vectorize で RAG</title>
        <published>2026-03-20T00:00:01+09:00</published>
        <updated>2026-05-07T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/ask-my-digital-double/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/ask-my-digital-double/</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;03&amp;#x2F;ask-my-digital-double&amp;#x2F;cover.webp?h=1c0e8f975b65a3d29155&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;何を作ったのか&quot;&gt;何を作ったのか&lt;&#x2F;h2&gt;
&lt;p&gt;このブログのナビゲーションに「ask」というメニューを追加しました。
私のデジタル分身(bot)に質問できるページが表示されます。質問を入力すると、ブログ記事の内容を踏まえて私っぽい回答を返します。&lt;&#x2F;p&gt;
&lt;p&gt;ブログに書いてある話題はもちろん、書いていない話題についても「私ならこう答えるだろう」という推測で回答を生成します。
ただし、たかだか個人ブログの文書量ですから大した学習量ではないため、平気で嘘をつきます。それも含めて楽しんでもらえればと思います。&lt;&#x2F;p&gt;
&lt;p&gt;たとえば、こんな質問を投げてみます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;Q&amp;A の例&lt;&#x2F;strong&gt;
        &lt;p&gt;&lt;strong&gt;Q:&lt;&#x2F;strong&gt; CIOも設置せず、IT Governanceの取り組みを行なわない理事長が「生成AIを導入したい」と言っています。どうすべきですか？&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;A:&lt;&#x2F;strong&gt; その理事長に、生成AIの導入が「新しいシステムの導入」と違うことを説明する必要があります。生成AIは、組織の判断の中枢に組み込まれ、自社固有の文脈で動く必要があります。そのためには、IT部門だけでなく、業務部門の理解と協力が必要です。
また、生成AIの導入には、データの整備、セキュリティの確保、コンプライアンスの確保などの準備が必要です。CIOを設置せず、IT Governanceの取り組みを行なわない組織では、これらの準備を十分に整えることが難しいでしょう。（以下、省略）&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;私が答えそうな回答を返してきました。ブログ記事の内容をベースにしつつ、ペルソナの設定に基づいた回答を生成しています。&lt;&#x2F;p&gt;
&lt;p&gt;ソースコードはGitHubで公開しています。&lt;&#x2F;p&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;yostos-persona&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;動機&quot;&gt;動機&lt;&#x2F;h2&gt;
&lt;p&gt;仕事を終えて職場を変えることになったとき、同僚が「質問できなくなるので、あなたのbotがあればいいのに」と言ってくれました。ありがたい話です。真に受けました。&lt;&#x2F;p&gt;
&lt;p&gt;もう1つの動機は、せっかくブログをCloudflare Pagesに移行したのでWorkers AIも試してみようという技術的な興味です。Workers AI、Vectorize、Workersを組み合わせたRAGシステムを自分で組んでみたかったですし、構築過程がそのままブログのネタになるのも都合が良いと思いました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;アーキテクチャ&quot;&gt;アーキテクチャ&lt;&#x2F;h2&gt;
&lt;p&gt;処理フローはシンプルなRAGパターンです。&lt;&#x2F;p&gt;
&lt;p&gt;まず事前処理として、ブログ記事をVectorizeに投入しておきます。&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
Articles[ブログ記事&lt;br&gt;Markdown]--&gt; Parse[front matter解析&lt;br&gt;+ セクション分割]--&gt; EMB1[BGE-M3&lt;br&gt;embedding]--&gt; V[(Vectorize)]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;質問時は、入力をベクトル化して類似チャンクを検索し、ペルソナ設定と合わせてLLMに渡します。&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
Q[質問]--&gt; EMB2[BGE-M3&lt;br&gt;embedding]--&gt; V[(Vectorize)]
V --&gt;|類似チャンク| LLM[Llama 3.3 70B]
Persona[ペルソナ設定]--&gt; LLM
LLM --&gt; A[回答 +&lt;br&gt;参考記事リンク]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;ol&gt;
&lt;li&gt;ユーザーが質問を入力&lt;&#x2F;li&gt;
&lt;li&gt;WorkersがBGE-M3で質問をベクトル化&lt;&#x2F;li&gt;
&lt;li&gt;Vectorizeで類似チャンクを検索（上位5件、スコア閾値0.3）&lt;&#x2F;li&gt;
&lt;li&gt;システムプロンプト（ペルソナ設定）＋ 取得したチャンク ＋ 質問をLlama 3.3 70Bに渡す&lt;&#x2F;li&gt;
&lt;li&gt;回答テキスト＋参考記事リンクをフロントエンドに返す&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;使用しているCloudflareサービスはWorkers、Workers AI（EmbeddingとLLM）、Vectorizeの3つだけです。フロントエンドはWorkersのAssets機能で配信しています。フレームワークは使わず、素のHTML&#x2F;CSS&#x2F;JSで構築しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;モデル選定&quot;&gt;モデル選定&lt;&#x2F;h2&gt;
&lt;p&gt;EmbeddingモデルはBGE-M3（&lt;code&gt;@cf&#x2F;baai&#x2F;bge-m3&lt;&#x2F;code&gt;）を採用しました。BAAI開発の多言語対応モデルで、出力は1024次元です。日本語と英語が混在するブログ記事に対応できることが決め手でした。当初はPLaMo-Embedding-1Bを検討しましたが、出力が2048次元でVectorizeの上限（1536次元）を超えるため断念しています。&lt;&#x2F;p&gt;
&lt;p&gt;LLMはLlama 3.3 70B Instruct FP8 Fast（&lt;code&gt;@cf&#x2F;meta&#x2F;llama-3.3-70b-instruct-fp8-fast&lt;&#x2F;code&gt;）です。128Kトークンのコンテキストウィンドウを持ち、日本語でのペルソナ付き回答生成は概ね良好です。中国語文字の混入が発生すると既知の問題として上がっています。今回は、システムプロンプトで抑制しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;事前処理:_ナレッジベースの構築&quot;&gt;事前処理: ナレッジベースの構築&lt;&#x2F;h2&gt;
&lt;p&gt;ブログのMarkdownファイル群をナレッジとして使用しており、これらを解析して事前にVectorizeする処理スクリプト(ingest)が行う処理は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;記事のファイルパス、front matterからslug、title、date、tagsを抽出し、本文を見出し（&lt;code&gt;##&lt;&#x2F;code&gt;）単位でセクション分割&lt;&#x2F;li&gt;
&lt;li&gt;各チャンクにメタデータ（ファイルパス、slug、title、section、URL）を付与&lt;&#x2F;li&gt;
&lt;li&gt;BGE-M3でベクトル化してVectorizeにアップサート&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;差分検出にはマニフェストファイル（slug → MD5ハッシュのマッピング）を使い、変更のあった記事のみ再処理します。初回ingestでは286記事を処理しました。Vectorizeのメタデータ上限（10,240 bytes）対策として、チャンク本文を8,000 bytesに切り詰めています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;質問(Request)対応:_Workers_AI_のコード&quot;&gt;質問(Request)対応: Workers AI のコード&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;Vectorize処理&quot;&gt;Vectorize処理&lt;&#x2F;h3&gt;
&lt;p&gt;Workers AIの特徴は &lt;code&gt;env.AI.run()&lt;&#x2F;code&gt; というバインディング呼び出しです。APIキーの管理もSDKのインストールも不要で、&lt;code&gt;wrangler.toml&lt;&#x2F;code&gt; の &lt;code&gt;[ai]&lt;&#x2F;code&gt; セクションに &lt;code&gt;binding = &quot;AI&quot;&lt;&#x2F;code&gt; と書くだけで使えます。&lt;&#x2F;p&gt;
&lt;p&gt;RAGの検索部分（rag.ts）を丸ごと載せます。Embedding生成からVectorize検索まで、これだけで完結しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot; data-name=&quot;src&#x2F;worker&#x2F;rag.ts&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; Env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; from&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;.&#x2F;types&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-keyword z-storage z-type&quot;&gt;export interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; RetrievedChunk&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-object z-property&quot;&gt;  text&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;  meta&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-variable z-object z-property&quot;&gt;    slug&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;    title&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;    section&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;    url&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-type z-primitive&quot;&gt; string&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-variable z-object z-property&quot;&gt;  score&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-type z-primitive&quot;&gt; number&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; SCORE_THRESHOLD&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.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-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; TOP_K&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; 5&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-keyword z-storage z-modifier z-storage z-type&quot;&gt;export async function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; retrieveChunks&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;  question&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-type z-primitive&quot;&gt; string&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;  env&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-type&quot;&gt; Env&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 z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-meta z-type&quot;&gt;RetrievedChunk[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;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-comment z-comment&quot;&gt;  &#x2F;&#x2F; Embed the question&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; embeddingResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;AI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;run&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;@cf&#x2F;baai&#x2F;bge-m3&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-source&quot;&gt;    text&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 z-variable z-other z-readwrite&quot;&gt; [question]&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-source&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; queryVector&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; embeddingResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;data[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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; Search Vectorize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; results&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;VECTORIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(queryVector&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;    topK&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-variable z-other z-constant z-ts&quot;&gt; TOP_K&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;    returnValues&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-constant z-language z-boolean&quot;&gt; false&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;    returnMetadata&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 z-definition z-string z-string&quot;&gt; &amp;quot;all&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-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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; Filter by score threshold and map to chunks&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; results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;matches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&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;m&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-function z-arrow z-ts&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;score&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-variable z-other z-constant z-ts z-source&quot;&gt; SCORE_THRESHOLD)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&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;m&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-function z-arrow z-ts&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;      text&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; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string&quot;&gt; &amp;quot;&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-source&quot;&gt;      meta&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        slug&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; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;slug&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string&quot;&gt; &amp;quot;&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-source&quot;&gt;        title&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; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string&quot;&gt; &amp;quot;&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-source&quot;&gt;        section&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; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string&quot;&gt; &amp;quot;&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-source&quot;&gt;        url&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; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-string&quot;&gt; &amp;quot;&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-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;      score&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; m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;score&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-source&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&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;LLM呼び出し&quot;&gt;LLM呼び出し&lt;&#x2F;h3&gt;
&lt;p&gt;LLMの呼び出しも同じパターンです。&lt;code&gt;env.AI.run()&lt;&#x2F;code&gt; にモデル名とメッセージを渡すだけで回答が返ってきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot; data-name=&quot;src&#x2F;worker&#x2F;index.ts（抜粋）&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; llmResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;AI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;run&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 z-definition z-string z-string&quot;&gt;  &amp;quot;@cf&#x2F;meta&#x2F;llama-3.3-70b-instruct-fp8-fast&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-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;    messages&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; [&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-source&quot;&gt; role&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 z-definition z-string z-string&quot;&gt; &amp;quot;system&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; content&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-variable z-other z-readwrite&quot;&gt; systemPrompt&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-source&quot;&gt; role&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 z-definition z-string z-string&quot;&gt; &amp;quot;user&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; content&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-variable z-other z-readwrite&quot;&gt; question&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;    ]&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;    max_tokens&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-constant z-numeric&quot;&gt; 512&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-source&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; answer&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (llmResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt; response&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-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;response&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;回答を生成できませんでした。&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;外部APIを叩いている感覚がなく、Workersの中でAIを呼んでいるだけという体験は新鮮です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ペルソナ設定&quot;&gt;ペルソナ設定&lt;&#x2F;h3&gt;
&lt;p&gt;コードの &lt;code&gt;systemPrompt&lt;&#x2F;code&gt; として渡しているのがペルソナ設定です。回答は私のキャラクタ設定に基づいて生成されます。元IBM&#x2F;AWSのエンジニア、ギター愛好家、CLIツール開発が趣味といったプロフィールに加えて、口調や回答スタイルも定義しています。敬語ベースで、好きな話題には熱量が上がり、知らないことでもぺらぺら喋るという設定です。こうしてみると、オタクそのものですね。&lt;&#x2F;p&gt;
&lt;p&gt;回答スタイルとして、簡潔に答えるだけでなく、ときどき脱線したり問い返したりするような振る舞いも仕込んでいます。200〜300文字程度を目安にしていますが、実際の挙動はモデル次第です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;コスト&quot;&gt;コスト&lt;&#x2F;h2&gt;
&lt;p&gt;個人ブログのQ&amp;amp;Aという用途なので、非機能要件は「1日数十件の質問を無料枠内で処理できること」に設定しています。&lt;&#x2F;p&gt;
&lt;p&gt;Workers AIの課金単位はNeuronsです。1リクエストあたりの消費量を見積もります。&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 style=&quot;text-align: right&quot;&gt;トークン数（概算）&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;Neurons&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Embedding（質問文）&lt;&#x2F;td&gt;&lt;td&gt;BGE-M3&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;50 入力&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.05&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;LLM 入力（プロンプト＋チャンク＋質問）&lt;&#x2F;td&gt;&lt;td&gt;Llama 3.3 70B&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2,000 入力&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;53&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;LLM 出力（回答生成）&lt;&#x2F;td&gt;&lt;td&gt;Llama 3.3 70B&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;512 出力&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;105&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;合計&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;約160&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Workers AIの無料枠は10,000 Neurons&#x2F;日なので、&lt;strong&gt;約60リクエスト&#x2F;日&lt;&#x2F;strong&gt;が上限になります。&lt;&#x2F;p&gt;
&lt;p&gt;Vectorizeも無料枠に十分収まります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;リソース&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;使用量&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;無料枠&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;消費率&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;格納次元数（286記事 × 1,024次元）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;約29万&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;500万&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;6%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;クエリ次元数&#x2F;月&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;数千&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;3,000万&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.1%未満&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;超過した場合はWorkers Paidプラン（月$5）で$0.011&#x2F;1,000 Neuronsの従量課金になりますが、現在の利用量では発生しない見込みです。仮に想定の倍（120リクエスト&#x2F;日）が30日続いたとしても、超過分は月約288,000 Neuronsで約$3.2、プラン基本料と合わせて月$8程度です。&lt;&#x2F;p&gt;
&lt;p&gt;悪用防止として、KVベースでIPあたり60秒間10リクエストのレート制限をかけています。単一IPからの過剰なリクエストは抑制できますが、分散アクセスに対しては無力なので、無料枠の維持を保証するものではありません。個人ブログの自然なトラフィックであれば問題ない想定です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;今後の課題&quot;&gt;今後の課題&lt;&#x2F;h2&gt;
&lt;p&gt;現時点で把握している課題は、BGE-M3の日本語検索精度、チャンク分割の粒度、LLMのmax_tokens最適値（回答品質とコストのバランス）、同一質問に対するキャッシュによる重複推論の回避です。&lt;&#x2F;p&gt;
&lt;p&gt;いずれの改善も、実際にどんな質問が来るかわからない段階では手の打ちようがありません。精度を上げるには実際の質問パターンに基づいた評価用クエリが必要で、つまりフィードバックループを回す必要があります。ただし、面白半分で作ったお遊びですし、質問内容を保持するのはプライバシーの観点で望ましくないため、質問内容のロギングは行っていません。一方で、ブログ記事が増えればナレッジベースが厚くなり、検索精度は自然と改善していく可能性があります。&lt;&#x2F;p&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;developers.cloudflare.com&#x2F;workers-ai&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Workers AI&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;vectorize&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Vectorize&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;huggingface.co&#x2F;BAAI&#x2F;bge-m3&quot;&gt;BAAI&lt;&#x2F;a&gt;. &quot;BGE-M3&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">ブログ記事をナレッジベースにして、著者のペルソナで質問に答えるAI Q&amp;Aページを Cloudflare Workers AI と Vectorize で構築しました。BGE-M3 による日本語 embedding、Llama 3.3 70B によるペルソナ付き回答生成、差分 ingest パイプラインまで、Cloudflare スタックだけで完結しています。</summary>
        </entry><entry xml:lang="en">
        <title>ブログ記事をBlueskyに自動投稿する — GitHub Actions + AT Protocol</title>
        <published>2026-03-18T00:00:00+00:00</published>
        <updated>2026-03-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/bluesky-auto-post/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/bluesky-auto-post/</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;03&amp;#x2F;bluesky-auto-post&amp;#x2F;cover.webp?h=28408c7b912f8c80fa6a&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;なぜBlueskyなのか&quot;&gt;なぜBlueskyなのか&lt;&#x2F;h2&gt;
&lt;p&gt;Blueskyは、AT Protocolという分散型プロトコル上に構築されたSNSです。ブログの告知先としてSNSを選ぶなら、X（旧Twitter）が最初の候補に挙がるかもしれません。しかし、XのAPIは2023年に有料化され、無料プランでは月1,500件の投稿しかできません。自動投稿の仕組みを維持するために月額の課金が必要になります。rate limitも厳しく、突然の仕様変更で動かなくなるリスクも無視できません。そもそも、a chaotic messと化したプラットフォームに技術記事の告知を流す意味があるのかという根本的な疑問もあります。&lt;&#x2F;p&gt;
&lt;p&gt;一方、BlueskyのAT Protocol APIは完全に無料で、認証もアプリパスワード1つで済みます。プロトコル仕様が公開されており、&lt;code&gt;curl&lt;&#x2F;code&gt; で直接叩ける素朴さがあります。個人ブログの告知先としては、APIの安定性とコストの両面でBlueskyに優位性があると判断しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;手動投稿の煩わしさ&quot;&gt;手動投稿の煩わしさ&lt;&#x2F;h2&gt;
&lt;p&gt;ブログ記事を書き上げてpushした後、Blueskyを開いてURLを貼り、説明文を添えて投稿する。この手作業は1分で終わりますが、毎回やるのは面倒です。忘れることもあります。&lt;&#x2F;p&gt;
&lt;p&gt;このブログはZolaで生成し、Cloudflare Pagesでホスティングしています。記事の公開は &lt;code&gt;git push origin main&lt;&#x2F;code&gt; で完了します。であれば、Blueskyへの告知もこのpushをトリガーにして自動化するのが自然な流れです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜGitHub_Actionsなのか&quot;&gt;なぜGitHub Actionsなのか&lt;&#x2F;h2&gt;
&lt;p&gt;自動投稿の実現方法について、いくつか検討してみました。&lt;&#x2F;p&gt;
&lt;p&gt;1.Cloudflare Worker + Deploy Hook&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;インフラをCloudflareで統一できる利点があるが、「新規記事かどうか」の判定にKV等の状態管理が必要になる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;ローカルのフック（Claude Code Hookなど）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;シンプルだが、別マシンからの投稿時に動作しない。また、GitHub Actionの完了との同期が面倒である。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;IFTTT&#x2F;Zapier等のSaaS&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;簡単だが、RSSベースのため遅延が発生する。また、プライバシーの懸念もある。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;結局、GitHub Actionsへ組み込むことにしました。&lt;&#x2F;p&gt;
&lt;p&gt;GitHub Actionsを選んだ決め手は、&lt;code&gt;git diff&lt;&#x2F;code&gt; が使えることです。&lt;code&gt;git diff --name-status HEAD~1 HEAD&lt;&#x2F;code&gt; の出力で &lt;code&gt;A&lt;&#x2F;code&gt;（Added）ステータスかつ &lt;code&gt;content&#x2F;**&#x2F;index.md&lt;&#x2F;code&gt; に一致するファイルを検出すれば、新規記事だけを正確に判別できます。更新や削除では発動しません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;仕組みの全体像&quot;&gt;仕組みの全体像&lt;&#x2F;h2&gt;
&lt;p&gt;処理フローはシンプルです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;mainブランチへのpushでワークフローが起動&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git diff&lt;&#x2F;code&gt; で新規記事（&lt;code&gt;A&lt;&#x2F;code&gt; ステータスの &lt;code&gt;index.md&lt;&#x2F;code&gt;）を検出&lt;&#x2F;li&gt;
&lt;li&gt;frontmatter（TOML形式）からtitle、description、tagsを抽出&lt;&#x2F;li&gt;
&lt;li&gt;Bluesky AT Protocol APIで認証&lt;&#x2F;li&gt;
&lt;li&gt;OGP画像を &lt;code&gt;com.atproto.repo.uploadBlob&lt;&#x2F;code&gt; でアップロード&lt;&#x2F;li&gt;
&lt;li&gt;リンクカード（サムネイル付き）のポストを作成&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ワークフローとスクリプトの2ファイル構成です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ワークフロー&quot;&gt;ワークフロー&lt;&#x2F;h2&gt;
&lt;p&gt;ワークフローは新規記事の検出と、スクリプトの呼び出しに責務を限定しています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;.github&#x2F;workflows&#x2F;bluesky-post.yml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&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-string&quot;&gt; Post to Bluesky&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-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  push&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    branches&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-string&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-entity z-name z-tag z-yaml&quot;&gt;    paths&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-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;content&#x2F;**&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-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    runs-on&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-string&quot;&gt; ubuntu-latest&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-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; uses&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-string&quot;&gt; actions&#x2F;checkout@v6&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-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          fetch-depth&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-constant z-numeric&quot;&gt; 2&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Detect new articles&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-tag z-yaml&quot;&gt;        id&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-string&quot;&gt; detect&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-tag z-yaml&quot;&gt;        run&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-keyword&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;          new_articles=$(git diff --name-status HEAD~1 HEAD \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            | grep &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-string&quot;&gt;            | awk &amp;#39;{print $2}&amp;#39; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            | grep &amp;#39;content&#x2F;.*&#x2F;index\.md$&amp;#39; || true)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          if [ -z &amp;quot;$new_articles&amp;quot; ]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;No new articles found&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;has_new=false&amp;quot; &amp;gt;&amp;gt; &amp;quot;$GITHUB_OUTPUT&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;New articles found:&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;$new_articles&amp;quot;&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;              echo &amp;quot;articles&amp;lt;&amp;lt;EOF&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;              echo &amp;quot;$new_articles&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;              echo &amp;quot;EOF&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            } &amp;gt;&amp;gt; &amp;quot;$GITHUB_OUTPUT&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;has_new=true&amp;quot; &amp;gt;&amp;gt; &amp;quot;$GITHUB_OUTPUT&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Post to Bluesky&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-tag z-yaml&quot;&gt;        if&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-string&quot;&gt; steps.detect.outputs.has_new == &amp;#39;true&amp;#39;&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-tag z-yaml&quot;&gt;        env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          BLUESKY_IDENTIFIER&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-string&quot;&gt; ${{ secrets.BLUESKY_IDENTIFIER }}&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-tag z-yaml&quot;&gt;          BLUESKY_APP_PASSWORD&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-string&quot;&gt; ${{ secrets.BLUESKY_APP_PASSWORD }}&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-tag z-yaml&quot;&gt;          NEW_ARTICLES&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-string&quot;&gt; ${{ steps.detect.outputs.articles }}&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-tag z-yaml&quot;&gt;        run&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-keyword&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;          echo &amp;quot;$NEW_ARTICLES&amp;quot; | while IFS= read -r article; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            [ -z &amp;quot;$article&amp;quot; ] &amp;amp;&amp;amp; continue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            bash scripts&#x2F;bluesky-post.sh &amp;quot;$article&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;&lt;code&gt;fetch-depth: 2&lt;&#x2F;code&gt; で直前のコミットとの差分を取得できるようにしています。&lt;code&gt;paths: [&#x27;content&#x2F;**&#x27;]&lt;&#x2F;code&gt; でcontent配下に変更がないpush（設定ファイルの変更など）ではワークフロー自体が起動しません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;投稿スクリプト&quot;&gt;投稿スクリプト&lt;&#x2F;h2&gt;
&lt;p&gt;投稿スクリプトは &lt;code&gt;curl&lt;&#x2F;code&gt; と &lt;code&gt;jq&lt;&#x2F;code&gt; だけで動作します。外部ライブラリは不要です。&lt;&#x2F;p&gt;
&lt;p&gt;処理は大きく5段階に分かれています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;frontmatterの抽出。&lt;&#x2F;strong&gt; &lt;code&gt;sed&lt;&#x2F;code&gt; でTOMLのfrontmatter領域（&lt;code&gt;+++&lt;&#x2F;code&gt; で囲まれた部分）を取り出し、title、description、tags、&lt;code&gt;social_media_card&lt;&#x2F;code&gt;（OGP画像パス）を個別にパースします。descriptionはTOMLの複数行文字列（&lt;code&gt;&quot;&quot;&quot;&lt;&#x2F;code&gt;）にも対応しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;投稿テキストの生成。&lt;&#x2F;strong&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;📝 Just published:&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;#blog #tag1 #tag2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;descriptionはリンクカードに表示されるため、テキスト本文には含めません。&lt;code&gt;#blog&lt;&#x2F;code&gt; は固定で付与し、記事のタグから最大5個のハッシュタグを追加します。スペースを含むタグ（&quot;Generative AI&quot; など）はBlueskyのハッシュタグとして機能しないためスキップします。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Facetの生成。&lt;&#x2F;strong&gt; Blueskyでハッシュタグをクリック可能にするには、テキスト中の &lt;code&gt;#tag&lt;&#x2F;code&gt; の位置をUTF-8バイトオフセットで指定する &lt;code&gt;facet&lt;&#x2F;code&gt; が必要です。&lt;code&gt;wc -c&lt;&#x2F;code&gt; でバイト位置を算出し、&lt;code&gt;app.bsky.richtext.facet#tag&lt;&#x2F;code&gt; を設定しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;OGP画像のアップロード。&lt;&#x2F;strong&gt; frontmatterの &lt;code&gt;social_media_card&lt;&#x2F;code&gt; で指定されたOGP画像を &lt;code&gt;com.atproto.repo.uploadBlob&lt;&#x2F;code&gt; でBlueskyにアップロードし、blobリファレンスを取得します。アップロードに失敗した場合はサムネイルなしで投稿を続行します。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;APIの呼び出し。&lt;&#x2F;strong&gt; &lt;code&gt;com.atproto.server.createSession&lt;&#x2F;code&gt; でセッションを作成し、&lt;code&gt;com.atproto.repo.createRecord&lt;&#x2F;code&gt; でポストを作成します。リンクカードは &lt;code&gt;app.bsky.embed.external&lt;&#x2F;code&gt; で埋め込み、アップロード済みのOGP画像を &lt;code&gt;thumb&lt;&#x2F;code&gt; フィールドに設定します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;リンクカードについて&quot;&gt;リンクカードについて&lt;&#x2F;h2&gt;
&lt;p&gt;Blueskyは投稿時にURLからOGPを自動取得しません。リンクカードを表示するには、投稿APIで &lt;code&gt;app.bsky.embed.external&lt;&#x2F;code&gt; を明示的に指定する必要があります。サムネイル画像を表示するには、事前に &lt;code&gt;com.atproto.repo.uploadBlob&lt;&#x2F;code&gt; で画像をアップロードし、返却されたblobリファレンスを &lt;code&gt;thumb&lt;&#x2F;code&gt; フィールドに設定します。&lt;&#x2F;p&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 z-definition z-string z-string&quot;&gt;&amp;quot;embed&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;$type&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;app.bsky.embed.external&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;external&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;uri&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;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;03&#x2F;bluesky-auto-post&#x2F;&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-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;title&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;記事タイトル&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-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;description&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;記事の説明文&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-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;thumb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;$type&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;blob&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; ...&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このスクリプトでは、frontmatterの &lt;code&gt;social_media_card&lt;&#x2F;code&gt; で指定されたOGP画像（WebP&#x2F;PNG&#x2F;JPEG対応）をアップロードしています。画像のアップロードに失敗した場合でも、サムネイルなしのリンクカードとして投稿が作成されるようにフォールバック処理を入れています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;GitHub_Secretsの設定&quot;&gt;GitHub Secretsの設定&lt;&#x2F;h2&gt;
&lt;p&gt;ワークフローで使用するシークレットは2つです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BLUESKY_IDENTIFIER&lt;&#x2F;code&gt; — Blueskyのハンドル&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;BLUESKY_APP_PASSWORD&lt;&#x2F;code&gt; — Blueskyのアプリパスワード（設定画面から生成）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;アプリパスワードはアカウントのパスワードとは別物で、権限を限定して発行できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;git push&lt;&#x2F;code&gt; から自動的にBlueskyへ投稿される仕組みを、GitHub Actionsとシェルスクリプトで構築しました。OGP画像のサムネイル付きリンクカードまで含めて、外部ライブラリに依存せず &lt;code&gt;curl&lt;&#x2F;code&gt; と &lt;code&gt;jq&lt;&#x2F;code&gt; だけで完結しています。この記事自体が最初の自動投稿テストです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&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;docs.bsky.app&#x2F;docs&#x2F;advanced-guides&#x2F;posts&quot;&gt;Bluesky&lt;&#x2F;a&gt;. &quot;Sending Post with the Bluesky API&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;atproto.com&#x2F;specs&#x2F;xrpc&quot;&gt;AT Protocol&lt;&#x2F;a&gt;. &quot;XRPC Specification&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">ブログの新規記事をmainにpushするだけで、Blueskyに自動投稿される仕組みをGitHub ActionsとAT Protocol APIで構築しました。git diffによる新規記事の判定、リンクカード付き投稿、ハッシュタグのfacet生成まで、シェルスクリプト一本で実現しています。</summary>
        </entry><entry xml:lang="en">
        <title>Mac環境のリフレッシュ</title>
        <published>2026-03-17T15:34:11+09:00</published>
        <updated>2026-03-17T15:34:11+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/mac-environment-refresh/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/mac-environment-refresh/</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;03&amp;#x2F;mac-environment-refresh&amp;#x2F;cover.webp?h=9246e8ce05db44c2688d&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&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;見送っていたMac環境のリフレッシュを実施しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MacPaw関連ソフトウェアの見直し&quot;&gt;MacPaw関連ソフトウェアの見直し&lt;&#x2F;h2&gt;
&lt;p&gt;MacPaw&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;の次の2つのソフトウェアを使用していました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CleanMyMac X&lt;&#x2F;strong&gt;: macOSのメンテナンス・ユーティリティ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Gemini 2&lt;&#x2F;strong&gt;: 重複ファイル削除ツール&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;いずれもサブスクリプションが中心ですが、私は2022年にロシアのウクライナ侵攻が起こった際に支援のつもりでLifeTimeの買い切りで購入しています。コストも発生せず、どちらも便利なツールです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、常駐して僅かですがリソースを食っているのが気になっていました。
今回はどちらもアンインストールして、CLI代替ツールに移行しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Mole_—_macOSクリーンアップツール&quot;&gt;Mole — macOSクリーンアップツール&lt;&#x2F;h2&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;tw93&amp;#x2F;mole&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;p&gt;macOSのクリーンナップと最適化に特化したコマンドラインツールです。
CleanMyMac、AppCleaner、DaisyDisk、iStat Menusなどの機能を1コマンドでカバーしていると謳っています。&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;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clean&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;  # アプリの完全アンインストール&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; optimize&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; analyze&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; status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;     # CPU&#x2F;GPU&#x2F;メモリ&#x2F;ディスク&#x2F;ネットワークのリアルタイム監視&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; purge&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; installer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Downloads内の.dmg&#x2F;.pkgの整理&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;結構危険な処理をするツールですが、いずれも&lt;code&gt;--dry-run&lt;&#x2F;code&gt;オプションがサポートされており、実際に削除する前に検証できます。&lt;&#x2F;p&gt;
&lt;p&gt;実際、CleanMyMac Xで使用していた機能のうちマルウェアスキャン以外はほぼカバーされています。
マルウェアスキャンについては、macOS標準のXProtectとGatekeeperがかなり優秀なので、基本的に追加のスキャナは不要と判断しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Czkawka（チカフカ）_—_不要ファイル検出ツール&quot;&gt;Czkawka（チカフカ） — 不要ファイル検出ツール&lt;&#x2F;h2&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;qarmin&amp;#x2F;czkawka&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;p&gt;主に重複ファイルの削除に使用していたGemini 2の代替です。名前はポーランド語で「しゃっくり」を意味します。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sahib&#x2F;rmlint&quot;&gt;rmlint&lt;&#x2F;a&gt;も検討しましたが、rmlintはバイト単位での重複判定のみで、Gemini 2のように画像の類似性による重複判定には対応していません。&lt;&#x2F;p&gt;
&lt;p&gt;その点Czkawkaは、パーセプチュアルハッシュによる類似画像検出をサポートしています。GUI版もありますが、安定のCLI版を使っています。&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;# 重複ファイル検出: -d 検索先 -e 除外先 -m 最小25B -s hash比較 -D aeo(最古以外を削除)&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;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dup -d ~&#x2F;Documents -e ~&#x2F;Documents&#x2F;Archive -m&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -x 7z rar IMAGE -s hash -f results.txt -D aeo&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;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; empty-folders -d ~&#x2F;Documents ~&#x2F;Downloads -f results.txt&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;# 巨大ファイル検出: -n 上位25件 -x VIDEO拡張子を除外&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;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; big -d ~&#x2F;Documents -e ~&#x2F;Documents&#x2F;Archive -n&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -x VIDEO -f results.txt&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;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; image -d ~&#x2F;Pictures -e ~&#x2F;Pictures&#x2F;Wallpapers -f results.txt&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;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; symlinks -d ~&#x2F;Projects -e ~&#x2F;Projects&#x2F;.git -x jpg -f results.txt&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;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; broken -d ~&#x2F;Downloads -f results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;重複ファイル、類似画像、空ファイル・フォルダ、一時ファイル、破損ファイル、拡張子不一致、不正ファイル名など、Gemini 2以上に多彩な検出機能を備えています。&lt;&#x2F;p&gt;
&lt;p&gt;なお、SenseiとCocktailは引き続き使用しています。Senseiはハードウェア情報やSSDのTrim管理に、CocktailはmacOSの定期メンテナンスタスクの自動実行に、それぞれ役割が明確なので残しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メニューバーの整理&quot;&gt;メニューバーの整理&lt;&#x2F;h2&gt;
&lt;p&gt;MacBookでメニューバーにたくさんアイコンが並ぶと、ノッチの裏に隠れて見えなくなる問題があります。この対策としてメニュー表示管理ツールを使用していました。&lt;&#x2F;p&gt;
&lt;p&gt;Bartenderから数年前に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jordanbaird&#x2F;Ice&quot;&gt;Ice&lt;&#x2F;a&gt;へ移行しましたが、macOS Tahoeではメニュー構造が変わった影響で動作が不安定になっていました。&lt;&#x2F;p&gt;
&lt;p&gt;代替として次のようなツールがありますが、いずれも新しいmacOSのメニュー構造の変更に対応しきれていないようでした。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Hidden Bar&lt;&#x2F;li&gt;
&lt;li&gt;Bartender 5（有料）&lt;&#x2F;li&gt;
&lt;li&gt;Vanilla&lt;&#x2F;li&gt;
&lt;li&gt;iBar&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;しかし、macOS Tahoeではメニューバーのカスタマイズ機能が大幅に強化されました。「システム設定 &amp;gt; メニューバー &amp;gt; メニューバーの操作」から、次の操作が可能になっています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;アプリごとにメニューバーへの表示のオン・オフを制御&lt;&#x2F;li&gt;
&lt;li&gt;Apple純正機能はコントロールセンターへ移動可能&lt;&#x2F;li&gt;
&lt;li&gt;Command+ドラッグでアイコンの並び替え&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;サードパーティ製ツールのように表示の動的な切り替えやレイアウト変更には対応していませんが、常駐アイコンの大半を整理できました。もうサードパーティ製ツールは不要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ブラウザArcの代替&quot;&gt;ブラウザArcの代替&lt;&#x2F;h2&gt;
&lt;p&gt;数年前に彗星のごとく登場したArcを愛用していましたが、2025年5月にThe Browser Companyが開発終了を発表しました。理由は「ほとんどの人にとってArcは違いが大きすぎて学習コストに見合わなかった」という&quot;novelty tax&quot;問題とのことです。後継としてAIブラウザ「Dia」の開発に注力するとされていますが、Arc自体はセキュリティ修正のみのメンテナンスモードに入っています。&lt;&#x2F;p&gt;
&lt;p&gt;当初はGoogle Chrome + Side Space拡張機能でほぼArcと同等のことができるかと試していました。しかし、Arcの全機能を再現しようとすると拡張の組み合わせが増えるばかりで、本末転倒だと気づきました。&lt;&#x2F;p&gt;
&lt;p&gt;結局、Safariに落ち着いています。iCloudとの連携、省電力性能、macOS標準のパスキー対応など、Apple製品で統一している環境であれば素直にSafariが最適という結論です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;GUIの常駐アプリをCLIに置き換え、メニューバーをOS標準機能で整理し、ブラウザもSafariに一本化しました。&lt;&#x2F;p&gt;
&lt;p&gt;やっとメニューバーが整理でき、&lt;code&gt;mo clean&lt;&#x2F;code&gt;一発でMacのクリーンナップもできる。そういう小さな快適さの積み重ねで、深呼吸できた心地がします。ゴミの山は鼻をつまんで走り抜けるに限ります。&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;github.com&#x2F;tw93&#x2F;mole&quot;&gt;GitHub - tw93&#x2F;mole&lt;&#x2F;a&gt;. &quot;Mole - Deep clean and optimize your Mac&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qarmin&#x2F;czkawka&quot;&gt;GitHub - qarmin&#x2F;czkawka&lt;&#x2F;a&gt;. &quot;Multi functional app to find duplicates, empty folders, similar images etc.&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cindori.com&#x2F;sensei&quot;&gt;Sensei — Cindori&lt;&#x2F;a&gt;. 「Mac Performance Monitor &amp;amp; Cleaner」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.maintain.se&#x2F;cocktail&#x2F;&quot;&gt;Cocktail — Maintain&lt;&#x2F;a&gt;. 「A perfect mixture for macOS」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;guide&#x2F;mac-help&#x2F;change-menu-bar-settings-mchlad96d366&#x2F;mac&quot;&gt;Apple Support&lt;&#x2F;a&gt;. &quot;Change Menu Bar settings on Mac&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.engadget.com&#x2F;ai&#x2F;the-browser-company-stops-active-development-of-arc-in-favor-of-new-ai-focused-product-153045276.html&quot;&gt;Engadget&lt;&#x2F;a&gt;. &quot;The Browser Company stops active development of Arc in favor of new AI-focused product&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;Macのユーティリティ系ソフトウェアを開発・販売しているウクライナのベンダー &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">無為がループした一年で放置していたMac環境をリフレッシュしました。MacPawのGUIツールをCLIへ移行し、メニューバーをmacOS Tahoe標準機能で整理し、ArcからSafariへ乗り換えた記録です。</summary>
        </entry><entry xml:lang="en">
        <title>Zennの生成AIコンテンツガイドラインに思うこと</title>
        <published>2026-03-11T00:00:00+00:00</published>
        <updated>2026-03-11T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/zenn-ai-guideline/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/zenn-ai-guideline/</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;03&amp;#x2F;zenn-ai-guideline&amp;#x2F;cover.webp?h=61a86250aa9c24c2055e&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;2026年3月10日、Zennが「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;info.zenn.dev&#x2F;2026-03-10-ai-contents-guideline&quot;&gt;コンテンツの執筆における生成AIの利用について&lt;&#x2F;a&gt;」と題したガイドラインを発表しました。生成AIによるコンテンツ乱造への対応として、プラットフォームがどのようなスタンスを取るのかを示した文書です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ガイドラインの概要&quot;&gt;ガイドラインの概要&lt;&#x2F;h2&gt;
&lt;p&gt;このガイドラインの主要なポイントは次の通りです。&lt;&#x2F;p&gt;
&lt;p&gt;Zennは「人が主体となって情報を発信する場」であることを重視しています。AIの利用自体は禁止せず、「人が主体となる」ことの定義として「著者による公開前の内容検証」と「著者自身の経験や洞察をコンテンツに込める」の2つを挙げています。&lt;&#x2F;p&gt;
&lt;p&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;&#x2F;ul&gt;
&lt;p&gt;実際の投稿制限は次の通りです。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;faq&#x2F;rate-limit&quot;&gt;
記事は直近24時間以内の投稿数（投稿予約中を含む）、本は直近1週間以内の投稿数に基づいて判定されます。上限に達した場合でも、一定時間が経過すれば再び投稿できるようになります。
  &lt;footer&gt;
&lt;cite&gt;Zenn Q&amp;A「&lt;a href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;faq&#x2F;rate-limit&quot;&gt;投稿数の上限とは？&lt;&#x2F;a&gt;」より引用&lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;制限の評価&quot;&gt;制限の評価&lt;&#x2F;h2&gt;
&lt;p&gt;AI利用を全面禁止しなかったのは現実的な判断です。生成AIは今やエンジニアの執筆支援ツールとして広く使われており、一律禁止は実効性がないだけでなく、正当な利用まで萎縮させてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;「公開前に内容を検証する」「著者自身の経験や洞察を込める」という2つの基準は具体的で、ユーザーにとって判断しやすい定義です。スクラップを「学習ログ用の緩い枠」として検討しているとも述べられており、AIの出力を整理して残したいという正当なユースケースへの配慮が感じられます。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、最も気になるのは、実際の対策が「投稿頻度の制限」に集約されている点です。これは結局、コンテンツの質ではなく更新サイクルでスパムかどうかを判断していることになります。&lt;&#x2F;p&gt;
&lt;p&gt;大量自動投稿botが実際にどの程度存在するかは把握していませんが、その対策としては確かに実効的です。
おそらく人が読めば判別できるようにも思いますが、内容でフィルターを掛けてしまうと「言論の自由」などという複雑な問題に入り込んでしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;この制限は、&lt;strong&gt;生成AIを活用するからこそ生産性が上がる&lt;&#x2F;strong&gt;という事実が見落とされています。
生成AIを業務へ取り入れているエンジニアは、調査能力が拡がり、知識の整理が速くなり、結果として記事を書くスピードが上がります。私自身、1日1記事のペースで投稿していますが、それは生成AIの支援で調査と執筆の効率が上がったからです。ガイドラインでは「上限は複数の指標に基づいて決定される（一律ではない）」とされています。しかし量による制限であることに変わりはなく、生産性の高いエンジニアにもブレーキをかけてしまう可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;少数でも中身の薄いAI生成記事を投稿するケースには、この制限は機能しにくいでしょう。上限の具体的な数値は非公開のため断言はできませんが、量を絞っても質の問題は残ります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;エンジニアのプラットフォームとして&quot;&gt;エンジニアのプラットフォームとして&lt;&#x2F;h2&gt;
&lt;p&gt;Zennは「エンジニアの実体験に基づく知見が集まる場」として信頼を築いてきました。そのブランドを守りたいという意図は理解できますし、プラットフォームとしてのポリシーを定める権利は当然あります。&lt;&#x2F;p&gt;
&lt;p&gt;世界に目を向ければ、AIエージェントを「デジタル従業員」としてプロジェクトに組み込む動きが加速しています。&lt;a href=&quot;&#x2F;blog&#x2F;2026&#x2F;03&#x2F;aws-proserve-innovation&#x2F;&quot;&gt;AWS ProServeの変革&lt;&#x2F;a&gt;やMcKinseyの25,000エージェント体制など、AIを人間と対等な「チームメンバー」として扱う方向へ明確にシフトしています。&lt;&#x2F;p&gt;
&lt;p&gt;Zennの運営元であるクラスメソッドは、AWSプレミアパートナーとして日本市場でAWSコンサルティングを提供しており、ProServeとは一部領域で競合する関係にあります。そのProServeはAIエージェントを人間の要員と同列に組み込んでいる一方、自社プラットフォームではAIの関与を投稿頻度の制限という形で抑制しています。AIを対等なチームメンバーとして扱う立場と、AIの関与を公正さを損なうものとして制約する立場——同じ市場で相対する組織でありながら、この対照的な姿勢は興味深いところです。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIのフロンティアで活躍するエンジニアが集まるプラットフォームにおいて、投稿頻度の制限は保守的すぎないでしょうか。生成AIを積極的に活用しているエンジニアほど投稿頻度が高くなりがちです。その活動を制限する施策は、プラットフォームの方向性と矛盾しているように見えます。&lt;&#x2F;p&gt;
&lt;p&gt;もう1つ、Zennの運営姿勢として気になる点があります。&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zenn-dev&#x2F;zenn-community&#x2F;issues&#x2F;78&quot;&gt;canonical URLの設定機能&lt;&#x2F;a&gt;が2020年9月から要望されているにもかかわらず、5年以上経った今も実装されていません。自分のドメインでブログを運営しているエンジニアが、より広い読者層にリーチするためZennでも記事を共有したいところです。その際、SEO上の重複コンテンツ問題を避けるためにcanonical URLを設定したい。これはdev.toなど他のプラットフォームでは当たり前に提供されている機能です。&lt;&#x2F;p&gt;
&lt;p&gt;運営側がネガティブSEO（悪質なサイトへのcanonical指定によるドメイン評価の毀損）を懸念していることは、Issue内のコメントから読み取れます。技術的に簡単でない問題だと理解できます。しかし5年以上の間に、レピュテーションの高いユーザー限定で開放するなど、段階的なアプローチを検討する余地があったのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;「人が主体となって情報を発信する」ことを掲げるならば、エンジニアが自身のドメインで発信した記事をZennでも共有できる仕組みこそ、その理念に合致するはずです。投稿頻度を制限する前に、こうした長年未対応の基本的な要望に応えてほしいと感じます。&lt;&#x2F;p&gt;
&lt;p&gt;また、2026年1月には&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;akari1106&#x2F;articles&#x2F;993e42b4430f36&quot;&gt;自動翻訳機能&lt;&#x2F;a&gt;がデフォルトONで事前説明なしにリリースされ、「自分のコンテンツが勝手に翻訳される」ことへの反発を受けて数時間でデフォルトOFFに撤回されるという一幕もありました。対応の速さは評価できますが、エンジニアの声を聞く前に動き、反発を受けて撤回するというパターンが繰り返されている印象を受けます。&lt;&#x2F;p&gt;
&lt;p&gt;もちろん、コンテンツの質を自動判定するのは技術的に難しい課題です。レピュテーション制度やレビュープロセスの導入は、投稿頻度の制限に比べて実装コストが高いことも理解しています。しかし、だからといって量の制限だけで代替し続けるのは、問題の本質に届いていません。コミュニティのリアクション（いいねやブックマーク）の活用など、既存の仕組みを生かした段階的な取り組みから始めることはできるはずです。方向性として、質に踏み込む施策の検討を期待したいところです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Zennのガイドラインは、生成AI時代のコンテンツプラットフォームが直面する課題への第一歩としては妥当です。AI利用を禁止しない姿勢と、「人が主体」という原則は支持できます。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、投稿頻度の制限だけでは、botは防げても、生成AIを道具として使いこなすエンジニアの活動まで制限してしまう可能性があります。canonical URLへの長年の未対応、自動翻訳機能の拙速なリリースと撤回。こうした運営判断の積み重ねを見ると、「エンジニアの発信を支えるプラットフォーム」として今後どのような方向に進むのか、期待と現実のギャップを感じます。&lt;&#x2F;p&gt;
&lt;p&gt;私自身は、今後Zennへのフル記事の投稿は行わないことにしました。自分の発信は自分のドメインで行い、Zennにはスクラップや要約の共有にとどめるつもりです。canonical URLが使えない以上、同じ記事を2箇所に全文掲載する意味はありません。&lt;&#x2F;p&gt;
&lt;p&gt;技術ブログプラットフォームにおいて、エンジニアが自分のコンテンツに対する裁量——何を、いつ、どれだけ公開するか——を持てることは決定的に重要です。今回の投稿頻度制限は、まさにその「いつ、どれだけ公開するか」という裁量をプラットフォーム側が制約するものです。2020年、Qiitaがエンジニアの閲覧履歴を無断で公開し、求人サービスへ個人情報を事前告知なく提供していた問題が発覚しました。自分の情報がどこまで公開されるかという裁量を奪われたエンジニアの多くがプラットフォームへの信頼を失い、Zennへ移行しました。問題の性質や深刻さは異なりますが、エンジニアの裁量を制限する運営方針がプラットフォームへの信頼に影響しうることを、この事例は示しています。&lt;&#x2F;p&gt;
&lt;p&gt;エンジニアは最終的に、自分のコンテンツを自ら管理できる場所で発信することを選びます。それが「人が主体となって情報を発信する」ということだと、私は考えています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&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;info.zenn.dev&#x2F;2026-03-10-ai-contents-guideline&quot;&gt;Zenn&lt;&#x2F;a&gt;. 「コンテンツの執筆における生成AIの利用について」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zenn-dev&#x2F;zenn-community&#x2F;issues&#x2F;78&quot;&gt;zenn-dev&#x2F;zenn-community&lt;&#x2F;a&gt;. &quot;記事に canonical_url を設定できるように · Issue #78&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;akari1106&#x2F;articles&#x2F;993e42b4430f36&quot;&gt;Zenn&lt;&#x2F;a&gt;. 「Zennの自動翻訳機能から学ぶプロダクト開発の難しさ」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Zennが発表した生成AIコンテンツガイドラインは、
AI利用を禁止せず「人が主体」という原則を掲げました。
その方針を評価しつつ、投稿頻度による制限という手法が
生成AIを活用するエンジニアにとって何を意味するのかを考察します。
</summary>
        </entry><entry xml:lang="en">
        <title>CLAUDE.mdを太らせない — リポジトリ設計で実現するClaude Codeのガードレールと再現性</title>
        <published>2026-03-08T07:04:00+09:00</published>
        <updated>2026-03-08T07:04:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/claude-code-repo-architecture/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/claude-code-repo-architecture/</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;03&amp;#x2F;claude-code-repo-architecture&amp;#x2F;cover.webp?h=4d465f543f1815d72ad1&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;CLAUDE.mdが肥大化していませんか&quot;&gt;CLAUDE.mdが肥大化していませんか&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを使い込むほど、CLAUDE.mdは育っていきます。ショートコードの構文リファレンス、コミットの手順、画像生成のコマンド、レビューのチェックリスト。気がつけば400行を超え、重要なルールが大量の参考情報に埋もれている――そんな状態になっていないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;CLAUDE.mdはセッション開始時に毎回読み込まれるコンテキストです。ここに情報を詰め込みすぎると、本当に守ってほしいルールの優先度が下がります。かといって削りすぎれば、Claudeは暗黙知を推測で補おうとして事故を起こします。&lt;&#x2F;p&gt;
&lt;p&gt;このブログ（Zola静的サイト）の運用で、CLAUDE.mdを458行から117行へ削減しながら、むしろルール遵守の精度と作業の再現性を向上させた設計パターンを紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4層アーキテクチャという考え方&quot;&gt;4層アーキテクチャという考え方&lt;&#x2F;h2&gt;
&lt;p&gt;この整理は、Shraddha Bharuka氏が提唱する「The Anatomy of a Claude Code Project」の考え方をベースにしています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Most people treat CLAUDE.md like a prompt file.&lt;br&gt;&lt;br&gt;That&#x27;s the mistake.&lt;br&gt;&lt;br&gt;If you want Claude Code to feel like a senior engineer living inside your repo, your project needs structure.&lt;br&gt;&lt;br&gt;Claude needs 4 things at all times:&lt;br&gt;&lt;br&gt;• the why → what the system does&lt;br&gt;• the map → where things… &lt;a href=&quot;https:&#x2F;&#x2F;t.co&#x2F;wumSCnNxHF&quot;&gt;pic.twitter.com&#x2F;wumSCnNxHF&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&amp;mdash; Shraddha Bharuka (@BharukaShraddha) &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;BharukaShraddha&#x2F;status&#x2F;2029836408232497678?ref_src=twsrc%5Etfw&quot;&gt;March 6, 2026&lt;&#x2F;a&gt;&lt;&#x2F;blockquote&gt; &lt;script async src=&quot;https:&#x2F;&#x2F;platform.twitter.com&#x2F;widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;&#x2F;script&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;氏の整理ではRepo Memory &#x2F; Reusable Expert Modes &#x2F; Guardrails &#x2F; Progressive Contextという4層が示されています。本記事ではClaude CodeのAuto Memory機能との混同を避けるため、一部の用語を変更しています。&lt;&#x2F;p&gt;
&lt;p&gt;リポジトリに散らばるClaude Code関連のファイルを、責務で4つの層に分離します。&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;th&gt;読み込みタイミング&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Project Instructions&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;CLAUDE.md&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;WHY・WHAT・HOW の要約&lt;&#x2F;td&gt;&lt;td&gt;毎セッション（常時）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Workflows&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;.claude&#x2F;commands&#x2F;&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;Guardrails&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;.claude&#x2F;settings.json&lt;&#x2F;code&gt; (Hooks)&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;Progressive Context&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;docs&#x2F;&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;&#x2F;p&gt;
&lt;h2 id=&quot;CLAUDE.md_—_Project_Instructions&quot;&gt;CLAUDE.md — Project Instructions&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeにはもうひとつ、Auto Memoryという記憶の仕組みがあります。これはClaude自身がセッション中に学んだこと――ビルドコマンドの癖、デバッグで得た知見、ユーザーの好み――を &lt;code&gt;~&#x2F;.claude&#x2F;projects&#x2F;&amp;lt;project&amp;gt;&#x2F;memory&#x2F;&lt;&#x2F;code&gt; に自動で書き残す機能です。CLAUDE.mdが「ユーザーからClaudeへの指示」であるのに対し、Auto Memoryは「Claudeが自分で蓄積する学習ノート」です。両者はセッション開始時に読み込まれますが、役割が異なります。この記事で扱う4層アーキテクチャは、ユーザーが意図的に設計する情報配置のパターンです。Auto Memoryはその外側で自動的に機能する補完的な仕組みとして捉えてください。&lt;&#x2F;p&gt;
&lt;p&gt;CLAUDE.mdには3つの情報だけを書きます。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;目的（WHY）&lt;&#x2F;dt&gt;
&lt;dd&gt;このリポジトリが何であるか。Zolaブログであること、tabi テーマを使っていること。新しいセッションのClaudeがプロジェクトを理解するための最小限の情報です。&lt;&#x2F;dd&gt;
&lt;dt&gt;マップ（WHAT）&lt;&#x2F;dt&gt;
&lt;dd&gt;記事のfrontmatterフォーマット、タグの命名規則への参照、ショートコードドキュメントへの参照。詳細はdocsに委ね、CLAUDE.mdには「どこを見ればよいか」だけを書きます。&lt;&#x2F;dd&gt;
&lt;dt&gt;ルール（HOW）&lt;&#x2F;dt&gt;
&lt;dd&gt;文体はですます調、descriptionは句点で終える、textlint-disableの使い方。Claudeが記事を書くときに常に意識すべき制約です。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;実際のCLAUDE.mdから、ショートコードのセクションを例に挙げます。以前は13個のショートコードそれぞれに構文、パラメータ一覧、使用例を書いていました。250行です。整理後は「ショートコードはtextlint-disableで囲む」というルールと、詳細ドキュメントへの参照だけになりました。個別の構文はClaude自身が必要なときに &lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt; 配下のショートコード定義書を読みに行けばよいのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Commands_—_Workflows&quot;&gt;Commands — Workflows&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;.claude&#x2F;commands&#x2F;&lt;&#x2F;code&gt; に配置したMarkdownファイルは、&lt;code&gt;&#x2F;コマンド名&lt;&#x2F;code&gt; で呼び出せるワークフロー定義です。セッションをまたいでも同じ手順が実行されるため、作業品質の一貫性が生まれます。&lt;&#x2F;p&gt;
&lt;p&gt;このブログでは6つのコマンドを定義しています。&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;&lt;code&gt;&#x2F;article-review&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;記事の品質レビュー（frontmatter、文体、アセット確認）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;article-publish&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;記事の公開（レビュー → OGP再生成 → ビルド検証 → コミット → push）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;article-cover&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;カバー画像生成（記事内容からDALL-E 3でcover.webpを生成）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;blog-review&lt;&#x2F;code&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;&#x2F;blog-refactor&lt;&#x2F;code&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;&#x2F;blog-release&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ブランチ運用のリリースフロー（CHANGELOG → PR → マージ → タグ）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;記事系（article-）とブログ基盤系（blog-）で命名体系を分けています。これは運用フローが根本的に異なるためです。記事はmainに直接push、ブログ設定はブランチを切ってPR経由でマージします。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;&#x2F;article-publish&lt;&#x2F;code&gt; の定義から、要点を抜粋して見てみましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot; data-name=&quot;.claude&#x2F;commands&#x2F;article-publish.md&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-entity z-name z-tag z-yaml&quot;&gt;description&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-string&quot;&gt; Publish an article. Run review, regenerate OGP,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  verify build, commit, and push to main automatically.&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;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\31  z-markdown&quot;&gt;# Article Publish&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-text&quot;&gt;Execute the full publish workflow automatically.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Prerequisite: the user has already confirmed the article&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;via &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`zola serve`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; preview.&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-heading z-markdown z-heading z-\32  z-markdown&quot;&gt;## Steps&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-text&quot;&gt;Execute in order. Stop and report if any step fails.&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 1. Run &#x2F;article-review&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Execute the full article quality review.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;If issues are found, stop and fix them before continuing.&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 2. Regenerate OGP Image&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; Delete the existing OGP image&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; Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`npm run ogp`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to regenerate&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 3. zola check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`zola check`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to verify no broken links or build errors.&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 4. Stage &amp;amp; Commit&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-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt; `git add .`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to stage all changes&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; Use &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`&#x2F;simple-commit:commit`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; skill to create the commit&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-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 5. Push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`git push origin main`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to publish.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドが実行する手順は、以前はCLAUDE.mdに散在するルールの組み合わせで「わかっているはず」と暗黙に期待していたものです。コマンドとして明示することで、どのセッションでも同じ品質で公開作業が完了します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Hooks_—_Guardrails&quot;&gt;Hooks — Guardrails&lt;&#x2F;h2&gt;
&lt;p&gt;Hooksは &lt;code&gt;.claude&#x2F;settings.json&lt;&#x2F;code&gt; に定義する、ツール実行の前後に自動で走るチェックです。CLAUDE.mdに「〜するな」と書いても、Claudeは忘れることがあります。Hooksは忘れません。&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;th&gt;動作&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;PreToolUse&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;git commit&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ブロック。&lt;code&gt;&#x2F;simple-commit:commit&lt;&#x2F;code&gt; の使用を強制&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PreToolUse&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;git add &amp;lt;個別ファイル&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ブロック。&lt;code&gt;git add .&lt;&#x2F;code&gt; のみ許可&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PreToolUse&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;themes&#x2F;&lt;&#x2F;code&gt; への Write&#x2F;Edit&lt;&#x2F;td&gt;&lt;td&gt;ブロック。サブモジュール保護&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PostToolUse&lt;&#x2F;td&gt;&lt;td&gt;content&#x2F;*.md への Write&#x2F;Edit&lt;&#x2F;td&gt;&lt;td&gt;Markdown画像記法 &lt;code&gt;![]()&lt;&#x2F;code&gt; を検出し、imageショートコード使用を指示&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;code&gt;git commit&lt;&#x2F;code&gt; のブロックを例に、実装を見てみましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;.claude&#x2F;settings.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;hooks&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;PreToolUse&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;      {&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;matcher&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;Bash&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;hooks&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;          {&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;type&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;command&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-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;jq -r &amp;#39;.tool_input.command&amp;#39; | grep -qE &amp;#39;^git commit&amp;#39; &amp;amp;&amp;amp; echo &amp;#39;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;decision&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;block&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;reason&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;git commit 直接実行は禁止です。&#x2F;simple-commit:commit スキルを使ってください&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;}&amp;#39; || true&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;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;Hooksの設計方針は「禁止ルールはHooksに、正のガイダンスはCLAUDE.mdに」です。「〜するな」はHooksで機械的にブロックし、「〜の代わりにこうする」はCLAUDE.mdやCommandsで伝えます。&lt;&#x2F;p&gt;
&lt;p&gt;この分離によってCLAUDE.mdから禁止文を削除できました。前向きなガイダンスだけが残り、読みやすいドキュメントになっています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;docs&#x2F;_—_Progressive_Context&quot;&gt;docs&#x2F; — Progressive Context&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt; にはCLAUDE.mdに収まらない詳細情報を配置します。Claudeは必要に応じてこれらのファイルを読みに行きます。&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;&lt;code&gt;docs&#x2F;tabi-shortcodes.md&lt;&#x2F;code&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;docs&#x2F;tag-rule.md&lt;&#x2F;code&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;docs&#x2F;TODO.md&lt;&#x2F;code&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;docs&#x2F;architectural-decision.md&lt;&#x2F;code&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;この層の設計原則は「CLAUDE.mdに場所を教え、詳細はdocsに置く」です。CLAUDE.mdのショートコードセクションには &lt;code&gt;See docs&#x2F;tabi-shortcodes.md&lt;&#x2F;code&gt; と一行書くだけで、Claudeはショートコードを使うときにそのファイルを読みに行きます。&lt;&#x2F;p&gt;
&lt;p&gt;毎セッションで250行のショートコードリファレンスをコンテキストに読み込む必要はありません。必要なときに必要な分だけ読む。これがProgressive Contextの考え方です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;責務分離の判断基準&quot;&gt;責務分離の判断基準&lt;&#x2F;h2&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;毎セッションで必ず意識すべきルール&lt;&#x2F;td&gt;&lt;td&gt;CLAUDE.md&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;複数ステップのワークフロー&lt;&#x2F;td&gt;&lt;td&gt;Commands&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;「〜するな」という禁止ルール&lt;&#x2F;td&gt;&lt;td&gt;Hooks&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;必要なときだけ参照する詳細情報&lt;&#x2F;td&gt;&lt;td&gt;docs&#x2F;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;迷ったときは「これをCLAUDE.mdから消したら、Claudeは間違えるか？」と自問してみてください。答えがNoなら、それはCLAUDE.mdに置くべき情報ではありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;CLAUDE.mdへ全部書く運用から、4層に分離する運用へ変えた結果を振り返ります。&lt;&#x2F;p&gt;
&lt;p&gt;CLAUDE.mdは458行から117行になりました。削減した341行が消えたのではなく、適切な層へ移動しただけです。ショートコードのリファレンスは&lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt;へ、公開フローはCommandsへ、禁止ルールはHooksへ。それぞれの情報が、もっとも効果的に機能する場所へ収まりました。&lt;&#x2F;p&gt;
&lt;p&gt;コンテキストが長いほど個々のルールへの注意が分散し、遵守率が下がります。CLAUDE.mdが短ければ、書いたルールが確実に守られます。ワークフローがCommandsに定義されていれば、セッション間で品質がブレません。Hooksが禁止ルールを機械的に強制すれば、「AIが忘れる」問題は起きません。&lt;&#x2F;p&gt;
&lt;p&gt;この4層アーキテクチャは、ブログに限らずあらゆるClaude Codeプロジェクトへ適用できるパターンです。CLAUDE.mdが長くなってきたら、責務の分離を検討してみてください。&lt;&#x2F;p&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;x.com&#x2F;BharukaShraddha&#x2F;status&#x2F;2029836408232497678&quot;&gt;Shraddha Bharuka (@BharukaShraddha)&lt;&#x2F;a&gt;. &quot;The Anatomy of a Claude Code Project&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;overview&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Claude Code Overview&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;memory&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Memory&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;best-practices&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Best practices&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;hooks&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Hooks&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;skills&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Skills&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">CLAUDE.mdに全部書いてしまい、肝心なルールが埋もれていませんか。CLAUDE.md、Commands、Hooks、docsの4層に責務を分離し、AIが忘れないガードレールとセッション間で一貫したワークフローを実現するリポジトリ設計パターンを、実例とともに解説します。</summary>
        </entry><entry xml:lang="en">
        <title>gyrotriage — DJIドローン映像のブレを診断し、Gyroflowのパラメータを自動推定するツール</title>
        <published>2026-03-07T22:00:00+09:00</published>
        <updated>2026-06-04T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/gyrotriage/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/gyrotriage/</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;03&amp;#x2F;gyrotriage&amp;#x2F;cover.webp?h=a52eaf44e6e2f027bce2&quot;
  alt=&quot;gyrotriage HUD出力例&quot; width=&quot;1440&quot; height=&quot;900&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;（2026-06-04更新）&lt;&#x2F;strong&gt; 本記事は当初、Gyroflowスタンドアロンアプリ向けの5つのパラメータを推奨する内容でした。その後、実運用のワークフローがDaVinci Resolve上のGyroflow OpenFXプラグインで完結することを踏まえ、推奨対象をプラグイン版「Adjust parameters」に一本化しました。以下では旧スタンドアロンアプリ版の記述に取り消し線を引き、新しい内容を併記しています。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;Gyroflowのパラメータ調整は面倒である&quot;&gt;Gyroflowのパラメータ調整は面倒である&lt;&#x2F;h2&gt;
&lt;p&gt;DJI NeoやAvataシリーズでFPV撮影をしている方なら、Gyroflowでの後処理は日常的な作業だと思います。EISをオフにして撮影し、Gyroflowでスタビライズする。この流れ自体は確立されていますが、問題はGyroflowのパラメータ調整です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;del&gt;Gyroflowには主に5つの調整パラメータがあります。&lt;&#x2F;del&gt;&lt;&#x2F;p&gt;
&lt;p&gt;DaVinci ResolveなどでGyroflow OpenFXプラグインを使う場合、調整の中心になるのは「Adjust parameters」パネルのSmoothnessとZoom limitです。スタンドアロンアプリ版にあった細かなパラメータはプラグインのUIには現れず、&lt;code&gt;.gyroflow&lt;&#x2F;code&gt; プロジェクト側に焼き込まれます（2026-06-04更新）。&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;Smoothness (1〜300)&lt;&#x2F;td&gt;&lt;td&gt;スムージングの強度。高いほどブレを強く除去するが、意図した動きも鈍る&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;del&gt;Max smoothness (s)&lt;&#x2F;del&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;del&gt;突発的なブレに対する最大補正量&lt;&#x2F;del&gt;（プラグイン版では非対応）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;del&gt;Max smoothness at high velocity (s)&lt;&#x2F;del&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;del&gt;高速旋回時の補正上限。短くすると旋回への追従性が上がる&lt;&#x2F;del&gt;（プラグイン版では非対応）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Zoom limit (%)&lt;&#x2F;td&gt;&lt;td&gt;安定化で生じる黒縁を隠すためのズーム上限&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;del&gt;Zooming speed (s)&lt;&#x2F;del&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;del&gt;Dynamic zoomingのFOV遷移速度&lt;&#x2F;del&gt;（プラグイン版では非対応）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FOV&lt;&#x2F;td&gt;&lt;td&gt;画角。算出対象外でベースライン1.0を提示&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;プラグインのSmoothnessは1〜300のスケール（デフォルト50）で、gyrotriageが従来出力していた百分率の値をそのまま入力できます。強く設定すればブレは消えますが、意図したカメラワークまで平滑化されたり、クロップで解像度が落ちたりします。適切な値はクリップごとに異なるため、毎回プレビューを見ながら試行錯誤することになります。&lt;&#x2F;p&gt;
&lt;p&gt;1本2本ならまだしも、フライト後に何十本ものクリップを処理するときは正直つらい作業です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gyrotriageでパラメータ推定を自動化する&quot;&gt;gyrotriageでパラメータ推定を自動化する&lt;&#x2F;h2&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;gyrotriage&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;p&gt;そこで作ったのが &lt;strong&gt;gyrotriage&lt;&#x2F;strong&gt; です。DJIドローンのMP4ファイルを渡すだけで、埋め込まれたモーションデータを解析し、ブレの度合いをスコアリングしつつ、&lt;del&gt;Gyroflowの5つのパラメータ&lt;&#x2F;del&gt;Gyroflow OpenFXプラグイン（DaVinci Resolve等）に入力するパラメータを自動で推定します。&lt;&#x2F;p&gt;
&lt;p&gt;考え方はシンプルです。パイロットが意図したカメラワーク（パン・チルト・旋回）と除去したいブレ（風や機体振動）では、動きの周波数帯域が異なります。ゆっくりしたパンは1Hz以下の低周波、プロペラ振動は20Hz以上の高周波に現れます。この境界を信号処理で自動検出し、Gyroflowの内部ロジックに合わせてパラメータに変換しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;インストール&quot;&gt;インストール&lt;&#x2F;h2&gt;
&lt;p&gt;macOSの場合はHomebrewでインストールできます。&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 gyrotriage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rustの開発環境がある場合はcargoからもインストールできます。&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;cargo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install --path .&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;基本的な使い方はMP4ファイルを渡すだけです。&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;gyrotriage&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; DJI_0001.MP4&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;File:        DJI_20260228080801_0003_D.MP4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Duration:    30.3s (60593 samples @ 2000Hz)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Score:       100 &#x2F; 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Level:       SEVERE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RMS:         34.8 °&#x2F;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Peak:        644.0 °&#x2F;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pitch:       avg=1.4°&#x2F;s  std=2.2°&#x2F;s  max=47.9°&#x2F;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Roll:        avg=11.7°&#x2F;s  std=13.5°&#x2F;s  max=251.1°&#x2F;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Yaw:         avg=3.3°&#x2F;s  std=4.4°&#x2F;s  max=89.0°&#x2F;s&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;Gyroflow plugin (Adjust parameters):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Smoothness:           21&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Zoom limit:           118&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  FOV:                  1.000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Integration method:   None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Lens correction:      100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;末尾の「Gyroflow plugin (Adjust parameters)」ブロックが、Gyroflow OpenFXプラグインの「Adjust parameters」パネルにそのまま入力できる推奨値です。&lt;del&gt;最後の2行がGyroflowに入力する推定パラメータです。&lt;&#x2F;del&gt; このうちSmoothnessとZoom limitはモーション解析から算出した値、Integration methodとLens correctionはDJI機の特性に基づく固定推奨です。この値をプラグインのパネルに入力すれば、そこから微調整を始められます（2026-06-04更新）。&lt;&#x2F;p&gt;
&lt;p&gt;なお旧スタンドアロンアプリ版では、末尾の出力が &lt;del&gt;&lt;code&gt;Gyroflow: smoothness=21% max=0.300s max@hv=0.030s zoom_limit=118% zooming_speed=2.6s&lt;&#x2F;code&gt;&lt;&#x2F;del&gt; という5値の形式でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;HUD表示で直感的にブレを把握する&quot;&gt;HUD表示で直感的にブレを把握する&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;--visual&lt;&#x2F;code&gt; オプションを付けると、ブレの特性をHUD風のグラフィックで表示します。&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;gyrotriage&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; DJI_0001.MP4 --visual&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;冒頭のカバー画像がHUD出力の実例です。画面には以下の情報が表示されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;スコアゲージ&lt;&#x2F;strong&gt;: ブレの重大度を0〜100で表示（STABLE &#x2F; MILD &#x2F; MODERATE &#x2F; SEVEREの4段階）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;レーダーチャート&lt;&#x2F;strong&gt;: Pitch・Roll・Yawの3軸でブレの偏りを可視化&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;del&gt;Gyroflowに入力する5つの値&lt;&#x2F;del&gt;Gyroflow OpenFXプラグインに入力する推奨値&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;数値だけでは分かりにくい「このクリップはRoll方向のブレが支配的」「後半に激しいブレが集中している」といった特性が一目で把握できます。Gyroflowプラグインを適用する前に、どのクリップにどの程度の処理が必要かをトリアージするのに役立ちます。&lt;&#x2F;p&gt;
&lt;p&gt;HUD画像は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-entity z-name z-function&quot;&gt;gyrotriage&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; DJI_0001.MP4 --output-image shake.png&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;WezTermやiTerm2などSixel&#x2F;iTerm2プロトコルに対応したターミナルでは &lt;code&gt;--visual&lt;&#x2F;code&gt; でインライン表示されます。非対応のターミナルでは &lt;code&gt;--output-image&lt;&#x2F;code&gt; でファイル出力してください。&lt;&#x2F;p&gt;
&lt;p&gt;テキストのみの環境向けには &lt;code&gt;--sparkline&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-entity z-name z-function&quot;&gt;gyrotriage&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; DJI_0001.MP4 --sparkline&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;gyrotriageはブレの重大度を0〜100のスコアで表示します。&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;STABLE&lt;&#x2F;td&gt;&lt;td&gt;0〜25&lt;&#x2F;td&gt;&lt;td&gt;ブレはほぼなし。スタビライズ不要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MILD&lt;&#x2F;td&gt;&lt;td&gt;26〜50&lt;&#x2F;td&gt;&lt;td&gt;軽微なブレ。スタビライズは任意&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MODERATE&lt;&#x2F;td&gt;&lt;td&gt;51〜75&lt;&#x2F;td&gt;&lt;td&gt;目に見えるブレ。Gyroflow推奨&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SEVERE&lt;&#x2F;td&gt;&lt;td&gt;76〜100&lt;&#x2F;td&gt;&lt;td&gt;激しいブレ。Gyroflow必須&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;DJI Air 3Sのような3軸ジンバル搭載機ではほぼSTABLEになりますが、DJI Neoのような1軸ジンバル機やAvataシリーズでアクロバティックな飛行をした場合はMODERATE〜SEVEREになることが多いです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;推定パラメータの使い方&quot;&gt;推定パラメータの使い方&lt;&#x2F;h2&gt;
&lt;p&gt;~~出力された5つのパラメータはGyroflowのUIに直接入力できます。~~出力された推奨値はGyroflow OpenFXプラグインの「Adjust parameters」パネルに直接入力できます（2026-06-04更新）。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;del&gt;Gyroflowでクリップを開く&lt;&#x2F;del&gt;DaVinci ResolveのタイムラインでクリップにGyroflowプラグインを適用する&lt;&#x2F;li&gt;
&lt;li&gt;出力された値をそれぞれのスライダーに入力する&lt;&#x2F;li&gt;
&lt;li&gt;プレビューで確認し、必要に応じて微調整する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;このとき、Integration methodはNone、Lens correctionは100、FOVは1.0を起点にします。DJI機はクォータニオンを記録済みなので再積分が不要で、正しいレンズプロファイルを読み込めばフル補正で問題ないためです。&lt;&#x2F;p&gt;
&lt;p&gt;推定値はあくまで調整の出発点です。ブレが残っている場合はSmoothnessを上げる、カメラワークが鈍く感じる場合はSmoothnessを下げる、といった微調整で仕上げてください。ゼロからスライダーを動かして探るよりも、妥当な出発点があるだけで調整時間は大幅に短縮できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対応機体と撮影条件&quot;&gt;対応機体と撮影条件&lt;&#x2F;h2&gt;
&lt;p&gt;モーションデータがMP4へ埋め込まれるDJI機種に対応しています。ただし撮影時の設定次第ではモーションデータが記録されないため、注意が必要です。&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;DJI Avata &#x2F; Avata 2&lt;&#x2F;td&gt;&lt;td&gt;EIS（Rocksteady）オフ、FOV Wide&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;DJI Neo &#x2F; Neo2&lt;&#x2F;td&gt;&lt;td&gt;アスペクト比4:3（EISは自動的にオフ）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Avataシリーズの場合、Rocksteadyをオンにしているとモーションデータが記録されません。Gyroflowで後処理する前提なら、撮影時はRocksteadyオフ・FOV Wideで撮影してください。&lt;&#x2F;p&gt;
&lt;p&gt;DJI Neoの場合、16:9で撮影するとモーションデータが記録されません。4:3で撮影する必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;DJI Air 3Sなど3軸ジンバル搭載機はGyroflow自体を必要としないケースが多く、対象外としています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;実際の効果&quot;&gt;実際の効果&lt;&#x2F;h2&gt;
&lt;p&gt;gyrotriageで推定したパラメータを微調整なしでそのままGyroflow OpenFXプラグインに適用した映像（右）と、オリジナルの未処理映像（左）の比較です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;youtube-container&quot; style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;uEInUgQIBrs&quot;
    style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&quot;
    frameborder=&quot;0&quot;
    allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;注意事項&quot;&gt;注意事項&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;推定値は信号処理に基づく客観的な算出であり、映像の主観的な品質評価は含まない&lt;&#x2F;li&gt;
&lt;li&gt;非常にゆっくりしたブレ（0.3Hz未満）は意図した動きと区別できない&lt;&#x2F;li&gt;
&lt;li&gt;GyroflowのDefaultアルゴリズムを前提としており、Plain 3Dや軸別モードでは推定値の解釈が異なる&lt;&#x2F;li&gt;
&lt;li&gt;極端に短いクリップ（2秒未満）では推定精度が低下する&lt;&#x2F;li&gt;
&lt;li&gt;商用空撮など業務用途では、必ずGyroflowのプレビューで結果を検証すること&lt;&#x2F;li&gt;
&lt;&#x2F;ul&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;gyroflow.xyz&#x2F;&quot;&gt;Gyroflow&lt;&#x2F;a&gt;. 「Gyroflow - Video stabilization using gyroscope data」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Gyroflowのパラメータ調整に毎回悩んでいませんか。gyrotriageはDJIドローンのMP4ファイルからブレを診断し、DaVinci ResolveのGyroflow OpenFXプラグインに入力するパラメータを自動で推定するCLIツールです。導入方法から使い方、出力の読み方までを解説します。</summary>
        </entry><entry xml:lang="en">
        <title>AIエージェントが&quot;同僚&quot;になる時代 ── AWS ProServe変革と日本のSIerへの示唆</title>
        <published>2026-03-05T00:00:00+00:00</published>
        <updated>2026-03-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/aws-proserve-innovation/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/aws-proserve-innovation/</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;03&amp;#x2F;aws-proserve-innovation&amp;#x2F;cover.webp?h=684f9f74312c298756a4&quot;
  alt=&quot;AIロボットとビジネスパーソンが会議室で協働するイメージ&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;次のBusiness Insiderの記事に基づいた考察です。&lt;&#x2F;p&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;www.businessinsider.com&amp;#x2F;amazon-aws-cloud-customers-proserve-consulting-fees-ai-automates-work-2026-2&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;AWS_ProServeとは&quot;&gt;AWS ProServeとは&lt;&#x2F;h2&gt;
&lt;p&gt;AWS ProserveはAWSの技術支援サービスです。&lt;&#x2F;p&gt;
&lt;p&gt;AWSのユーザーにとっては、「SA」（Solutions Architect）と呼ばれる無償の技術支援のほうが馴染み深いかもしれません。一方、AWS ProServe（Professional Services）は、有償の支援サービスです。&lt;&#x2F;p&gt;
&lt;p&gt;AWSの公式エキスパートが顧客のチームに入り、一緒にプロジェクトを成功させるコンサルティング部門です（ProServeについては&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;note.com&#x2F;jazzy_slug5355&#x2F;n&#x2F;n6d3fa6120c79&quot;&gt;こちらの解説記事&lt;&#x2F;a&gt;が分かりやすいです）。クラウド移行やモダナイゼーションといった技術コンサルティングに加え、DX戦略の策定やビジネス変革の支援まで幅広く対応しています。単なる代行ではなく、顧客が自らAWSを使いこなせるようになる「自走支援」に重点を置いている点が特徴です。&lt;&#x2F;p&gt;
&lt;p&gt;ProServeはAWSの収益創出に大きく貢献しています&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;。内部文書によれば、売上1,290億ドル（2025年）のAWSを10年以内に5,000億ドル企業へ押し上げるドライバーとしてProServeを位置づけており、その重要度は増す一方です。&lt;&#x2F;p&gt;
&lt;p&gt;筆者は2021年から2024年まで日本のProServeに在籍していました。日本のProServeはまだ規模が小さく、米国本体に比べれば発展途上の組織です。しかしその分、一人ひとりの守備範囲が広く、技術・ビジネス両面で顧客に向き合う経験を積める環境でした。ProServeの役割は年々広がっており、技術支援にとどまらずビジネス変革の伴走へ変化してきたことを肌で感じていました。そのProServeが今、AIによってさらに大きく変わろうとしています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AIを「デジタル従業員」にするという衝撃&quot;&gt;AIを「デジタル従業員」にするという衝撃&lt;&#x2F;h2&gt;
&lt;p&gt;Business Insiderが入手したProServeの内部文書によると、方針の核心はシンプルです。AIエージェントを「&lt;strong&gt;デジタル従業員（digital employees）&lt;&#x2F;strong&gt;」と位置づけ、人間と同列の要員としてプロジェクトに組み込むというものです。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIを便利なツールとして活用する企業は既に多くあります。筆者の古巣であるIBMも、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;ibm-cobol-claude-irony&quot;&gt;以前の記事&lt;&#x2F;a&gt;で取り上げたAIエージェント「IBM Bob」を社内10,000人超の開発者に展開しています。McKinseyのCEO Bob Sternfelsは、40,000人の人間の従業員に加え25,000のAIエージェントを「従業員」として数えていると発表しました。検索・分析タスクだけで年間150万時間を削減し、6か月で250万枚のチャートを生成したとしています。2026年末までにAIエージェント数を人間の従業員数と同数にする目標も掲げています。ただし、このエージェント数を誇るアプローチに対しては懐疑的な声もあります。競合のEYは「エージェント数が価値に直結するわけではない」、PwCのチーフAIオフィサーも「誤った測定基準だ」と指摘しています。PwC、EY、Boston Consulting Groupも含め、各社がAIエージェントの活用を進めてはいるものの、その位置づけはあくまで「人間の生産性を高めるツール」にとどまっています。&lt;&#x2F;p&gt;
&lt;p&gt;Business Insiderの報道が正しければ、ProServeが一線を画すのは、AIを「ツール」ではなく「デジタル従業員」として組織に位置づけようとしている点です。内部文書には具体的に以下のような施策が記載されていたとされています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;「Agentic AI」専任チームの設立と「Agent Operating Model」の導入&lt;&#x2F;li&gt;
&lt;li&gt;AI Agent Service and Marketplaceの構築による、エージェントの開発・配備・管理の組織化&lt;&#x2F;li&gt;
&lt;li&gt;特定タスクの最大90%自動化を見込んだ生産性目標&lt;&#x2F;li&gt;
&lt;li&gt;人員を大幅に増やさず、従業員あたり収益を前年比20%増とする計画&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;実際、AWSは2025年11月に「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;machine-learning&#x2F;accelerate-enterprise-solutions-with-agentic-ai-powered-consulting-introducing-aws-professional-service-agents&#x2F;&quot;&gt;AWS Professional Service Agents&lt;&#x2F;a&gt;」を公式に発表し、agent-first consultingの取り組みを公にしています。AWS Professional Services Delivery Agentは、提案書の作成を数週間から数時間に短縮し、生成AIアプリ開発プロジェクトの所要期間を6〜8週間から数日に圧縮したとされています。大規模な移行プロジェクトでも、従来12か月以上かかっていた期間を数か月に短縮できるとしています。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、これは内部文書のリークだけの話ではなく、AWS自身が公式に推進している方針なのです。&lt;strong&gt;プロジェクトの体制表に人間コンサルタントとAIエージェントが並ぶ&lt;&#x2F;strong&gt;。これはツール導入の延長線上にはない、組織設計そのものの転換です。&lt;&#x2F;p&gt;
&lt;p&gt;この動きが日本のSIer・コンサルティング会社に示唆するものは大きいです。記事によれば、Booking.comやDanske Bankは既にProServeに対し「AI-delivered pricing」（AI前提の低価格）での契約再交渉を求めているとのことです。こうした圧力は遅かれ早かれ日本にも波及するのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;ここで筆者が強く懸念しているのは、日本のSIer業界に根深い「人月モデル」の問題です。日本のSIerの多くは契約形態としては請負契約を採用していますが、実態としては人月単価を積み上げて見積りを作り、それを顧客への価値訴求の根拠としています。つまり「エンジニアが何人月かかるか」が価格の正当性そのものになっている構造です。&lt;&#x2F;p&gt;
&lt;p&gt;AIエージェントが要員として組み込まれ、同じ成果をより少ない人間の稼働で出せる時代になったとき、この価値訴求は成り立つでしょうか。「人が何人月かけたか」ではなく「どんな成果を出したか」で価値を問われるようになれば、人月を積み上げる以外の方法で自社のサービスの価値を顧客に説明できなければなりません。それができる日本のSIerがどれだけあるのか。筆者は正直、心許なく思っています。&lt;&#x2F;p&gt;
&lt;p&gt;AIエージェントを要員としてデリバリーに組み込む体制を前提としている日本の企業は、まだほとんどありません。ProServeの動きが本格化すれば、日本のSIer・コンサルティング会社にとってパラダイムシフトの始まりになり得ると筆者は考えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;準委任からFixed_Priceへの転換に思うこと&quot;&gt;準委任からFixed Priceへの転換に思うこと&lt;&#x2F;h2&gt;
&lt;p&gt;もう1つ、元ProServe社員として見過ごせない変化があります。課金モデルの転換です。&lt;&#x2F;p&gt;
&lt;p&gt;ProServeの内部文書は、2026年までにプロジェクトの75%をFixed Price（固定価格）にする目標を掲げていました。&lt;&#x2F;p&gt;
&lt;p&gt;AWS ProServeでは従来、準委任契約（Time &amp;amp; Materials）が主流でした。準委任は想定稼働時間にコンサルタント単価を掛けるシンプルな構造で、提供者側のリスクが比較的低いモデルです。それが75%をFixed Priceにするというのは、組織文化の根本的な転換を意味します。&lt;&#x2F;p&gt;
&lt;p&gt;顧客側の論理は明快です。「AIが作業を高速化・自動化しているのに、なぜ同じ料金を払わなければならないのか」。この問いに、成果で応えるモデルへ移行せざるを得なくなっているのです。&lt;&#x2F;p&gt;
&lt;p&gt;Fixed Priceへの移行は、提供者側に大きな能力変革を要求します。緻密なスコープ定義、正確な工数見積り、リスク管理、そしてビジネスケースの算出が不可欠です。筆者は日本IBM出身ですが、IBMのサービス事業では請負契約が主流であり、こうした見積り・リスク管理の規律が組織に染みついていました。一方、ProServe在籍時に感じていたのは、準委任が主流の環境ではそうした規律が育ちにくいということです。技術力は高くても、プロジェクトを経営的に組み立てる力は別物です。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、ProServeには技術力の高さと、顧客の自走を支援するという明確なミッションがあります。この強みは、AI時代にも変わらない価値です。AIエージェントという新たな「要員」を得たことで、技術力を活かしながら成果ベースのデリバリーに挑む。ProServeの変革は、技術集団が経営的視点を獲得していく過程でもあると筆者は見ています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Business Insiderが報じたProServeの変革は、2つの点で従来のAI活用と次元が異なります。&lt;&#x2F;p&gt;
&lt;p&gt;1つ目は、AIエージェントを「ツール」ではなく「デジタル従業員」として組織に位置づけたこと。2つ目は、それに伴い課金モデルを準委任からFixed Priceへ転換しようとしていることです。&lt;&#x2F;p&gt;
&lt;p&gt;日本のSIer・コンサルティング業界にとって、この報道は他人事ではありません。人月単価の積み上げで価値を訴求してきた従来のモデルは、AIが要員になる時代には通用しなくなる可能性があります。「何人月かけたか」ではなく「どんな成果を出したか」で問われる時代に、自社のサービスの価値をどう説明するのか。その問いに向き合う時期が来ていると感じています。&lt;&#x2F;p&gt;
&lt;p&gt;では、私たちは何から始められるでしょうか。筆者は3つのことを考えています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;まず、自分たちの提供するサービスの価値を「人月」ではなく「成果」で言語化してみること。これは個人レベルでも今日から始められる&lt;&#x2F;li&gt;
&lt;li&gt;次に、AIエージェントを「便利なツール」ではなく「チームメンバー」として扱うプロジェクト運営を小さく試してみること。AIに任せられるタスクを洗い出し、人間とAIの役割分担を設計する経験は、来るべき変化への備えになる&lt;&#x2F;li&gt;
&lt;li&gt;そして、技術力だけでなく、スコープ定義や見積り、ビジネスケースの組み立てといった「プロジェクトを経営する力」を意識的に磨くこと&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ProServeの変革が示しているのは、AIの進化によってコンサルティングの価値の源泉が変わるということです。変化は脅威でもあり、機会でもあります。早く動いた者が、次の時代のスタンダードを作ることになるでしょう。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&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;筆者は2021〜2024年にAWS ProServeに在籍していましたが、本記事は公開情報（Business Insiderの報道等）および筆者の個人的な所感に基づいており、AWSの機密情報を開示するものではありません。記載内容は筆者個人の見解であり、AWSの公式見解を代表するものではありません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&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.businessinsider.com&#x2F;&quot;&gt;Business Insider&lt;&#x2F;a&gt;. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.businessinsider.com&#x2F;amazon-aws-cloud-customers-proserve-consulting-fees-ai-automates-work-2026-2&quot;&gt;AI rewrites the economics of Amazon&#x27;s cloud-consulting business&lt;&#x2F;a&gt;&quot; (Eugene Kim, Feb 26, 2026)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.businessinsider.com&#x2F;&quot;&gt;Business Insider&lt;&#x2F;a&gt;. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.businessinsider.com&#x2F;amazon-cloud-reboot-future-consulting-ai-era-2026-3&quot;&gt;Amazon&#x27;s cloud reboot shows the future of consulting in the AI era&lt;&#x2F;a&gt;&quot; (Alistair Barr, Mar 4, 2026)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;machine-learning&#x2F;&quot;&gt;AWS Machine Learning Blog&lt;&#x2F;a&gt;. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;machine-learning&#x2F;accelerate-enterprise-solutions-with-agentic-ai-powered-consulting-introducing-aws-professional-service-agents&#x2F;&quot;&gt;Accelerate enterprise solutions with agentic AI-powered consulting: Introducing AWS Professional Service Agents&lt;&#x2F;a&gt;&quot; (Nov 17, 2025)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;siliconangle.com&#x2F;&quot;&gt;SiliconANGLE&lt;&#x2F;a&gt;. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;siliconangle.com&#x2F;2025&#x2F;11&#x2F;17&#x2F;aws-develops-ai-agents-speed-aws-proserve-consulting-projects&#x2F;&quot;&gt;AWS develops AI agents to speed up AWS ProServe consulting projects&lt;&#x2F;a&gt;&quot; (Nov 17, 2025)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dnyuz.com&#x2F;&quot;&gt;Dnyuz&lt;&#x2F;a&gt;. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dnyuz.com&#x2F;2026&#x2F;02&#x2F;13&#x2F;mckinsey-says-it-has-25000-ai-agents-its-rivals-say-thats-not-a-metric-of-success&#x2F;&quot;&gt;McKinsey says it has 25,000 AI agents. Its rivals say that&#x27;s not a metric of success.&lt;&#x2F;a&gt;&quot; (Feb 13, 2026)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;note.com&#x2F;&quot;&gt;note&lt;&#x2F;a&gt;. 「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;note.com&#x2F;jazzy_slug5355&#x2F;n&#x2F;n6d3fa6120c79&quot;&gt;AWS ProServe（プロフェッショナルサービス）とは？&lt;&#x2F;a&gt;」&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;Business Insiderが入手した内部文書によると、ProServeのコンサルティング業務は2024年にAWSの約125億ドルの収益創出に貢献したとされています。 &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">AWS ProServeがAIエージェントを「デジタル従業員」としてプロジェクトに組み込む方針を打ち出しました。人月モデルに依存する日本のSIerへの影響と、成果ベースへの転換について元ProServe社員の視点で考察します。
</summary>
        </entry><entry xml:lang="en">
        <title>SPFのDNSルックアップ上限10回、あなたの組織は大丈夫？</title>
        <published>2026-03-03T00:00:00+00:00</published>
        <updated>2026-03-03T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/spf-lookup-limit-risk/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/spf-lookup-limit-risk/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;p&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;spf-lookup-limit-risk&amp;#x2F;cover.webp?h=bc1f2cf07dfaabe490a7&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&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;spf-lookup-limit-risk&quot;&gt;Zenn&lt;&#x2F;a&gt; に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;p&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;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;「ある日突然、自組織からのメールが取引先に届かなくなった」——そんな事態が、メール配信サービスを複数利用している組織で実際に起こり得ます。原因は、SPF（Sender Policy Framework）のDNSルックアップ上限です。&lt;&#x2F;p&gt;
&lt;p&gt;外部のメール配信サービスを導入するたびにSPFレコードへ &lt;code&gt;include&lt;&#x2F;code&gt; を追加していくと、気づかないうちに上限へ近づきます。しかも、上限超過のトリガーは自組織の操作ではなく、外部サービス側の設定変更かもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、SPFのDNSルックアップ上限の仕組みを解説し、上限超過のリスクと対策を整理します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;SPFの仕組みとDNSルックアップ上限&quot;&gt;SPFの仕組みとDNSルックアップ上限&lt;&#x2F;h2&gt;
&lt;p&gt;SPFは、メールの送信元ドメインが「どのサーバーからの送信を許可しているか」をDNSのTXTレコードで宣言する仕組みです。受信側メールサーバーは、送信元IPアドレスがSPFレコードに含まれているかを検証し、正当な送信元かどうかを判断します。&lt;&#x2F;p&gt;
&lt;p&gt;SPFレコードの例を示します。&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;v=spf1 ip4:192.0.2.0&#x2F;24 include:spf.example.com ~all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この例では、&lt;code&gt;192.0.2.0&#x2F;24&lt;&#x2F;code&gt; のIPレンジからの送信と、&lt;code&gt;spf.example.com&lt;&#x2F;code&gt; が許可する送信元を正当とみなします。&lt;&#x2F;p&gt;
&lt;p&gt;SPFの検証は受信側メールサーバーで行われます。メールを受け取ったサーバーが送信元ドメインのSPFレコードをDNSに問い合わせ、送信元IPが許可されているかを確認します。この検証過程でDNSルックアップが発生しますが、RFC 7208（Section 4.6.4）により、1回のSPF検証で実行できるDNSルックアップは最大10回と制限されています。この制限は、SPF検証によるDNSサーバーへの負荷を防ぐために設けられたものです。&lt;&#x2F;p&gt;
&lt;p&gt;すべてのメカニズムがDNSルックアップを消費するわけではありません。消費するメカニズムとしないメカニズムを表にまとめます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;メカニズム &#x2F; 修飾子&lt;&#x2F;th&gt;&lt;th&gt;DNSルックアップ&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ip4&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;ip6&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;0回（IP直接指定のためDNS不要）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;a&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;mx&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回（＋MXレコードが指すAレコードの解決）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回 ＋ 参照先のSPFレコード内のルックアップ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;redirect&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;exists&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;重要なのは &lt;code&gt;include&lt;&#x2F;code&gt; の挙動です。&lt;code&gt;include&lt;&#x2F;code&gt; は参照先のSPFレコードをさらに評価するため、参照先に &lt;code&gt;include&lt;&#x2F;code&gt; や &lt;code&gt;a&lt;&#x2F;code&gt; が含まれていれば、それらも合算されます。つまり、1つの &lt;code&gt;include&lt;&#x2F;code&gt; が実際には複数回のルックアップを消費する場合があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;includeの入れ子で上限に近づく実例&quot;&gt;includeの入れ子で上限に近づく実例&lt;&#x2F;h2&gt;
&lt;p&gt;架空の組織 &lt;code&gt;example.or.jp&lt;&#x2F;code&gt; を例に考えます。この組織では業務メールに加えて、メールマガジン配信に3つの外部サービスを利用しています。SPFレコードは以下のようになっています。&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;v=spf1 ip4:192.0.2.0&#x2F;29 ip4:198.51.100.1 include:spf.mail-a.example include:spf.mail-b.example include:spf.mail-c.example include:spf.bizmail.example ~all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;各エントリのDNSルックアップ数を確認します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;エントリ&lt;&#x2F;th&gt;&lt;th&gt;DNSルックアップ&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ip4:192.0.2.0&#x2F;29&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;0回（IP直接指定）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ip4:198.51.100.1&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;0回（IP直接指定）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.mail-a.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.mail-b.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回 ＋ 内部で3回 = 4回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.mail-c.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.bizmail.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;合計&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;7回 &#x2F; 上限10回&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;一見すると余裕がありそうですが、問題は &lt;code&gt;spf.mail-b.example&lt;&#x2F;code&gt; の内部構造です。このSPFレコードは以下のようになっています。&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;v=spf1 exists:%{i}.spf.mail-b1.example exists:%{i}.spf.mail-b2.example include:spf.mail-b3.example ~all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;include&lt;&#x2F;code&gt; 1つで4回のルックアップを消費しています。そして、この内訳は外部サービス側の設定に依存しています。&lt;&#x2F;p&gt;
&lt;p&gt;ここに大きなリスクがあります。外部サービスがインフラ変更に伴いSPFレコードへ &lt;code&gt;include&lt;&#x2F;code&gt; や &lt;code&gt;a&lt;&#x2F;code&gt; を追加すれば、自組織が何も変更していなくてもルックアップ数が増加します。たとえば &lt;code&gt;spf.mail-b.example&lt;&#x2F;code&gt; が内部で1つ &lt;code&gt;include&lt;&#x2F;code&gt; を追加するだけで、合計は8回になり、上限までわずか2回です。さらに別のサービスも同様の変更をすれば、上限を超えてしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;上限を超えるとどうなるか&quot;&gt;上限を超えるとどうなるか&lt;&#x2F;h2&gt;
&lt;p&gt;SPFのルックアップ数が10回を超えると、SPFの検証結果は &lt;code&gt;permerror&lt;&#x2F;code&gt;（恒久的エラー）になります。これは「SPFレコードが壊れている」とみなされる状態です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;permerror&lt;&#x2F;code&gt; が発生すると、受信側メールサーバーの設定に応じて以下のいずれかが起こります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;メールが拒否される（バウンス）&lt;&#x2F;li&gt;
&lt;li&gt;迷惑メールフォルダに振り分けられる&lt;&#x2F;li&gt;
&lt;li&gt;DMARCのSPF判定がfailとなり、DMARCポリシー次第でメールが拒否される&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に厄介なのは、この問題が自組織側からは気づきにくい点です。送信自体は正常に行われ、送信者にはエラーが返らない場合もあります。受信側で静かにスパム判定されるため、「最近メールの返信が来ない」「メルマガの開封率が急落した」といった間接的な兆候で初めて気づくことになります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自分のドメインのルックアップ数を確認する方法&quot;&gt;自分のドメインのルックアップ数を確認する方法&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;dig&lt;&#x2F;code&gt; コマンドでSPFレコードの内容を確認できます。&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;dig&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +short TXT example.or.jp&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; spf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;表示されたSPFレコードに含まれる &lt;code&gt;include&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-entity z-name z-function&quot;&gt;dig&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +short TXT spf.mail-b.example&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;手動での再帰的な確認は手間がかかるため、オンラインツールの利用も有効です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MXToolbox SPF Record Lookup&lt;&#x2F;strong&gt; — SPFレコードの内容とDNSルックアップ数を自動計算してくれる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;dmarcian SPF Surveyor&lt;&#x2F;strong&gt; — SPFレコードの構造をツリー表示で可視化できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらのツールにドメイン名を入力するだけで、現在のルックアップ数と上限までの余裕を確認できます。定期的にチェックしておくことをお勧めします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策&quot;&gt;対策&lt;&#x2F;h2&gt;
&lt;p&gt;SPFルックアップ上限の問題に対して、短期的な対策と中長期的な対策があります。&lt;&#x2F;p&gt;
&lt;p&gt;まず短期的な対策として、メール送信経路を棚卸しします。SPFレコードに登録されている &lt;code&gt;include&lt;&#x2F;code&gt; やIPアドレスが、現在も使われているかを確認します。利用を終了したサービスの &lt;code&gt;include&lt;&#x2F;code&gt; が残っていると、ルックアップ数を無駄に消費するだけでなく、そのサービスのIPレンジが自ドメインの正当な送信元として許可されたままになります。これはなりすましに悪用されるリスクでもあります。&lt;&#x2F;p&gt;
&lt;p&gt;次に、メール配信サービスの統合を検討します。メルマガ配信に複数のサービスを併用している場合、1つに統合すれば &lt;code&gt;include&lt;&#x2F;code&gt; の数を減らせます。配信実績の分析も一元化でき、コスト管理も簡素化されます。&lt;&#x2F;p&gt;
&lt;p&gt;これらの根本対策とは別に、技術的な回避策も存在します&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-spf-workaround-1&quot;&gt;&lt;a href=&quot;#fn-spf-workaround&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。ただし運用上の注意点があるため、まずは送信経路の整理を優先すべきです。&lt;&#x2F;p&gt;
&lt;p&gt;最後に、中長期的な対策としてDMARCポリシーの段階的強化があります。DMARCはSPFとDKIMの認証結果に基づいて、認証失敗時のメール処理方針を宣言する仕組みです。ポリシーは以下の順で強化します。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;p=none&lt;&#x2F;code&gt;（監視モード）でDMARCレポートを収集し、全送信経路の認証状況を把握する&lt;&#x2F;li&gt;
&lt;li&gt;全経路でSPF・DKIMがpassすることを確認したうえで &lt;code&gt;p=quarantine&lt;&#x2F;code&gt;（隔離）に移行する&lt;&#x2F;li&gt;
&lt;li&gt;一定期間の監視後、問題がなければ &lt;code&gt;p=reject&lt;&#x2F;code&gt;（拒否）に移行する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;送信経路が整理されていれば、この移行は技術的には難しくありません。逆に、送信経路が乱立したままでは各経路の認証状況を把握すること自体が困難であり、DMARC強化は事実上不可能です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;SPFのDNSルックアップ上限10回は、メール配信サービスを複数利用する組織にとって見落とされがちなリスクです。外部サービスの &lt;code&gt;include&lt;&#x2F;code&gt; は入れ子構造でルックアップ数が膨らみ、しかも外部サービス側の変更で自組織のルックアップ数が増加するという、制御しにくい特性があります。&lt;&#x2F;p&gt;
&lt;p&gt;まずは自分のドメインの現在のルックアップ数を確認してみてください。上限に近づいている場合は、不要な &lt;code&gt;include&lt;&#x2F;code&gt; の削除やサービスの統合を検討し、DMARCポリシーの強化と合わせてメール配信の信頼性を確保していくことが重要です。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-spf-workaround&quot;&gt;
&lt;p&gt;技術的な回避策としてSPF MacroとSPF flatteningがあります。SPF Macroは &lt;code&gt;exists&lt;&#x2F;code&gt; メカニズムと変数を組み合わせてルックアップ数を抑える手法です。SPF flatteningは &lt;code&gt;include&lt;&#x2F;code&gt; 先のIPアドレスを直接 &lt;code&gt;ip4&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;ip6&lt;&#x2F;code&gt; で記述してルックアップを削減する手法です。ただしflatteningは参照先のIPが変更されたときに追従が必要なため、自動化ツールなしでの運用は推奨しません。 &lt;a href=&quot;#fr-spf-workaround-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">SPFにはDNSルックアップ上限10回の制約があり、外部メール配信サービスのincludeが入れ子で膨らむと意図せず超過するリスクがあります。上限超過の仕組みと確認方法、対策を解説します。</summary>
        </entry><entry xml:lang="en">
        <title>CLS改善のためにZolaの画像ショートコードを自作した</title>
        <published>2026-03-01T06:35:31+09:00</published>
        <updated>2026-03-01T06:35:31+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/zola-robust-image-shortcode/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/zola-robust-image-shortcode/</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;CLSとは&quot;&gt;CLSとは&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflare Pagesにブログを移行したことで、Cloudflare Web Analyticsが利用できるようになりました。アクセス数だけでなくCore Web Vitalsの各指標も確認できるのですが、そのなかでCLS（Cumulative Layout Shift）のスコアが気になる結果でした。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;zola-robust-image-shortcode&amp;#x2F;cls.webp?h=a3143d5feda5b00f4198&quot;
  alt=&quot;CLS&quot; width=&quot;733&quot; height=&quot;621&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;Cloudflare Web Analytics画面&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Core Web VitalsはGoogleが提唱するWebページのユーザー体験を測定する指標群で、LCP（Largest Contentful Paint：読み込み速度）、INP（Interaction to Next Paint：応答性）、CLS（Cumulative Layout Shift：視覚的安定性）の3つで構成されます。いずれもGoogleの検索ランキングに影響するため、サイト運営者にとって無視できない指標です。&lt;&#x2F;p&gt;
&lt;p&gt;CLSはページの読み込み中にコンテンツが予期せずずれる現象を数値化したもので、0.1以下が「良好」とされています。CLSが悪化する代表的な原因は、画像や広告などの要素にサイズ（&lt;code&gt;width&lt;&#x2F;code&gt;と&lt;code&gt;height&lt;&#x2F;code&gt;）が指定されていないことです。サイズが未指定の画像は、読み込まれるまでブラウザが表示領域を確保できません。画像の読み込みが完了した瞬間にページ全体がガクッとずれてしまい、ユーザーが読んでいた箇所を見失うことになります。&lt;&#x2F;p&gt;
&lt;p&gt;私のブログを調べてみると、ほぼすべての記事画像に&lt;code&gt;width&lt;&#x2F;code&gt;と&lt;code&gt;height&lt;&#x2F;code&gt;が設定されていませんでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;画像要素の改善&quot;&gt;画像要素の改善&lt;&#x2F;h2&gt;
&lt;p&gt;このブログは静的サイトジェネレーターのZolaを使用しており、記事はMarkdownで書いています。Markdownの画像記法は以下のとおりですが、&lt;code&gt;width&lt;&#x2F;code&gt;や&lt;code&gt;height&lt;&#x2F;code&gt;などのメタ情報を記述する手段がありません&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;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-link&quot;&gt;![&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;カバー画像&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;cover.jpg&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;そこでZolaのショートコードを利用して、画像サイズなどのメタ情報を自動でセットする仕組みを作りました。以下はコードの抜粋です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;shortcodes&#x2F;image.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        This supports the co-location pattern where content and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        assets live in the same directory. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set colocated_path = page.colocated_path | default(value=&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-text&quot;&gt;    {%- set resolved_path = colocated_path ~ src -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set meta = get_image_metadata(path=resolved_path, allow_missing=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-text&quot;&gt;    {%- if meta -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Zolaの&lt;code&gt;get_image_metadata&lt;&#x2F;code&gt;関数はビルド時に画像ファイルを読み取り、幅と高さを返してくれます。これを利用して&lt;code&gt;width&lt;&#x2F;code&gt;と&lt;code&gt;height&lt;&#x2F;code&gt;を&lt;code&gt;img&lt;&#x2F;code&gt;要素に指定しています。あわせて&lt;code&gt;get_url&lt;&#x2F;code&gt;関数の&lt;code&gt;cachebust=true&lt;&#x2F;code&gt;オプションでファイルのハッシュ値をURLに付与し、キャッシュバスティングにも対応しました。&lt;&#x2F;p&gt;
&lt;p&gt;あとはHTMLの&lt;code&gt;img&lt;&#x2F;code&gt;要素として画像サイズが出力されるように組み立てるだけです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;shortcodes&#x2F;image.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {%- if meta and meta.width %} width=&amp;quot;{{ meta.width }}&amp;quot;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {%- if meta and meta.height %} height=&amp;quot;{{ meta.height }}&amp;quot;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {%- if lazy_loading %} loading=&amp;quot;lazy&amp;quot;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif %}&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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{{ caption_text }}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;この結果、記事には以下のように書くだけで、画像サイズとキャッシュバスティングに対応した&lt;code&gt;img&lt;&#x2F;code&gt;要素を自動出力できるようになりました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&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-text&quot;&gt;{{ image(src=&amp;quot;cover.jpg&amp;quot;, alt=&amp;quot;カバー画像&amp;quot;) }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Zola依存にはなりますが、記述を複雑にせずCLS対策ができました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;figure対応&quot;&gt;figure対応&lt;&#x2F;h2&gt;
&lt;p&gt;記事内の画像にキャプションを付けたい場合もあります。そこで&lt;code&gt;caption&lt;&#x2F;code&gt;パラメータが指定された場合には、&lt;code&gt;img&lt;&#x2F;code&gt;要素を&lt;code&gt;figure&lt;&#x2F;code&gt;要素で囲み、&lt;code&gt;figcaption&lt;&#x2F;code&gt;要素でキャプションを出力するようにしました。&lt;code&gt;caption&lt;&#x2F;code&gt;を省略した場合は従来どおり&lt;code&gt;img&lt;&#x2F;code&gt;要素のみを出力します。&lt;&#x2F;p&gt;
&lt;p&gt;以下がショートコードの全容です。&lt;&#x2F;p&gt;
&lt;details&gt;
  &lt;summary&gt;imageショートコード&lt;&#x2F;summary&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;shortcodes&#x2F;image.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&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-text&quot;&gt;    image.html - Image shortcode for Zola&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-text&quot;&gt;    Copyright (c) 2026 Toshiyuki Yoshida&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    Released 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-text&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-text&quot;&gt;     Repository: https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&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-text&quot;&gt;    Renders an &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; tag with automatic path resolution,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    image metadata (width&#x2F;height), cache busting, and lazy loading.&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-text&quot;&gt;    Parameters:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      src          - Image path or remote URL (required)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      alt          - Alt text for accessibility (recommended)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      caption      - Caption text displayed below the image (optional)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                     When specified, wraps output in &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      lazy_loading - Enable lazy loading (default: true)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      link_to_self - Wrap the image in a link to the image file itself,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                     opening in a new tab (default: false)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- Strip leading &amp;quot;.&#x2F;&amp;quot; from src to normalize colocated paths&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    e.g. &amp;quot;.&#x2F;photo.jpg&amp;quot; -&amp;gt; &amp;quot;photo.jpg&amp;quot; -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set src = src | trim_start_matches(pat=&amp;quot;.&#x2F;&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-text&quot;&gt;{#- ---- URL resolution ---- -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if src is starting_with(&amp;quot;http&amp;quot;) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {#- Remote image: use src as-is. Metadata cannot be retrieved&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        for external URLs, so width&#x2F;height will not be set. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set image_url = src -%}&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-text&quot;&gt;{%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {#- Local image: first try resolving relative to the page&amp;#39;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        colocated directory (e.g. content&#x2F;blog&#x2F;my-post&#x2F;photo.jpg).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        This supports the co-location pattern where content and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        assets live in the same directory. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set colocated_path = page.colocated_path | default(value=&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-text&quot;&gt;    {%- set resolved_path = colocated_path ~ src -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set meta = get_image_metadata(path=resolved_path, allow_missing=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-text&quot;&gt;    {%- if meta -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {#- Colocated path resolved successfully -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- set image_url = get_url(path=resolved_path, cachebust=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-text&quot;&gt;    {%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {#- Fallback: treat src as an absolute path from the project root.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            This handles images placed under the static&#x2F; directory,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            e.g. src=&amp;quot;&#x2F;images&#x2F;shared.jpg&amp;quot; -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- set meta = get_image_metadata(path=src, allow_missing=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-text&quot;&gt;        {%- if meta -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            {%- set image_url = get_url(path=src, cachebust=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            {#- Neither path worked. Output the URL anyway so the page&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                does not break, but width&#x2F;height will be omitted.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                This may indicate a missing or misspelled image path. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            {%- set image_url = get_url(path=src, cachebust=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- endif -%}&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-text&quot;&gt;    {%- endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- endif -%}&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-text&quot;&gt;{#- ---- Attribute defaults ---- -#}&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-text&quot;&gt;{#- Default alt to empty string so the attribute is always present.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    An explicit alt=&amp;quot;&amp;quot; is valid for decorative images and is preferred&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    over omitting the attribute entirely for accessibility. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set alt_text = alt | default(value=&amp;quot;&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-text&quot;&gt;{#- Lazy loading is enabled by default for better page performance -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set lazy_loading = lazy_loading | default(value=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-text&quot;&gt;{#- Caption: when specified, wrap in &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-text&quot;&gt;{%- set caption_text = caption | default(value=&amp;quot;&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-text&quot;&gt;{#- When enabled, wrap the image in a link to the image file itself,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    opening in a new tab so the full-size image can be viewed alone. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set link_to_self = link_to_self | default(value=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-text&quot;&gt;{#- ---- Output ---- -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if caption_text -%}&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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; href&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; target&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 z-definition z-string z-string&quot;&gt;&amp;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; rel&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 z-definition z-string z-string&quot;&gt;&amp;quot;noopener&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif -%}&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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  src&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  alt&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ alt_text }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.width %} width&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.width }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.height %} height&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.height }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if lazy_loading %} loading&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 z-definition z-string z-string&quot;&gt;&amp;quot;lazy&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&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-tag&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif %}&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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{{ caption_text }}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; href&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; target&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 z-definition z-string z-string&quot;&gt;&amp;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; rel&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 z-definition z-string z-string&quot;&gt;&amp;quot;noopener&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif -%}&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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  src&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  alt&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ alt_text }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.width %} width&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.width }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.height %} height&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 z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.height }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if lazy_loading %} loading&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 z-definition z-string z-string&quot;&gt;&amp;quot;lazy&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&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-tag&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;  &lt;!-- textlint-enable --&gt;
&lt;&#x2F;details&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;web.dev. 「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.dev&#x2F;articles&#x2F;cls&quot;&gt;Cumulative Layout Shift (CLS)&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;web.dev. 「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.dev&#x2F;articles&#x2F;vitals&quot;&gt;Core Web Vitals&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;Zola. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;documentation&#x2F;content&#x2F;shortcodes&#x2F;&quot;&gt;Shortcodes&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;li&gt;Zola. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;documentation&#x2F;templates&#x2F;overview&#x2F;#get-image-metadata&quot;&gt;Overview - get_image_metadata&lt;&#x2F;a&gt;&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;ZolaはCommonMarkをベースとしたpulldown-cmarkというRustのライブラリ
を使用しているため画像にメタ情報を付与できませんが、Markdownの処理系によっては記述可能なものも存在します。 &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">Zolaで構築したブログのCLS（Cumulative Layout Shift）を改善するため、画像サイズを自動取得するショートコードを作成しました。実装の詳細と、caption対応によるfigure要素の出力まで解説します。</summary>
        </entry><entry xml:lang="en">
        <title>エージェント型AI組織導入の7つの前提条件 — ツールの前に土壌を整えよ</title>
        <published>2026-02-27T00:00:00+00:00</published>
        <updated>2026-02-27T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/ai-agent-org-adoption-prerequisites/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/ai-agent-org-adoption-prerequisites/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&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;ai-agent-org-adoption-prerequisites&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;ai-agent-org-adoption-prerequisites&amp;#x2F;cover.webp?h=08c6138791203946f525&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;この記事の前提&quot;&gt;この記事の前提&lt;&#x2F;h2&gt;
&lt;p&gt;「生成AI入れたいんだけど、今は何がいいの？」との問いに「エージェント型じゃないですかね」と。&lt;&#x2F;p&gt;
&lt;p&gt;そんな会話をした組織は皆さんが想像する100倍くらいITガバナンスの成熟度が低い。業務プロセスは属人的、ドキュメントは紙と口頭、セキュリティポリシーの管理者すら曖昧。そう簡単には進むはずはないと思いつつ、一応準備した資料をベースとしています。&lt;&#x2F;p&gt;
&lt;p&gt;つまり本記事は、ITガバナンスが成熟した組織に向けたものではありません。「うちの組織、正直そのへん全然できてないな」と心当たりがある方にこそ読んでいただきたい内容です。エージェント型AIは強力ですが、土壌が整っていない組織に入れても空回りするだけです。&lt;&#x2F;p&gt;
&lt;p&gt;Gartnerは2025年6月、「エージェント型AIプロジェクトの40%以上が2027年末までに中止される」と予測しています。その主因はコスト超過、不明確なビジネス価値、不十分なリスク管理であり、いずれも「技術」ではなく「組織の準備不足」に起因します。40%という数字を見て「うちは大丈夫」と思った方、たぶん大丈夫じゃないです。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、エージェント型AIの組織導入前に整えておくべき7つの前提条件を整理します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;チャット型とエージェント型は何が違うのか&quot;&gt;チャット型とエージェント型は何が違うのか&lt;&#x2F;h2&gt;
&lt;p&gt;エージェント型AIは、従来のチャット型生成AIとは本質的に異なります。チャット型は「質問して回答を得る」受動的なツールですが、エージェント型は「指示を受けて自律的にタスクを遂行する」能動的なシステムです。ファイルの読み書き、外部APIの呼び出し、ツールの実行といった操作をAIが自ら行います。&lt;&#x2F;p&gt;
&lt;p&gt;この違いはリスクの性質を根本的に変えます。チャット型では「不正確な回答」が主なリスクでしたが、エージェント型では「意図しない操作の実行」がリスクに加わります。だからこそ、組織としての準備が求められるのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;グローバルの導入状況&quot;&gt;グローバルの導入状況&lt;&#x2F;h2&gt;
&lt;p&gt;Deloitteの2025年調査によれば、エージェント型AIを本番環境で稼働させている組織はわずか11%にとどまっています。McKinseyが調査した2,000社のうち62%が「実験中」と回答していますが、その3分の2は意味のある展開には至っていません。McKinseyの調査では正式なAIガバナンスを導入済みの組織は17%にすぎず、導入済みの組織ほどエージェント型AIの展開に成功していると報告されています。&lt;&#x2F;p&gt;
&lt;p&gt;国内では、経済産業省・総務省の「AI事業者ガイドライン（第1.1版）」（2025年3月28日）において、AIエージェントについて「事故等の安全性面のリスクや過度な依存、労働者の失業等のリスクの複雑化・深刻化の可能性」が指摘されています。現時点ではエージェント型AI単体のガイドラインは未策定であり、第1.2版での対応が検討されている段階です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件1:_業務プロセスの言語化・構造化&quot;&gt;前提条件1: 業務プロセスの言語化・構造化&lt;&#x2F;h2&gt;
&lt;p&gt;エージェント型AIは「やりたいこと」をテキストで指示して動かすものです。コンセプトと方針を業務要件に落とし、業務要件を業務設計に落とすには、現行の業務プロセスが明文化されている必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;「あの人に聞けばわかる」状態の属人的な業務は、AIに指示を出すこともできません。業務の可視化・構造化は、エージェント型AI活用の大前提です。&lt;&#x2F;p&gt;
&lt;p&gt;McKinseyは「エージェント型組織」を提唱する中で、ガバナンスは定期的な紙ベースの運用ではなく、リアルタイムかつデータ駆動で埋め込まれたものでなければならないと述べています。これは業務プロセスの構造化がその大前提であることを意味します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件2:_テキストベースの業務遂行力&quot;&gt;前提条件2: テキストベースの業務遂行力&lt;&#x2F;h2&gt;
&lt;p&gt;エージェント型AIとの協業は本質的にテキストで行われます。口頭伝達と紙の回覧が主な伝達手段の組織では、エージェント型AIの導入以前の問題です。&lt;&#x2F;p&gt;
&lt;p&gt;SlackやTeamsでの指示・依頼を
自然にこなせること、
ドキュメントをテキストで書く習慣が
あることは最低限の土壌です。
特にMarkdownのような
構造化されたテキストを書く力は、
エージェント型AIと協業するうえで
最低限必要なスキルです。&lt;&#x2F;p&gt;
&lt;p&gt;プレーンテキストで構造化された文書を書く力は、
エージェント型AI時代の
基礎リテラシーと言えます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件3:_「正解をもらう」から「判断を自分でする」への意識転換&quot;&gt;前提条件3: 「正解をもらう」から「判断を自分でする」への意識転換&lt;&#x2F;h2&gt;
&lt;p&gt;チャット型AIを
「答えを教えてくれる便利なツール」として
使ってきた人が、エージェント型AIで
「指示を出して結果を評価する」立場に
移行するのは、ツールの違い以上に
思考様式の転換を伴います。&lt;&#x2F;p&gt;
&lt;p&gt;特に見落とされがちなのは
「AIの出力を評価・判断する力」です。
エージェント型AIの実行結果が
業務的に正しいか、
ビジネス上使えるかを判断できるのは
人間だけです。
この判断力なくして
エージェント型AIを導入することは、
ハンドルのない車を運転するに等しい行為です。&lt;&#x2F;p&gt;
&lt;p&gt;Gartnerは2026年の戦略予測で、
生成AIの利用による批判的思考力の低下に
警鐘を鳴らし、グローバル組織の50%が
「AIを使わない」スキル評価を
導入すると予測しています。
AIに依存しすぎず、
自ら判断する力を組織的に維持することが
不可欠です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件4:_情報セキュリティポリシーの再設計&quot;&gt;前提条件4: 情報セキュリティポリシーの再設計&lt;&#x2F;h2&gt;
&lt;p&gt;エージェント型AIはファイルの読み書き、
外部APIの呼び出し、ツールの実行をこなします。
従来のチャット型AIとは
リスクの性質が根本的に異なり、
「生成AIに社内情報を入力してよいか」
というレベルのポリシーでは対応できません。&lt;&#x2F;p&gt;
&lt;p&gt;必要なのは以下のような設計です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AIにどの範囲のファイルアクセスを
許可するか&lt;&#x2F;li&gt;
&lt;li&gt;AIが実行できるアクションの範囲を
どう制御するか&lt;&#x2F;li&gt;
&lt;li&gt;AIの操作ログをどう記録・監査するか&lt;&#x2F;li&gt;
&lt;li&gt;人間による承認が必要な操作の基準を
どう定めるか&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;セキュリティポリシーのオーナーシップを
明確にし、エージェント型AIのリスクへ
対応できるかたちに再設計する必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;McKinseyは、DevSecOpsが
デジタルデリバリーに
自動チェックを埋め込んだように、
エージェント型組織ではワークフローに
制御エージェントを埋め込むことを
提唱しています。
出力を検証するエージェント、
ポリシーを強制するエージェント、
コンプライアンスを監視するエージェントを
配置し、すべてのアクションを
リアルタイムでログ・説明可能にする
という構想です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件5:_試行錯誤を許容する組織文化&quot;&gt;前提条件5: 試行錯誤を許容する組織文化&lt;&#x2F;h2&gt;
&lt;p&gt;エージェント型AIの活用スキルは
試行錯誤でしか身につきません。
スキル獲得のパスは確立されておらず、
実践だけがパスです。
新しいやり方を試すこと自体が
歓迎されない組織文化では、
導入してもツールが放置されるだけです。&lt;&#x2F;p&gt;
&lt;p&gt;イノベーション普及理論が示すように、
新技術を積極的に採用するのは
組織の約2割です。
これは個人の意志だけでなく
組織の許容度にも起因します。
失敗にコストがかかる環境、
前例のないことを試すことに
心理的安全性がない環境では、
その2割さえも得られません。&lt;&#x2F;p&gt;
&lt;p&gt;Deloitteの調査では、
完全自律型AIエージェントへの信頼度は
27%にとどまり、
1年前の43%から低下しています。
成功している組織は、初期段階では
「human-in-the-loop」モデル
（人間がループに入る形）で
自律性を制限し、段階的に権限を拡大する
アプローチを採用しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件6:_段階的な導入設計&quot;&gt;前提条件6: 段階的な導入設計&lt;&#x2F;h2&gt;
&lt;p&gt;「AIは支援→AIと協業→AIを使役」
という段階があるように、
組織導入もその段階に沿うべきです。
いきなり全社でエージェント型を
展開するのではなく、
まずチャット型で「AIに問いかける」ことに
慣れた層から、
エージェント型での
「AIに仕事を任せる」段階へ移行させる設計が
現実的です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;段階&lt;&#x2F;th&gt;&lt;th&gt;AIの役割&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;第1段階: AIは支援&lt;&#x2F;td&gt;&lt;td&gt;質問への回答、情報収集、文章の下書き&lt;&#x2F;td&gt;&lt;td&gt;方針決定、最終判断、成果物の品質確認&lt;&#x2F;td&gt;&lt;td&gt;ChatGPT Business &#x2F; Claude Team等の直接契約&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;第2段階: AIと協業&lt;&#x2F;td&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;第3段階: AIを使役&lt;&#x2F;td&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;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Gartnerは、初期段階では
明確なROIが見込める領域に限定して
エージェント型AIを適用すべきと
推奨しています。
個別タスクの強化ではなく、
企業全体の生産性向上に焦点を当てることが
重要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件7:_トップ3モデルプロバイダーとの直接契約&quot;&gt;前提条件7: トップ3モデルプロバイダーとの直接契約&lt;&#x2F;h2&gt;
&lt;p&gt;エージェント型AIの本格導入において、
OpenAI・Anthropic・Googleといった
トップ3モデルプロバイダーとの直接契約は
重要な意思決定です。&lt;&#x2F;p&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;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;why-genai-wrapper-services-are-a-trap&amp;#x2F;&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;p&gt;上記の記事で詳述したとおり、APIラッパーに過ぎないサービスを間に挟むことには構造的な問題があります。Gartnerが警告する「エージェントウォッシング」（既存製品にエ
ージェントの看板を掛けてリブランディングする行為）の影響もあり、数千のエージェント型AIベンダーのうち真にエージェント型の能力を持つのは約130社にすぎないとされて
います。&lt;&#x2F;p&gt;
&lt;p&gt;「馴染みのベンダーに任せよう」という意思決定構造そのものが障壁になりえます。技術選定の根拠を非技術系の経営層に説明できる推進者が組織内にいることが前提です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;7つの前提条件のサマリー&quot;&gt;7つの前提条件のサマリー&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;th&gt;緊急度&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;業務プロセスの言語化・構造化&lt;&#x2F;td&gt;&lt;td&gt;AIに指示を出せず、導入が空回りする&lt;&#x2F;td&gt;&lt;td&gt;即時対応が必要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;テキストベースの業務遂行力&lt;&#x2F;td&gt;&lt;td&gt;AIとの協業が成立しない&lt;&#x2F;td&gt;&lt;td&gt;即時対応が必要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;「判断を自分でする」意識転換&lt;&#x2F;td&gt;&lt;td&gt;AIに依存し、判断力が低下する&lt;&#x2F;td&gt;&lt;td&gt;中期的に育成&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&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;5&lt;&#x2F;td&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;6&lt;&#x2F;td&gt;&lt;td&gt;段階的な導入設計&lt;&#x2F;td&gt;&lt;td&gt;Gartner予測の40%中止に該当する&lt;&#x2F;td&gt;&lt;td&gt;導入計画策定時&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;トップ3プロバイダーとの直接契約&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;h2 id=&quot;おわりに_—_変化の時間は限られている&quot;&gt;おわりに — 変化の時間は限られている&lt;&#x2F;h2&gt;
&lt;p&gt;7つの前提条件は、いずれも「エージェント型AI」固有の話ではなく、組織の基礎体力の問題です。だからこそ、今から着手することに意味があります。&lt;&#x2F;p&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;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;death-of-clerical-work&amp;#x2F;&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;p&gt;経済産業省の推計が示す2040年の事務職437万人余剰、Microsoft AI CEOの「18か月以内にほぼすべてのホワイトカラー業務がAIで自動化される」という発言。変化のスピードは推計よりもはるかに速い可能性があります。準備の時間は限られています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;参考資料&quot;&gt;参考資料&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;Gartner &quot;Gartner Predicts Over 40% of Agentic AI Projects Will Be Canceled by End of 2027&quot; (2025年6月)&lt;&#x2F;li&gt;
&lt;li&gt;McKinsey &quot;The agentic organization: Contours of the next paradigm for the AI era&quot; (2025年)&lt;&#x2F;li&gt;
&lt;li&gt;McKinsey &quot;CEO strategies for leading in the age of agentic AI&quot; (2025年)&lt;&#x2F;li&gt;
&lt;li&gt;Deloitte &quot;Agentic AI enterprise adoption: Navigating key factors&quot; (2025年)&lt;&#x2F;li&gt;
&lt;li&gt;Deloitte &quot;AI trends 2025: Adoption barriers and updated predictions&quot; (2025年)&lt;&#x2F;li&gt;
&lt;li&gt;MIT Sloan Management Review &quot;The Emerging Agentic Enterprise&quot; (2025年)&lt;&#x2F;li&gt;
&lt;li&gt;World Economic Forum &quot;Agentic AI: Overcoming 3 obstacles to adoption and innovation&quot; (2025年12月)&lt;&#x2F;li&gt;
&lt;li&gt;Gartner &quot;Strategic Predictions for 2026&quot; (2025年)&lt;&#x2F;li&gt;
&lt;li&gt;経済産業省・総務省「AI事業者ガイドライン（第1.1版）」(2025年3月)&lt;&#x2F;li&gt;
&lt;li&gt;IPA「テキスト生成AIの導入・運用ガイドライン」(2024年7月)&lt;&#x2F;li&gt;
&lt;li&gt;経済産業省「2040年の就業構造推計（改訂版）について」(2026年1月)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        <summary type="html">エージェント型AIを組織に導入する前に整えるべき7つの前提条件を整理します。業務プロセスの言語化からセキュリティポリシーの再設計まで、ITガバナンスが未成熟な組織こそ取り組むべき土壌づくりを解説します。</summary>
        </entry><entry xml:lang="en">
        <title>ZolaブログにPagefindで日本語検索を導入した</title>
        <published>2026-02-26T07:58:30+09:00</published>
        <updated>2026-02-26T07:58:30+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/zola-pagefind-search/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/zola-pagefind-search/</id>
        
            <content type="html">&lt;h2 id=&quot;はじめに（Zolaの検索事情）&quot;&gt;はじめに（Zolaの検索事情）&lt;&#x2F;h2&gt;
&lt;p&gt;このブログも記事数が255を超え、
検索機能なしでは目的の記事に
たどり着きにくくなってきました。
タグやアーカイブで絞り込めはしますが、
「あのキーワードで書いた記事どこだっけ」
という場面には対応できません。&lt;&#x2F;p&gt;
&lt;p&gt;このブログで使用している静的サイトジェネレーター
Zolaには検索機能が組み込まれています。
検索エンジンには
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;elasticlunr.com&#x2F;&quot;&gt;elasticlunr.js&lt;&#x2F;a&gt;
が使われていますが、
日本語のトークナイズに対応していません。
elasticlunr自体が長期間更新されておらず、
今後の対応も期待できない状況です。&lt;&#x2F;p&gt;
&lt;p&gt;適用しているテーマ
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;welpo&#x2F;tabi&quot;&gt;tabi&lt;&#x2F;a&gt;
の検索UIもelasticlunrを前提としており、
日本語ブログでは実質的に使えません。
&lt;code&gt;config.toml&lt;&#x2F;code&gt;では&lt;code&gt;build_search_index = false&lt;&#x2F;code&gt;
として無効化していました。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、日本語対応の検索機能を導入することにしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;検索エンジンの選定&quot;&gt;検索エンジンの選定&lt;&#x2F;h2&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;Algolia&lt;&#x2F;td&gt;&lt;td&gt;SaaS依存。無料枠に月10,000リクエスト制限。検索クエリが外部に送信される&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Meilisearch&lt;&#x2F;td&gt;&lt;td&gt;サーバーの常時稼働が必要で、静的サイトとは根本的に合わない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Fuse.js&lt;&#x2F;td&gt;&lt;td&gt;全インデックスをクライアントにダウンロードする設計。記事数の増加に弱い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Google PSE&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;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pagefind.app&#x2F;&quot;&gt;Pagefind&lt;&#x2F;a&gt;
です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Pagefind_とは&quot;&gt;Pagefind とは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pagefind.app&#x2F;&quot;&gt;Pagefind&lt;&#x2F;a&gt;は
CloudCannonが開発した静的サイト向けの
全文検索ライブラリです。&lt;&#x2F;p&gt;
&lt;p&gt;サイトのビルド後にHTMLを解析して
検索インデックスを静的ファイルとして生成し、
検索時にはWebAssemblyで動作する
クライアントサイドの検索エンジンが
必要なチャンクだけを読み込んで結果を返します。
外部サーバーへの通信は一切発生しません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;セグメンテーションとは、
文章を単語に分割する処理。
英語のように単語がスペースで
区切られていない日本語・中国語・韓国語は
単語を区切る処理が必要。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Extended版ではCJK（中国語・日本語・韓国語）の
セグメンテーションに対応しており、
&lt;code&gt;npx pagefind&lt;&#x2F;code&gt;を実行するだけで
Extended版が自動的にダウンロードされます。
検索UIコンポーネントも同梱されているため、
数行のHTMLを追加するだけで
検索ページを構築できます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;Note&lt;&#x2F;strong&gt;
        &lt;p&gt;PagefindのセグメンテーションはMeCabのような
品詞分解を行う形態素解析ではなく、
Unicode標準に基づく単語境界の検出です。
そのため「走る」で「走った」がヒットするような
活用形の展開（ステミング）には対応していません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;このブログでPagefindを採用した
決め手は次の点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;日本語対応&lt;&#x2F;strong&gt;:
Extended版がCJKセグメンテーションに対応している&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;プライバシー&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;h2 id=&quot;実装のアプローチ&quot;&gt;実装のアプローチ&lt;&#x2F;h2&gt;
&lt;p&gt;tabiテーマにはできるだけ手を入れない
方針を採りました。
テーマを直接編集すると、
アップデートのたびに変更が衝突して
追従が面倒になるためです。
Zolaでは&lt;code&gt;templates&#x2F;&lt;&#x2F;code&gt;に同名のファイルを
置くことでテーマのテンプレートを
上書きでき、CSSも&lt;code&gt;static&#x2F;custom.css&lt;&#x2F;code&gt;で
追記できます。&lt;&#x2F;p&gt;
&lt;p&gt;tabiの検索UIは&lt;code&gt;build_search_index = true&lt;&#x2F;code&gt;
のときにだけ表示される仕組みです。
Pagefindは独自のUIコンポーネントを持っているため、
tabiの検索モーダルは使わず、
Pagefind UIを載せた専用の検索ページを
新設する方式にしました。
ナビゲーションメニューに「search」を
追加し、読者はそこから検索を利用します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Pagefindの実装&quot;&gt;Pagefindの実装&lt;&#x2F;h2&gt;
&lt;!-- author-approved: Pagefindの実装セクション配下の分類に必要 --&gt;
&lt;h3 id=&quot;実装概要&quot;&gt;実装概要&lt;&#x2F;h3&gt;
&lt;p&gt;まずPagefindをインストールします。&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;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -D pagefind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次にプロジェクトルートにPagefindの設定ファイル
&lt;code&gt;pagefind.yml&lt;&#x2F;code&gt;を作成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;pagefind.yml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;site&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-string&quot;&gt; public&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-tag z-yaml&quot;&gt;glob&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 z-definition z-string z-string&quot;&gt; &amp;quot;blog&#x2F;**&#x2F;*.html&amp;quot;&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-tag z-yaml&quot;&gt;force_language&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-string&quot;&gt; ja&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;glob&lt;&#x2F;code&gt;でインデックス対象を&lt;code&gt;blog&#x2F;&lt;&#x2F;code&gt;配下の
記事に限定し、トップページやaboutなどの
固定ページは除外しています。
&lt;code&gt;force_language: ja&lt;&#x2F;code&gt;は
日本語のCJKセグメンテーションを強制する設定です。&lt;&#x2F;p&gt;
&lt;p&gt;検索ページはZolaのセクションとして作成します。
&lt;code&gt;content&#x2F;search&#x2F;_index.md&lt;&#x2F;code&gt;でテンプレートを指定し、
&lt;code&gt;templates&#x2F;search.html&lt;&#x2F;code&gt;にPagefind UIを配置します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;search.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% extends &amp;quot;base.html&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-text&quot;&gt;{% block main_content %}&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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; class&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 z-definition z-string z-string&quot;&gt;&amp;quot;wide-container&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;link&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      href&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 z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;pagefind&#x2F;pagefind-ui.css&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      rel&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 z-definition z-string z-string&quot;&gt;&amp;quot;stylesheet&amp;quot;&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-tag&quot;&gt;    &#x2F;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; id&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 z-definition z-string z-string&quot;&gt;&amp;quot;search&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      src&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 z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;pagefind&#x2F;pagefind-ui.js&amp;quot;&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-tag&quot;&gt;    &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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;      window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;addEventListener&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 z-definition z-string z-string&quot;&gt;        &amp;#39;DOMContentLoaded&amp;#39;&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; =&amp;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-keyword z-operator z-new&quot;&gt;        new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; PagefindUI&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;          element&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 z-definition z-string z-string&quot;&gt; &amp;quot;#search&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-source&quot;&gt;          showSubResults&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-constant z-language z-boolean&quot;&gt; true&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;          showImages&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-constant z-language z-boolean&quot;&gt; false&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;          translations&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            placeholder&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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;quot;検索キーワードを入力…&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-source&quot;&gt;            zero_results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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;quot;[SEARCH_TERM] の検索結果は&amp;quot;&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ありません&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-source&quot;&gt;            one_result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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;quot;[SEARCH_TERM] の検索結果: 1件&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-source&quot;&gt;            many_results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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;quot;[COUNT] 件の検索結果&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-source&quot;&gt;            clear_search&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 z-definition z-string z-string&quot;&gt; &amp;quot;クリア&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-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-source&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&quot;&gt;      }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% endblock main_content %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;tabiの&lt;code&gt;base.html&lt;&#x2F;code&gt;を継承することで、
ヘッダーやフッター、
スキンの設定がそのまま反映されます。
&lt;code&gt;translations&lt;&#x2F;code&gt;で検索UIの
日本語メッセージを指定しています。&lt;&#x2F;p&gt;
&lt;!-- author-approved: Pagefindの実装セクション配下の分類に必要 --&gt;
&lt;h3 id=&quot;minify_htmlの罠&quot;&gt;minify_htmlの罠&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;zola build&lt;&#x2F;code&gt;後にPagefindを実行したところ、
304個のHTMLファイルを検出しながら
インデックスされたページは0件、
「Discovered 0 languages」という
結果になりました。&lt;&#x2F;p&gt;
&lt;p&gt;原因の切り分けは次のように進めました。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;最小限のHTMLファイルを作成して
Pagefindを実行 → 正常動作&lt;&#x2F;li&gt;
&lt;li&gt;Zolaが実際に生成したHTMLをコピーして
Pagefindを実行 → 再現&lt;&#x2F;li&gt;
&lt;li&gt;HTMLの要素を削りながら比較
→ &lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;の有無で結果が変わることを特定&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Zolaの&lt;code&gt;config.toml&lt;&#x2F;code&gt;で&lt;code&gt;minify_html = true&lt;&#x2F;code&gt;を
設定すると、HTML5の仕様上省略可能な
&lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;閉じタグが除去されます。
これ自体はHTML5として合法ですが、
Pagefind v1.4.0のHTMLパーサーは
&lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;がないとページを正しく解析できず、
言語検出に失敗していました。&lt;&#x2F;p&gt;
&lt;p&gt;このブログの規模ではHTML minifyの
恩恵は無視できるため、
&lt;code&gt;config.toml&lt;&#x2F;code&gt;で&lt;code&gt;minify_html = false&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;config.toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;minify_html&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-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これはZolaの不具合ではなく
Pagefindのパーサー側の制約です。
将来Pagefindが&lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;省略に
対応すれば&lt;code&gt;minify_html&lt;&#x2F;code&gt;を
再度有効化できます。&lt;&#x2F;p&gt;
&lt;!-- author-approved: Pagefindの実装セクション配下の分類に必要 --&gt;
&lt;h3 id=&quot;テーマとの共存で踏んだCSS問題&quot;&gt;テーマとの共存で踏んだCSS問題&lt;&#x2F;h3&gt;
&lt;p&gt;Pagefind UIにはCSS Custom Propertiesで
スタイルをカスタマイズする仕組みがあります。
テーマカラーに合わせるため
&lt;code&gt;:root&lt;&#x2F;code&gt;で変数を宣言したところ、
期待どおりに適用されませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;原因はCSSのカスケード順序にあります。
&lt;code&gt;pagefind-ui.css&lt;&#x2F;code&gt;は検索ページの&lt;code&gt;&amp;lt;main&amp;gt;&lt;&#x2F;code&gt;内で
読み込まれるため、tabiが&lt;code&gt;&amp;lt;head&amp;gt;&lt;&#x2F;code&gt;内で
読み込む&lt;code&gt;custom.css&lt;&#x2F;code&gt;よりも後にカスケードされます。
結果として、Pagefindのデフォルト値が
こちらの&lt;code&gt;:root&lt;&#x2F;code&gt;宣言に勝っていました。&lt;&#x2F;p&gt;
&lt;p&gt;セレクタを&lt;code&gt;.pagefind-ui&lt;&#x2F;code&gt;に変更し、
クラスセレクタの詳細度で
確実にオーバーライドするようにしました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;css&quot; data-name=&quot;static&#x2F;custom.css&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-entity z-other z-attribute-name z-class z-css&quot;&gt;pagefind-ui&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&quot;&gt;  --pagefind-ui-primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--primary-color&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&quot;&gt;  --pagefind-ui-text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--text-color&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&quot;&gt;  --pagefind-ui-background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--background-color&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&quot;&gt;  --pagefind-ui-border&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--divider-color&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&quot;&gt;  --pagefind-ui-tag&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-support z-function z-misc&quot;&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--bg-0&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&quot;&gt;  --pagefind-ui-font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--sans-serif-font&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;tabiの既存のCSS変数を参照することで、
ダークモードやevangelionスキンの
カラースキームに自動で追従します。&lt;&#x2F;p&gt;
&lt;p&gt;もうひとつ、tabiテーマは全リンクに対して
&lt;code&gt;a:hover { background-color: var(--primary-color) }&lt;&#x2F;code&gt;
を適用するグローバルスタイルを持っています。
Pagefindの検索結果は&lt;code&gt;&amp;lt;a&amp;gt;&lt;&#x2F;code&gt;タグで構成されるため、
ホバーするとevangelionスキンの赤
（&lt;code&gt;#d12e36&lt;&#x2F;code&gt;）が結果全体の背景に
適用されてしまいました。&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;css&quot; data-name=&quot;static&#x2F;custom.css&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-entity z-other z-attribute-name z-class z-css&quot;&gt;pagefind-ui&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-pseudo-class&quot;&gt;hover&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-entity z-other z-attribute-name z-class z-css&quot;&gt;pagefind-ui&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-pseudo-class&quot;&gt;focus&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-type z-property-name z-css&quot;&gt;  background-color&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; transparent&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-type z-property-name z-css&quot;&gt;  color&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-support z-function z-misc&quot;&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--primary-color&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;h2 id=&quot;CI&#x2F;CDへの組み込み&quot;&gt;CI&#x2F;CDへの組み込み&lt;&#x2F;h2&gt;
&lt;p&gt;このブログはGitHub Actionsで
Cloudflare Workersにデプロイしています。
ワークフローに検索インデックス生成の
ステップを追加しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;.github&#x2F;workflows&#x2F;deploy.yml&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-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Build&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-tag z-yaml&quot;&gt;  run&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-string&quot;&gt; zola build&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&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Build search index&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-tag z-yaml&quot;&gt;  run&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-string&quot;&gt; npx pagefind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;zola build&lt;&#x2F;code&gt; → &lt;code&gt;npx pagefind&lt;&#x2F;code&gt;の
2ステップだけで完結します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Pagefindの導入により、
303ページ（セクションページ含む）・
17,217語のインデックスが生成され、
日本語キーワードでの検索が
機能するようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;実装自体はシンプルでしたが、
&lt;code&gt;minify_html&lt;&#x2F;code&gt;によるHTML構造の変化や
テーマとのCSS競合など、
組み合わせ固有の問題に時間を取られました。
単独では正しく動くものが
組み合わせると壊れるパターンは、
静的サイトのツールチェーンでは
よくある話かもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;現時点での制約として、
日本語のステミングには未対応です。
「走る」で検索しても
「走った」はヒットしません。
ただし単語単位の検索は安定しており、
現在の規模では実用上十分です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">静的サイトジェネレーターZolaで運用しているこのブログに、
Pagefindを使った日本語対応のサイト内検索を導入しました。
選定の経緯から実装時のハマりどころまでを記録します。
</summary>
        </entry><entry xml:lang="en">
        <title>IBMが組み込んだClaude、IBMを撃つ ── メインフレーム・モダナイゼーションは誰にも解けない</title>
        <published>2026-02-24T17:30:00+09:00</published>
        <updated>2026-02-24T17:30:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/ibm-cobol-claude-irony/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/ibm-cobol-claude-irony/</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;IBM株、一夜にして13%急落&quot;&gt;IBM株、一夜にして13%急落&lt;&#x2F;h2&gt;
&lt;p&gt;2026年2月23日、IBM株が13%急落しました。
2000年10月以来、最大の下落幅です。&lt;&#x2F;p&gt;
&lt;p&gt;きっかけはAnthropicが公開したブログ記事
「How AI helps break the cost barrier
to COBOL modernization」でした。
Claude Codeを使えば、
COBOLレガシーシステムの
モダナイゼーションにおける
調査・分析作業を大幅に短縮できる
という内容です。
従来は人間のアナリストが数か月かけていた
依存関係のマッピングやワークフローの文書化を、
AIが高速に処理できると主張しています。&lt;&#x2F;p&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;claude.com&amp;#x2F;blog&amp;#x2F;how-ai-helps-break-cost-barrier-cobol-modernization&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;p&gt;日本の金融機関などはまだまだ
メインフレームが残っていますが、
米国でも似たような状況のようです。
Anthropicのブログによれば
毎日数千億行のCOBOLが
本番環境で稼働しているそうです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ibm.com&#x2F;think&#x2F;architectures&quot;&gt;IBM Architecture Collection&lt;&#x2F;a&gt;などを見ても、
IBMはメインフレーム
（彼らは「IBM Z」と呼びますが）を
捨てたわけではありません。
また、メインフレームと
メインフレーム・モダナイゼーションの
コンサルティングも
IBMの主要事業の1つです。
投資家はこの市場がAIによって
ディスラプトされることを懸念しました。&lt;&#x2F;p&gt;
&lt;p&gt;ここまでなら「AIベンチャーが大手の牙城を脅かす」
というよくある構図です。
しかし今回の話には、もう一層の皮肉があります。&lt;&#x2F;p&gt;
&lt;p&gt;IBM自身が開発中のAIエージェント
「Project Bob」（以下「IBM Bob」）は、
AnthropicのClaudeをマルチモデル構成の
中核として採用しているのです。
自社のメインフレーム・モダナイゼーション
ツールに組み込んだ相手のAIが、
自社の株価を叩き落とすという構図。
元IBM社員として、
複雑な感慨を覚えました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Watson時代を知る者として&quot;&gt;Watson時代を知る者として&lt;&#x2F;h2&gt;
&lt;p&gt;私がIBMに在籍していた当時、
Watson一色の時代がありました。
社内のあらゆるプレゼンテーションに
Watsonのロゴが入り、営業資料にはWatsonの
事例が並び、「Cognitive（コグニティブ）」
という言葉が社内の共通語のように
使われていました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;p&gt;2011年のJeopardy!でWatsonが勝利したとき、&lt;&#x2F;p&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;IBMは「AIの会社」として
華々しく旗を掲げていました。
あの頃の熱狂を思い出すと、
隔世の感があります。
しかし生成AI時代になって
主導権を握ったのは
OpenAIやAnthropicであり、
IBMのwatsonxとGraniteモデルは、
エンタープライズの現場では
外部モデルに頼る結果となりました。&lt;&#x2F;p&gt;
&lt;p&gt;IBM Bobが利用するAIモデルは
Claude、Mistral、Graniteなど
複数で構成されており、
タスクに応じて自動振り分けされます。
watsonxというプラットフォームと
Graniteという自社モデルを
持っていながら、
それだけでは最前線で戦えない。
この現実には、
やはり複雑なものを感じます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、これを単なる敗北と
読むべきではないとも思います。
IBMの強みは「AIモデルそのもの」ではなく、
エンタープライズ向けのガバナンス、
ハイブリッド環境への対応力、
そして仕様駆動開発という
メソドロジーの側にあります。
モデルは最良のものを
外から持ってきて、
インテグレーションとガバナンスの
レイヤーで勝負する。
これは割り切った戦略転換であり、
むしろ合理的な判断だと考えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;IBM_Bobの仕様駆動アプローチ&quot;&gt;IBM Bobの仕様駆動アプローチ&lt;&#x2F;h2&gt;
&lt;p&gt;IBM Bobは汎用的なAI駆動開発ツールであり、
新規開発からフレームワーク移行、
セキュリティ修正まで幅広く対応します。
IBMが特に注力するのは
「仕様駆動開発」です。
AIにコードをいきなり書かせるのではなく、
まず仕様を文書化して唯一の基準とし、
AIが仕様に基づいてコードやテストケースを
生成する方式です。
いわゆるバイブコーディングとは
対極の設計思想にあります。&lt;&#x2F;p&gt;
&lt;p&gt;IBM社内では10,000人超の開発者が
Bobを活用し、
平均45%の生産性改善を
実現したとされています。
2027年以降は顧客プロジェクト全体で
工数35%削減・期間30%短縮を目標に
掲げています。&lt;&#x2F;p&gt;
&lt;p&gt;このアプローチ自体は筋が悪くありません。
特にエンタープライズの重要システムでは、
仕様なき生成は許されないため、
仕様駆動という思想は理にかなっています。
しかしこの「45%の改善」という数字は、
仕様が明確に存在する前提での話です。
メインフレーム・モダナイゼーションの
現場で何が起きているかというと、
その前提自体が成り立ちません。&lt;&#x2F;p&gt;
&lt;p&gt;仕様書は残っていないケースが大半です。
コードを書いた人はとうに退職しています。
コード自体が唯一の仕様書であり、
しかもそのコードの意味を
正確に理解できる人間が
もういないのです。&lt;&#x2F;p&gt;
&lt;p&gt;IBM Bobが「AIでコードから
仕様を逆抽出する」ことを
目指しているのは理解できます。
しかし抽出された仕様が正しいかどうかを
検証する人間がいなければ、
それは推測の域を出ません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWSのBlu_Ageはもっと危うい&quot;&gt;AWSのBlu Ageはもっと危うい&lt;&#x2F;h2&gt;
&lt;p&gt;メインフレーム・モダナイゼーションの
競合として、
AWSのBlu Ageにも触れておきます。
AWSはフランスのBlu Age社を買収し、
COBOLやPL&#x2F;Iを自動的にJava&#x2F;Spring Bootに
変換するソリューションを展開しています。
最新では「AWS Transform for mainframe」
というエージェント型AIサービスに
統合されました。&lt;&#x2F;p&gt;
&lt;p&gt;Transamericaでバッチ性能30%向上、
Vismaで年間コスト55%削減といった
実績が報告されており、
変換の自動化度は高いと言えます。&lt;&#x2F;p&gt;
&lt;p&gt;しかしこのアプローチには
構造的な弱点があります。
変換されたJavaコードは一見モダンですが、
Blu Ageの独自ランタイムライブラリが
メインフレーム固有の機能を
エミュレーションで提供しています。
COBOLのメモリレイアウト再現、
CICSトランザクション管理、
VSAMファイルアクセス、
JCLバッチ実行。
これらがすべて独自ランタイムに
依存しているため、
変換後のコードは純粋なJavaではありません。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、メインフレームへの
ベンダーロックインが、
AWSへのベンダーロックインに
置き換わっただけです。
確かにJavaコードになったことで
ソースコードの可読性自体は向上し、
Java開発者による保守は可能になります。
しかし、ランタイム層の理解なしには
本質的な改修はできず、
「この処理は何をしているのか」が
わからないという根本的な問題は
解消されていません。&lt;&#x2F;p&gt;
&lt;p&gt;個人的な評価としては、
仕様を基準に据えるIBMの方が
まだましだと考えています。
少なくとも「何をしているのか」を
明らかにしようとする姿勢がある。
Blu Ageは「動けばいい」であり、
その先の保守性を
犠牲にしています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;誰も解けない本当の理由&quot;&gt;誰も解けない本当の理由&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Code、IBM Bob、AWS Blu Age。
いずれのツールを使っても、
メインフレーム・モダナイゼーションの
本質的な問題は解けません。
なぜなら、これは技術の問題ではなく、
人と組織の問題だからです。&lt;&#x2F;p&gt;
&lt;p&gt;COBOLの基幹システムを書いた世代は
60代後半から70代で現役を退いています。
彼らが持っていたのは
コーディングスキルだけではありません。
「この例外処理はあの税制改正で入れた」
「このフラグは特定の取引先との
契約条件で分岐する」
といった業務の文脈そのものでした。&lt;&#x2F;p&gt;
&lt;p&gt;AIがコードから仕様を
抽出できたとしましょう。
しかし、その仕様が正しいかどうかを
検証できる人間がいません。
ユーザー企業は情シス部門を縮小して
ベンダーに丸投げしてきました。
SIer側は下請け構造の中で
業務知識が分散・属人化しました。
仕様を書いた人、コードを書いた人、
運用している人がバラバラで、
全体を通して理解している人が
どこにもいない。&lt;&#x2F;p&gt;
&lt;p&gt;IBMが「経営層向けワークショップ」や
「成果コミット型パートナーシップ」を
打ち出しているのは、
この問題への間接的な回答です。
しかし結局のところ、
「御社の業務を一番わかっているのは
御社です」という当たり前の話に戻ります。
そしてその「御社」の中に、
もうわかる人がいないのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;株価が映すもの&quot;&gt;株価が映すもの&lt;&#x2F;h2&gt;
&lt;p&gt;IBMの株価が一日で13%下がったことは、
市場がメインフレーム・モダナイゼーションの
ディスラプトを織り込んだように見えます。
しかし実態はもう少し複雑です。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeが得意なのは
コードの探索と分析です。
数千行のCOBOLコードから
依存関係をマッピングし、
ワークフローを文書化し、
リスクを特定する。
これは確かに人間が数か月かけていた
作業を短縮できるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;しかし「分析できる」ことと
「移行できる」ことの間には、
深い溝があります。
コードの構造を理解することと、
そのコードが担っている
業務の意味を理解することは別物です。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;resources.anthropic.com&#x2F;code-modernization-playbook&quot;&gt;Code Modernization Playbook&lt;&#x2F;a&gt;は
優れた資料ですが、
あくまで「探索と分析のコスト障壁を
下げる」ことに焦点を当てています。
最終的に移行を完遂するには、
業務知識を持った人間の判断が不可欠です。
そしてその人間がいないことこそが、
メインフレーム・モダナイゼーションが
何十年も進まない理由なのです。&lt;&#x2F;p&gt;
&lt;p&gt;株価が映しているのは、
「AIがCOBOLを解決する」という
期待と恐怖です。
しかし現実には、
必要なのは業務知識の再構築への
地道な投資であり、
どんなに優秀なAIツールが登場しても、
その投資の代わりにはなりません。&lt;&#x2F;p&gt;
&lt;p&gt;IBM自身のツールにClaudeが
組み込まれているという事実は、
技術の世界に敵味方の区別がない
ことを示しています。
本当の敵はツールの優劣ではなく、
長い年月をかけて失われた
業務知識という名の技術的負債です。
Anthropic、IBM、AWSのいずれであっても、
魔法のように解くことはできません。
それでも、この問題を直視し、
業務知識の再構築に地道に取り組む
組織だけが、次の時代のシステムを
手にするのだと思います。&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;CNBC.
&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cnbc.com&#x2F;2026&#x2F;02&#x2F;23&#x2F;ibm-is-the-latest-ai-casualty-shares-are-tanking-on-anthropic-cobol-threat.html&quot;&gt;IBM is the latest AI casualty.
Shares tank 13% on Anthropic programming
language threat&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;li&gt;GIGAZINE.
「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gigazine.net&#x2F;news&#x2F;20260224-ibm-ai-casualty-anthropic-claude-code-cobol&#x2F;&quot;&gt;IBMの株価が13％下落、AnthropicがClaude Codeで
「COBOLを使ったレガシーシステムの
モダナイゼーションの自動化」を解説したのが
原因&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;Anthropic.
&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;claude.com&#x2F;blog&#x2F;how-ai-helps-break-cost-barrier-cobol-modernization&quot;&gt;How AI helps break the cost barrier
to COBOL modernization&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;li&gt;ITmedia エンタープライズ.
「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.itmedia.co.jp&#x2F;enterprise&#x2F;articles&#x2F;2602&#x2F;19&#x2F;news045.html&quot;&gt;日本IBMのAI戦略&quot;3つの柱&quot;
「制御できるAI」でレガシー資産を
モダナイズ&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;IBM.
&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ibm.com&#x2F;new&#x2F;announcements&#x2F;ibm-project-bob&quot;&gt;Announcing IBM Project Bob&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;li&gt;Anthropic.
&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;resources.anthropic.com&#x2F;code-modernization-playbook&quot;&gt;The Code Modernization Playbook&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;li&gt;AWS.
&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;m2&#x2F;latest&#x2F;userguide&#x2F;ba-shared-architecture.html&quot;&gt;Blu Age Runtime high level
architecture&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&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;本記事は投資助言を目的とするものではありません。
筆者は現在IBMとの雇用関係はなく、
記載された情報は全て公開情報に基づく
個人の見解です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">AnthropicのCOBOLモダナイゼーション対応発表で
IBM株が13%急落しました。皮肉にもIBM自身が
Claudeを自社ツールに組み込んでいた矢先の出来事です。
Watson時代を知る元IBM社員の視点から、
COBOLの構造的課題とツールの限界を考察します。
</summary>
        </entry><entry xml:lang="en">
        <title>Zolaテーマ「tabi」の活用機能を探る</title>
        <published>2026-02-24T12:00:00+09:00</published>
        <updated>2026-02-24T12:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/zola-theme-tabi/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/zola-theme-tabi/</id>
        
            <content type="html">&lt;!-- author-approved: ショートコード名・設定項目の列挙に###を使用 --&gt;
&lt;p&gt;このブログはZola静的サイトジェネレーターと
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;welpo.github.io&#x2F;tabi&#x2F;&quot;&gt;tabi&lt;&#x2F;a&gt;テーマで
運用しています。
tabiは多機能なテーマですが、
実際に活用しているのはその一部に過ぎません。
改めてテーマの全機能を棚卸しして、
まだ使っていない機能を洗い出してみました。&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;ショートコード&quot;&gt;ショートコード&lt;&#x2F;h2&gt;
&lt;p&gt;tabiには18種類のビルトインショートコードと、
このブログ用に自作したカスタムショートコード
2種類があります
（カスタムコードは当然ながらtabiには
含まれません）。&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;admonition&lt;&#x2F;td&gt;&lt;td&gt;info、warning、tipなどのタイプを指定して、注意書きや補足情報を装飾付きボックスで表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;add_src_to_code_block（非推奨）&lt;&#x2F;td&gt;&lt;td&gt;コードブロックの &lt;code&gt;name=&lt;&#x2F;code&gt; ラベルをクリック可能なリンクに変換します。現在は &lt;code&gt;code_block_name_links = true&lt;&#x2F;code&gt; を設定し、&lt;code&gt;name=&lt;&#x2F;code&gt; にURLを直接書く方式が推奨されています&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;aside&lt;&#x2F;td&gt;&lt;td&gt;本文の横にサイドバー風の補足情報を表示します。admonitionより控えめな見た目で、ちょっとした注釈を添えるのに向いています&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;dimmable_image&lt;&#x2F;td&gt;&lt;td&gt;ダークモード時に画像の明るさを自動的に抑えます。白背景のスクリーンショットがダークモードで眩しくなるのを防げます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;dual_theme_image&lt;&#x2F;td&gt;&lt;td&gt;ライトモードとダークモードで異なる画像を自動的に切り替えて表示します。背景色によって見えにくくなる図表に便利です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;force_text_direction&lt;&#x2F;td&gt;&lt;td&gt;テキストブロックのLTR（左から右）またはRTL（右から左）の方向を強制的に指定します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;full_width_image&lt;&#x2F;td&gt;&lt;td&gt;記事の本文幅を超えて、画像をページ全幅で表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;iine&lt;&#x2F;td&gt;&lt;td&gt;特定のブロック単位でいいねボタンを設置できます。tabiの作者が提供するSupabaseインスタンスにカウントが記録されます。導入時はプライバシーポリシーの更新を検討してください&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;image_hover&lt;&#x2F;td&gt;&lt;td&gt;マウスホバーで別の画像に切り替わります。Before&#x2F;After比較や加工前後の写真を見比べるのに最適です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;image_toggler&lt;&#x2F;td&gt;&lt;td&gt;クリックで2枚の画像をトグル切り替えします。image_hoverと似ていますが、ホバーが使えないモバイル環境でも動作します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;invertible_image&lt;&#x2F;td&gt;&lt;td&gt;ダークモード時に画像の色を反転します。白背景に黒線で描かれた図表をダークモードでも見やすくできます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;linkcard（自作）&lt;&#x2F;td&gt;&lt;td&gt;はてなブログカードのiframeを使い、URLをカード形式で表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;mermaid&lt;&#x2F;td&gt;&lt;td&gt;Mermaid記法でフローチャートやシーケンス図などの図表を描画します。記事のFrontmatterで &lt;code&gt;mermaid = true&lt;&#x2F;code&gt; の設定が必要です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;multilingual_quote&lt;&#x2F;td&gt;&lt;td&gt;原文と翻訳をトグルで切り替え表示できる引用ブロックです。英語の技術ドキュメントを引用する際に原文と日本語訳を並べて見せられます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;references&lt;&#x2F;td&gt;&lt;td&gt;参考文献をスタイル付きで表示するブロックです。学術的な記事や多くの出典をまとめる場合に適しています&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;remote_text&lt;&#x2F;td&gt;&lt;td&gt;外部URLやローカルファイルの内容を記事内にインラインで埋め込みます。GitHubにあるコンフィグファイルをそのまま表示するような使い方ができます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;spoiler&lt;&#x2F;td&gt;&lt;td&gt;クリックするまで内容が隠されるテキストブロックです。ネタバレを隠したりクイズの答えを伏せるのに使えます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;toc&lt;&#x2F;td&gt;&lt;td&gt;記事内に &lt;code&gt;&amp;lt;!-- toc --&amp;gt;&lt;&#x2F;code&gt; マーカーを挿入するショートコードです。マーカーを直接書くのと同等の動作です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;wide_container&lt;&#x2F;td&gt;&lt;td&gt;記事の本文幅を超えて、ページ全幅にコンテンツを表示します。大きな表やワイドな画像を見切れずに表示したい場合に使えます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;youtube（自作）&lt;&#x2F;td&gt;&lt;td&gt;YouTube動画を埋め込み表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;以下、このブログで使用しているショートコードから、
よく使うものに絞ってサンプルを載せておきます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;admonition&quot;&gt;admonition&lt;&#x2F;h3&gt;
&lt;p&gt;info、warning、danger、tip、noteなどの
タイプを指定できます。&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-text&quot;&gt;{% admonition(type=&amp;quot;warning&amp;quot;, title=&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-text&quot;&gt;ここに警告メッセージを書きます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% end %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&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;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;aside&quot;&gt;aside&lt;&#x2F;h3&gt;
&lt;p&gt;admonitionより控えめな見た目で、
ちょっとした注釈を添えるのに向いています。
PCなどの表示では記事の左右に表示され、
スマートフォンなどでは記事と並んで
表示されます。
&lt;code&gt;position&lt;&#x2F;code&gt; パラメータで配置を調整できます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;右側にも表示できます。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&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-text&quot;&gt;{% aside(position=&amp;quot;right&amp;quot;) %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-text&quot;&gt;{% end %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;multilingual_quote&quot;&gt;multilingual_quote&lt;&#x2F;h3&gt;
&lt;p&gt;原文と翻訳をトグルで切り替え表示できます。
英語の技術ドキュメントを引用する際に、
原文と日本語訳を並べて見せられます。
&lt;code&gt;author&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-text&quot;&gt;{{ multilingual_quote(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  translated=&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-text&quot;&gt;  original=&amp;quot;Cogito, ergo sum.&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  author=&amp;quot;René Descartes&amp;quot;) }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;quote-container&quot;&gt;
    &lt;input type=&quot;checkbox&quot; id=&quot;toggle-2159&quot; class=&quot;quote-toggle&quot;&gt;
    &lt;div class=&quot;quote&quot;&gt;
        &lt;div class=&quot;translated&quot;&gt;
            &lt;blockquote&gt;
                &lt;p&gt;“考える、ゆえに我あり。”&lt;&#x2F;p&gt;
                &lt;p&gt;— René Descartes &lt;label for=&quot;toggle-2159&quot; class=&quot;quote-label quote-label-original&quot;&gt;
                    (Show original quote)
                &lt;&#x2F;label&gt;&lt;&#x2F;p&gt;
            &lt;&#x2F;blockquote&gt;
        &lt;&#x2F;div&gt;
        &lt;div class=&quot;original&quot;&gt;
            &lt;blockquote&gt;
                &lt;p&gt;“Cogito, ergo sum.”&lt;&#x2F;p&gt;
                &lt;p&gt;— René Descartes &lt;label for=&quot;toggle-2159&quot; class=&quot;quote-label quote-label-translate&quot;&gt;
                    (Show translation)
                &lt;&#x2F;label&gt;&lt;&#x2F;p&gt;
            &lt;&#x2F;blockquote&gt;
        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;references&quot;&gt;references&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-text&quot;&gt;{% references() %}&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; WEBサイト. 「&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;[記事名]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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; 著者(2026). 『書名』.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {% end %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;Example Site. 「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;example.com&#x2F;article&quot;&gt;Zolaで技術ブログを作る&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;結城浩. (2020). 『&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;example.com&#x2F;book&quot;&gt;数学ガール&lt;&#x2F;a&gt;』&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;spoiler&quot;&gt;spoiler&lt;&#x2F;h3&gt;
&lt;p&gt;クリックするまで内容がぼかされて隠れます。
JavaScriptを使わず、
CSSとチェックボックスで実装されています。&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-text&quot;&gt;犯人は、{{ spoiler(text=&amp;quot;執事でした。&amp;quot;) }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;p&gt;犯人は、


&lt;label class=&quot;spoiler-container&quot;&gt;
    &lt;input type=&quot;checkbox&quot; id=&quot;spoiler-22573&quot; class=&quot;spoiler-toggle&quot; role=&quot;button&quot; aria-pressed=&quot;false&quot; &#x2F;&gt;
    &lt;span class=&quot;spoiler-content&quot; title=&quot;reveal spoiler&quot; tabindex=&quot;0&quot;&gt;
        &lt;span class=&quot;spoiler-hidden&quot;&gt;執事でした。&lt;&#x2F;p&gt;
&lt;&#x2F;span&gt;
    &lt;&#x2F;span&gt;
&lt;&#x2F;label&gt;
&lt;&#x2F;p&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;テンプレート&quot;&gt;テンプレート&lt;&#x2F;h2&gt;
&lt;p&gt;tabiでは記事に対して3種類のtemplateが
提供されています。
いずれもセクションの &lt;code&gt;_index.md&lt;&#x2F;code&gt; で有効にします。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;section - 通常のテンプレート&lt;&#x2F;dt&gt;
&lt;dd&gt;通常の記事向けのテンプレートです。&lt;&#x2F;dd&gt;
&lt;dt&gt;series — 連載記事テンプレート&lt;&#x2F;dt&gt;
&lt;dd&gt;複数回にわたる連載記事を番号付きインデックスで管理できるテンプレートです。&lt;&#x2F;dd&gt;
&lt;dd&gt;複数回にわたる技術解説記事に向いています。&lt;&#x2F;dd&gt;
&lt;dt&gt;cards — カードグリッドテンプレート&lt;&#x2F;dt&gt;
&lt;dd&gt;フィルタ可能なカードグリッドのレイアウトです。&lt;&#x2F;dd&gt;
&lt;dd&gt;ポートフォリオやプロジェクト一覧を見せるのに適しています。&lt;&#x2F;dd&gt;
&lt;dd&gt;タグによるフィルタリングも可能です。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;サイト設定&quot;&gt;サイト設定&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;config.toml&lt;&#x2F;code&gt; の &lt;code&gt;[extra]&lt;&#x2F;code&gt; セクションで
設定できるオプションです。
以下の説明は、筆者が気になったものだけを
取り上げており網羅的ではありません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;skin_—_カラースキーム&quot;&gt;skin — カラースキーム&lt;&#x2F;h3&gt;
&lt;p&gt;tabiには12種類のカラースキームが用意されています。
sakura、lavender、mint、teal、evangelionなど、
テーマカラーを一行で切り替えられます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&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;extra&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;skin&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 z-definition z-string z-string&quot;&gt; &amp;quot;sakura&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このブログでは &lt;code&gt;custom.css&lt;&#x2F;code&gt; で
独自にカラーを指定しているため使っていません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;browser_theme_color_—_モバイルブラウザのテーマカラー&quot;&gt;browser_theme_color — モバイルブラウザのテーマカラー&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;toml&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;extra&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;browser_theme_color&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 z-definition z-string z-string&quot;&gt; &amp;quot;#087e96&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;compact_tags_—_コンパクトなタグクラウド&quot;&gt;compact_tags — コンパクトなタグクラウド&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;toml&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;extra&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;compact_tags&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-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;feed_icon_—_RSSアイコン&quot;&gt;feed_icon — RSSアイコン&lt;&#x2F;h3&gt;
&lt;p&gt;フッターにRSSフィードのアイコンを表示します。
当ブログではsocialsを使ってRSSを
表示しているため使用していません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&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;extra&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;feed_icon&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-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;full_content_in_feed_—_フィード全文配信&quot;&gt;full_content_in_feed — フィード全文配信&lt;&#x2F;h3&gt;
&lt;p&gt;Atomフィードに記事の全文を含めます。
当ブログでは既にこの設定を有効にしています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&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;extra&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;full_content_in_feed&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-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;webmentions_—_IndieWeb_Webmentions&quot;&gt;webmentions — IndieWeb Webmentions&lt;&#x2F;h3&gt;
&lt;p&gt;Webmentionによるインタラクションを表示できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&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;extra.webmentions&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;enable&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-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;domain&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 z-definition z-string z-string&quot;&gt; &amp;quot;www.example.com&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;KaTeX_—_数式レンダリング&quot;&gt;KaTeX — 数式レンダリング&lt;&#x2F;h3&gt;
&lt;p&gt;LaTeX形式の数式をレンダリングできます。
数学や統計を扱う記事で使えます。&lt;&#x2F;p&gt;
&lt;p&gt;記事のFrontmatterで有効化します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&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;extra&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;katex&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-constant z-language z-boolean&quot;&gt; true&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;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;インライン数式: $E = mc^2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;ブロック数式: $$\sum_{i=1}^{n} x_i$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;未使用のFrontmatterオプション&quot;&gt;未使用のFrontmatterオプション&lt;&#x2F;h2&gt;
&lt;p&gt;記事ごとに &lt;code&gt;[extra]&lt;&#x2F;code&gt; セクションで
個別にオーバーライドできる設定です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tldr&quot;&gt;tldr&lt;&#x2F;h3&gt;
&lt;p&gt;これまでセクションを設けて記載していましたが、
Frontmatterで設定できることがわかりました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;updated_—_最終更新日&quot;&gt;updated — 最終更新日&lt;&#x2F;h3&gt;
&lt;p&gt;記事の最終更新日を &lt;code&gt;date&lt;&#x2F;code&gt; とは別に表示します。
内容を更新した記事に設定すると、
読者に最新性を伝えられます。
&lt;code&gt;[extra]&lt;&#x2F;code&gt; ではなくトップレベルの
Frontmatterフィールドです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&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-source&quot;&gt;title&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 z-definition z-string 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-source&quot;&gt;date&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; 2026-02-01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;updated&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; 2026-02-20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;+++&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;show_reading_time_—_読了時間の個別制御&quot;&gt;show_reading_time — 読了時間の個別制御&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;toml&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;extra&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;show_reading_time&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-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;giscus_—_コメントの個別制御&quot;&gt;giscus — コメントの個別制御&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;toml&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;extra&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;giscus&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-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;toc_—_目次の個別制御&quot;&gt;toc — 目次の個別制御&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;toml&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;extra&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;toc&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-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このブログでは &lt;code&gt;&amp;lt;!-- toc --&amp;gt;&lt;&#x2F;code&gt; マーカーを
&lt;code&gt;details&lt;&#x2F;code&gt;要素に入れて、畳めるようにしているため利用していませんが、
そのような要件がなければ
Frontmatterで制御するほうがシンプルです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;tabiは使い切れないほど多機能なテーマです。
今回改めて棚卸しをしてみると、
これまで使っていなかった機能のなかにも
便利なものが数多く存在しました。&lt;&#x2F;p&gt;
&lt;p&gt;たとえば &lt;code&gt;tldr&lt;&#x2F;code&gt; はこれまで記事本文に
セクションを設けて書いていましたが、
Frontmatterに設定するだけで済むと知り、
今後は積極的に活用していきます。
&lt;code&gt;updated&lt;&#x2F;code&gt; による最終更新日の表示なども、
知っていれば必要な場面ですぐに使える
実用的なオプションです。&lt;&#x2F;p&gt;
&lt;p&gt;テンプレートについても、
これまでは通常の &lt;code&gt;section&lt;&#x2F;code&gt; テンプレートしか
使っていませんでしたが、
&lt;code&gt;series&lt;&#x2F;code&gt; テンプレートは複数回にわたる
連載記事をまとめるのに向いており、
技術解説のシリーズ記事などで
活用していきたいと考えています。
&lt;code&gt;cards&lt;&#x2F;code&gt; テンプレートも、
ポートフォリオやプロジェクト一覧のような
通常のブログ記事とは異なるタイプの
コンテンツを見せる場面で使えそうです。&lt;&#x2F;p&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;tabi. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;welpo.github.io&#x2F;tabi&#x2F;&quot;&gt;tabi documentation&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Zolaの高機能テーマ「tabi」には、
普段使っていない便利な機能が数多く眠っています。
ショートコード、テンプレート、Frontmatterオプションまで、
見落としがちな機能をまとめて紹介します。
</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>Cloudflare無料プランだけで個人サイトのセキュリティが完結した話</title>
        <published>2026-02-20T00:00:00+00:00</published>
        <updated>2026-02-20T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/cloudflare-benefits/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/cloudflare-benefits/</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;02&amp;#x2F;cloudflare-benefits&amp;#x2F;cover.webp?h=a800061cf7b938db4dbe&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareのアドバンテージは、次の3点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;無料プランだけでWAF・ボット対策まで揃う、セキュリティの充実度&lt;&#x2F;li&gt;
&lt;li&gt;DNS統合だからこそ、煩雑でリスクの高い設定をワンクリックで実現&lt;&#x2F;li&gt;
&lt;li&gt;AIクローラー対策やページ先読みなど、最新トレンドへの即応&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;つい3日前に&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;migration-to-cloudflare&#x2F;&quot;&gt;Cloudflareへ移転した&lt;&#x2F;a&gt;ばかりです。構成はシンプルで、Cloudflareでドメインを取得し、GitHubリポジトリと連携して静的コンテンツをCloudflare Pages&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;へデプロイしています。この構成だけでも思いの外多くの恩恵が得られたので、まとめておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflareでの設定&quot;&gt;Cloudflareでの設定&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareのダッシュボードで有効にした機能を、カテゴリごとに紹介します。いずれも無料プランで利用でき、ほとんどがトグルひとつで有効にできるものです。なお、本記事の機能名やβ表記は2026年2月時点のCloudflare管理画面のUIに基づいています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Edge_Certificates&quot;&gt;Edge Certificates&lt;&#x2F;h3&gt;
&lt;p&gt;Cloudflareが発行・管理するSSL&#x2F;TLS証明書と、HTTPS通信に関する設定です。&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;Always Use HTTPS&lt;&#x2F;td&gt;&lt;td&gt;HTTP でアクセスが来た場合に自動的に HTTPS へ301リダイレクトしてくれるので、暗号化されていない通信を防げる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HSTS&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.dev&lt;&#x2F;code&gt; ドメイン&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を使用しているので私の場合あまり恩恵がないが、ブラウザレベルでHTTPSが強制できる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Minimum TLS Version&lt;&#x2F;td&gt;&lt;td&gt;サイトに接続する際に許可するTLSプロトコルの最低バージョンの指定。TLS 1.0 と 1.1 は既知の脆弱性があるので、私はTLS1.2にしている。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Opportunistic Encryption&lt;&#x2F;td&gt;&lt;td&gt;HTTPでアクセスしてきたブラウザに対して「暗号化接続も利用可能ですよ」と通知する仕組み。&lt;code&gt;.dev&lt;&#x2F;code&gt; の場合、HTTPアクセスが発生しないので実質的に意味がない。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TLS 1.3&lt;&#x2F;td&gt;&lt;td&gt;Minimum TLS Version を 1.2 に設定し、この TLS 1.3 をオンにしておけば、「最低 1.2、対応していれば 1.3 を使う」という構成になる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Automatic HTTPS Rewrites&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;http:&#x2F;&#x2F;&lt;&#x2F;code&gt; をCloudflare が自動的に &lt;code&gt;https:&#x2F;&#x2F;&lt;&#x2F;code&gt; に書き換えて「混在コンテンツ（mixed content）」の問題を防いでくれる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Certificate Transparency Monitoring&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;Security&quot;&gt;Security&lt;&#x2F;h3&gt;
&lt;p&gt;ボット対策、DDoS防御、WAFなど、サイトを外部の脅威から守るための設定です。&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;AI Labyrinth&lt;&#x2F;td&gt;&lt;td&gt;まだβ機能だが、robots.txt 等のクロールルールを無視して勝手にサイトをスクレイピングするボットに対して偽コンテンツを読ませて学習データを汚染させるという「ハニーポット」的な機能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Block AI bots&lt;&#x2F;td&gt;&lt;td&gt;AI学習用クローラーをブロックする機能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bot fight mode&lt;&#x2F;td&gt;&lt;td&gt;悪意のあるボット（スパム、クレデンシャルスタッフィング、DDoS等）を検知すると、JavaScriptチャレンジを出して人間かどうかを確認する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Browser Integrity Check&lt;&#x2F;td&gt;&lt;td&gt;訪問者のHTTPヘッダーを検査して、不正なUser-Agentやスパムボットによく見られる異常なヘッダーパターンを検出し、脅威が見つかった場合はブロックページを表示する。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Challenge passage&lt;&#x2F;td&gt;&lt;td&gt;チャレンジ（CAPTCHA等）をクリアした訪問者が、再度チャレンジを求められるまでの有効時間&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP DDoS attack protection&lt;&#x2F;td&gt;&lt;td&gt;HTTPレイヤーのDDoS攻撃を自動検知・緩和する。無料プランでもCloudflare Free Managed Ruleset（基本的なWAFルール）が付属する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Manage your robots.txt&lt;&#x2F;td&gt;&lt;td&gt;Cloudflare が robots.txt を自動管理するβ機能。Content Signals Policyを選択すると、コンテンツの利用意図を用途別（検索・AI入力・AI学習）に宣言できる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Network-layer DDoS attack protection&lt;&#x2F;td&gt;&lt;td&gt;DDoS保護&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;DNS&quot;&gt;DNS&lt;&#x2F;h3&gt;
&lt;p&gt;DNS応答の改ざん防止やメールのなりすまし対策など、ドメインの信頼性を高める設定です。&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;DNSSEC&lt;&#x2F;td&gt;&lt;td&gt;DNSレスポンスに暗号署名を付与して、DNS応答の偽造（DNSキャッシュポイズニング等）を防ぐ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Email Security&lt;&#x2F;td&gt;&lt;td&gt;有効にしてDMARCの設定。メール送信の予定はないので、SPFは&quot;v=spf1 -all&quot;で設定。DMARCは&quot;v=DMARC1; p=reject&quot;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;Speed&quot;&gt;Speed&lt;&#x2F;h3&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;Web analytics using real user measurement (RUM)&lt;&#x2F;td&gt;&lt;td&gt;実際の訪問者のブラウザからパフォーマンスデータ（ページ読み込み時間など）を収集する。Cookieを使わないプライバシー重視の計測方式&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Speed Brain&lt;&#x2F;td&gt;&lt;td&gt;ユーザーがリンクをクリックする前にページを先読みする機能。Speculation Rules API を使い、体感的なページ遷移が高速になる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2&lt;&#x2F;td&gt;&lt;td&gt;HTTP&#x2F;1.1の後継。1つの接続で複数リクエストを並行処理（多重化）でき、ページ読み込みが高速になる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;3&lt;&#x2F;td&gt;&lt;td&gt;HTTP&#x2F;2の次世代版。TCPの代わりにQUICプロトコルを使い、接続確立が高速でパケットロス時の劣化も少ない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2 to Origin&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareとオリジンサーバー間の通信にもHTTP&#x2F;2を使う設定&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0-RTT Connection Resumption&lt;&#x2F;td&gt;&lt;td&gt;TLS 1.3で接続済みのクライアントが再訪問時にハンドシェイクの最初の往復を省略でき、再訪問者の初回リクエストが速くなる&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;昨年までAmazon Amplify、先月までGitHub Pagesで運用していました。
上記で挙げたCloudflareの機能が、それぞれの環境ではどうだったかを比較してみます。特にセキュリティ列の差に注目してください。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;○: 標準&#x2F;無料で利用可能&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;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Amplify + CloudFront&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;GitHub Pages&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;Always Use HTTPS&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HSTS&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（手動設定）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;AWSだけ手動設定の手間がかかる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Minimum TLS Version&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;GitHub Pagesは古いTLSを拒否できず、セキュリティポリシーを徹底しにくい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Opportunistic Encryption&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;HTTP接続の暗号化への誘導は他のサービスでは提供されていない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TLS 1.3&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Automatic HTTPS Rewrites&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;他では混在コンテンツを自分で探して直す必要がある&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Certificate Transparency Monitoring&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（ACMの一部）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;不正な証明書発行の早期発見に差が出る&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AI Labyrinth&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;ワンクリックでAIスクレイピングに対抗できる機能は他にない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Block AI bots&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAFルールで対応）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;AWSは自前でルールを書く手間とWAF費用がかかる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bot fight mode&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAF Bot Control有料）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;AWSで同等機能を得るにはBot Control（月額$10〜＋リクエスト従量課金）が必要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Browser Integrity Check&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAFで部分的）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;AWSでは同等ルールの自作が必要で、運用負荷が高い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Challenge passage&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAF）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareはチャレンジの有効期間まで細かく制御できる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP DDoS attack protection&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAFは有料）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;無料でWAFまで付くのはCloudflareの大きな強み&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Manage your robots.txt&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;増え続けるAIクローラーへの対応を自動化できる機能は他にない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Network-layer DDoS attack protection&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○（Shield Standard）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;DNSSEC&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○（Route 53）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（DNS providerに依存）&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareはワンクリック、DNS一体管理なので設定が圧倒的に楽&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Email Security&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○（Route 53）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（DNS providerに依存）&lt;&#x2F;td&gt;&lt;td&gt;同上。DNS管理とセットなのでSPF&#x2F;DMARCの設定も迷わない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Web analytics (RUM)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（CloudWatch RUM有料）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareは追加費用なしでCookie不要の計測が使える&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Speed Brain&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;ページ先読みによる体感速度向上は他のサービスでは提供されていない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;3&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;GitHub Pagesは2026年2月時点でHTTP&#x2F;3未サポート&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2 to Origin&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;−&lt;&#x2F;td&gt;&lt;td&gt;オリジンサーバーがある構成でのみ意味がある&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0-RTT&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&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;h2 id=&quot;AI時代のコンテンツ保護&quot;&gt;AI時代のコンテンツ保護&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareの無料プランには、AIクローラーに対応する機能が複数用意されています。これらは独立した機能ですが、組み合わせると多層的な防御になります。&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;Content Signals Policy&lt;&#x2F;td&gt;&lt;td&gt;意思表示&lt;&#x2F;td&gt;&lt;td&gt;robots.txt内でコンテンツの用途別に許可&#x2F;拒否を宣言する。強制力はなく、善意あるクローラーへの「お願い」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Block AI bots&lt;&#x2F;td&gt;&lt;td&gt;技術的ブロック&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareが「AI学習用」と分類するクローラーをWAFレベルでブロックする。検索エンジンやAIアシスタントは対象外&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AI Labyrinth&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;ポイントは、Content Signals PolicyとBlock AI botsの役割分担です。Content Signals Policyでは &lt;code&gt;search=yes, ai-input=yes, ai-train=no&lt;&#x2F;code&gt; のように宣言し、「検索やAI回答での引用はOKだが、モデルの学習には使うな」という意思を伝えます。しかし宣言はあくまで「お願い」なので、AI学習用クローラーに対してはBlock AI botsがWAFレベルで実際にアクセスを遮断します。それでもすり抜けてくるクローラーにはAI Labyrinthが偽データを食わせます。&lt;&#x2F;p&gt;
&lt;p&gt;さらに、AI Crawl ControlのCrawlersタブではクローラーごとに個別のAllow&#x2F;Blockを設定できます。たとえば「ChatGPT-Userは許可するがBytespiderはブロックする」といった細かい制御も可能です。&lt;&#x2F;p&gt;
&lt;p&gt;この多層構成により、AI検索からの流入を確保しつつ学習目的のスクレイピングは拒否するという運用が、無料プランだけで実現できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflareの評価&quot;&gt;Cloudflareの評価&lt;&#x2F;h2&gt;
&lt;p&gt;比較表を振り返ると、Cloudflareの強みは大きく3つあります。&lt;&#x2F;p&gt;
&lt;p&gt;1つ目は、無料プランでのセキュリティの充実度です。AWSで同等のボット対策やWAFを実現しようとすると、AWS WAFやBot Controlの追加費用と自前でのルール作成が必要でした。GitHub Pagesではユーザーが設定できるセキュリティ機能はほとんどありません。Cloudflareでは、AIボットのブロック、Bot fight mode、WAFまで無料プランに含まれており、しかもダッシュボードのトグルひとつで有効にできます。&lt;&#x2F;p&gt;
&lt;p&gt;2つ目は、DNS・証明書・セキュリティ・CDNがひとつのダッシュボードに統合されている点です。AWSではRoute 53、CloudFront、ACM、WAFと複数サービスをまたいで設定する必要がありました。GitHub PagesではDNSが外部依存のため、DNSSECやSPF&#x2F;DMARCの設定は利用するDNSプロバイダ次第でした。Cloudflareではドメイン取得からDNSSEC、メールセキュリティ、デプロイまで一箇所で完結するため、設定の見通しがよく管理も楽です。&lt;&#x2F;p&gt;
&lt;p&gt;3つ目は、他のサービスでは提供されていない独自機能です。前述のとおり、Content Signals PolicyからBlock AI bots、AI Labyrinthまで、AIクローラーへの多層的な対応が無料プランだけで揃います。加えて、Speculation Rules APIを活用したSpeed BrainやTLS 1.3の0-RTT再接続など、パフォーマンス面でも独自の機能が提供されています。特にAIクローラー対策は今後ますます重要になる領域であり、「意思表示」と「技術的ブロック」と「欺瞞防御」を組み合わせた構成がワンクリックで手に入るのは大きな安心感があります。&lt;&#x2F;p&gt;
&lt;p&gt;個人の静的サイトという用途では、Cloudflareの無料プランだけで「やりたいことが全部できる」状態になりました。以前はAWSの複数サービスを組み合わせて実現していたことが、Cloudflareではひとつのダッシュボードで、しかも無料で手に入ります。移行してよかったと素直に思います。&lt;&#x2F;p&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-2&quot;&gt;
&lt;p&gt;Cloudflare Pagesは現在、Cloudflare Workersとの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;pages-and-workers-are-converging-into-one-experience&#x2F;&quot;&gt;統合が進んでいる&lt;&#x2F;a&gt;。将来的にはWorkersの静的アセット機能に一本化される見込みだが、Pages自体も引き続き利用可能。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;code&gt;.dev&lt;&#x2F;code&gt; ドメインはGoogleが管理しているTLDで、HSTS Preload ListにTLD単位で登録済みなので最初からHTTPSが強制される。 &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">Cloudflareの無料プランで利用できるWAF・ボット対策・AIクローラー対策などのセキュリティ機能を、AWS AmplifyやGitHub Pagesと比較しながら紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>非エンジニアのためのClaude Code入門ハンズオンを公開しました</title>
        <published>2026-02-18T00:00:00+00:00</published>
        <updated>2026-02-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/claude-code-entry/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/claude-code-entry/</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;02&amp;#x2F;claude-code-entry&amp;#x2F;cover.webp?h=b65196c18135d12c77d7&quot;
  alt=&quot;Cover&quot; width=&quot;1456&quot; height=&quot;816&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&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-entry&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;非エンジニアにもエージェント型AIを広めたい&quot;&gt;非エンジニアにもエージェント型AIを広めたい&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeはエンジニアの世界を一変させました。AIが自らコードを読み書きし、テストを実行し、デバッグまでこなす。ソフトウェア開発の生産性は劇的に向上し、エージェント型AIはエンジニアにとって不可欠なツールになっています。&lt;&#x2F;p&gt;
&lt;p&gt;この波は非エンジニアにも広がり始めています。2026年1月にAnthropicがリリースした「Claude Cowork」は、コマンドライン不要でデスクトップ上のファイルを直接読み書きできるエージェント型AIです。ただし現時点ではClaude Maxプラン向けの研究プレビューであり、すぐに誰でも使えるわけではありません。&lt;&#x2F;p&gt;
&lt;p&gt;Coworkの正式展開を待たなくても、エージェント型AIとの協業は今すぐ体験できます。Claude CodeはターミナルとエディタがあればPro&#x2F;Maxプランで利用可能です。プログラミング経験がない方を対象にしたセルフハンズオン教材を作りました。&lt;&#x2F;p&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-entry&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;何を学べるか&quot;&gt;何を学べるか&lt;&#x2F;h2&gt;
&lt;p&gt;演習の題材は、WebサイトリニューアルのRFP（提案依頼書）です。「ベンダーに出すRFP書いて」と上司に言われて途方に暮れている非エンジニアの同僚の姿、あるいはでき上がったRFPを見てあなたが頭を抱えた経験はありませんか。要件が曖昧、評価基準が不明確、技術的に実現不可能な記述――エンジニアから見るとツッコミどころ満載の仕様書が回ってくるのはよくある話です。&lt;&#x2F;p&gt;
&lt;p&gt;このハンズオンでは、架空の経営支援サービス会社の社員としてその状況に挑みます。Claude Codeと協業しながらRFPを段階的に仕上げる5つの工程を通じて、ひとりでは手に負えない文書でもエージェント型AIがあれば形にできることを実感してもらえます。環境はWindows PC前提で、Macは想定していません。非エンジニアの標準的な業務環境をそのまま使えるようにしています。&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;Claude Codeの役割&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;仕様書を作成する&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;&#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;HTML変換を行う&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ポイントは「生成AIに丸投げする」のではなく、「工程を踏んで人間が主導する」ことです。各工程でエージェントにどう指示し、どう情報を共有し、どう成果物を仕上げるかを体験します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対象者&quot;&gt;対象者&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;プログラミング経験がない、または少ない方&lt;&#x2F;li&gt;
&lt;li&gt;生成AIを業務の文書作成に活用したい方&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;前提として必要なのは、PCの基本操作とMarkdownの基本的な書き方だけです。プログラミングの知識は不要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜRFPを題材にしたか&quot;&gt;なぜRFPを題材にしたか&lt;&#x2F;h2&gt;
&lt;p&gt;システムの提案依頼書（RFP）を題材に選んだ理由は3つあります。&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;生成AIとの相性が良い&lt;&#x2F;strong&gt; -- 要件の洗い出しや表現の推敲に向いている&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;「チャットで聞いてコピペする」のではなく、構造化された文書をエージェントと一緒に段階的に作り上げるプロセスを体験することが、このハンズオンの狙いです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3つの柱&quot;&gt;3つの柱&lt;&#x2F;h2&gt;
&lt;p&gt;このハンズオンでは、以下の3つを重視しています。&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; -- 生成AIは道具。何を作るか決めるのは自分&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ツールを組み合わせる&lt;&#x2F;strong&gt; -- 校正ツール（textlint）など、小さなツールをClaude Codeに使わせる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に「人間が主導する」は、品質面だけでなく著作権の観点からも重要です。人間が構成を考え、指示を出し、取捨選択や修正を加えることで、AI生成物に対する人間の創作的寄与が認められやすくなります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;環境と所要時間&quot;&gt;環境と所要時間&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;環境&lt;&#x2F;strong&gt;: Windows PC、Git Bash、Visual Studio Code&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Code&lt;&#x2F;strong&gt;: Claude Pro&#x2F;Maxプランの契約、またはAPIクレジット&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;所要時間&lt;&#x2F;strong&gt;: 約3時間40分（自分のペースで進行可能）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ハンズオン資料はMarpスライド形式で、ブラウザで開けるHTMLファイルとして提供しています。&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-entry&#x2F;releases&quot;&gt;Releases&lt;&#x2F;a&gt;ページからダウンロードして、すぐに始められます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Dry_Runにつきコメント歓迎&quot;&gt;Dry Runにつきコメント歓迎&lt;&#x2F;h2&gt;
&lt;p&gt;現時点ではDry Run（試行版）として公開しています。&lt;&#x2F;p&gt;
&lt;p&gt;技術知識の前提はできる限り下げています。ただしMarkdownの基本やVS Codeの操作は事前に学んでもらう想定です。プレーンテキストで構造化された文書を書く力は、エージェント型AIと協業するうえで最低限必要なスキルだと考えています。とはいえ、実際に非エンジニアが触ったときの「ここが無理」のラインは作った側には見えません。&lt;&#x2F;p&gt;
&lt;p&gt;ぜひ周囲の非エンジニアの方に試してもらい、フィードバックをいただけると助かります。GitHubの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-entry&#x2F;issues&quot;&gt;Issues&lt;&#x2F;a&gt;でもこの記事のコメントでも構いません。「ここで詰まった」「これは無理」という率直な声が一番ありがたいです。&lt;&#x2F;p&gt;
&lt;p&gt;CC BY 4.0ライセンスで公開していますので、社内研修や勉強会でも自由にご活用ください。&lt;&#x2F;p&gt;
</content>
        <summary type="html">非エンジニアを対象としたClaude Code入門ハンズオン教材を公開しました。RFPの作成を題材に、エージェント型AIとの協業を5つの工程で体験できます。</summary>
        </entry><entry xml:lang="en">
        <title>Zolaブログを新ドメイン取得 + Cloudflare移転</title>
        <published>2026-02-17T00:00:00+00:00</published>
        <updated>2026-02-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/migration-to-cloudflare/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/migration-to-cloudflare/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&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;migration-to-cloudflare&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;TL;DR（Zola利用者向け）&quot;&gt;TL;DR（Zola利用者向け）&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare ProxyとGitHub Pagesの組み合わせでは、Let&#x27;s Encrypt証明書のHTTP-01チャレンジを妨げるリスクがある&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare PagesのCI&#x2F;CDはv2以降Zolaをサポートしていない（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;issue #3&lt;&#x2F;a&gt;は2023年からOpen）。GitHub Actions + &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt;で代替可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;以前、Amazon Amplify + Next.js + Tailwind CSSで運用していたブログをGitHub Pages + Zolaに移行しました。GitHub Pagesはシンプルで運用コストが低い一方、カスタムHTTPレスポンスヘッダーを設定できないという制約があります。&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;github-pages-security-headers&#x2F;&quot;&gt;以前の記事&lt;&#x2F;a&gt;でも書きましたが、セキュリティスキャナーで警告が出る状態をずっと気にしていました。&lt;&#x2F;p&gt;
&lt;p&gt;では、Cloudflareに持っていくかと移転をはじめたところ、いくつかひっかかりポイントがあったので共有します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;新ドメインの取得&quot;&gt;新ドメインの取得&lt;&#x2F;h2&gt;
&lt;p&gt;移転にあたり、新ドメイン&lt;code&gt;codedchords.dev&lt;&#x2F;code&gt;を取得しました。旧ドメインから変更した理由は2つあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflareの無料プランではDNSをCloudflareに移管する必要がある。旧ドメインはFastMailでメール運用しておりDNSもFastMailに移管済みのため、Cloudflareへの再移管が難しい&lt;&#x2F;li&gt;
&lt;li&gt;旧ドメインは長年の運用とブログ改築の結果、404でインデックスされないページが多数あり、これを機に一新してもよい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;TLDは&lt;code&gt;.dev&lt;&#x2F;code&gt;を選びました。&lt;code&gt;.dev&lt;&#x2F;code&gt;はGoogleが管理するTLDで、HSTSプリロードリストに登録されています。ブラウザレベルでHTTPS接続が強制されるため、セキュリティ面で最初から一段高い状態が保証されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflare_Workers_への移行&quot;&gt;Cloudflare Workers への移行&lt;&#x2F;h2&gt;
&lt;p&gt;セキュリティヘッダーを設定するために、Cloudflareを利用する方針で検討を進めました。最終的にCloudflare Workersの静的アセット機能に落ち着くまでに、2つのアプローチで挫折しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;案1: Cloudflare Proxy + Transform Rules（断念）&lt;&#x2F;strong&gt;。最初に検討したのは、CloudflareのProxyを有効にしてTransform Rulesでレスポンスヘッダーを追加する方法です。GitHub Pagesをオリジンとし、Cloudflareを前段に配置する構成です。しかし、GitHub PagesのLet&#x27;s Encrypt証明書は90日ごとにHTTP-01チャレンジで自動更新されます。Cloudflare Proxyが間に入るとチャレンジがGitHubへ届かず、更新が静かに失敗する可能性があります。証明書の期限切れでサイトが突然表示不能になるリスクがあり、静的ブログで証明書を定期監視するのは割に合いません。この案は見送りました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;案2: Cloudflare Pages CI&#x2F;CD（断念）&lt;&#x2F;strong&gt;。次に、Cloudflare PagesのCI&#x2F;CDでZolaをビルドしてそのままホスティングする方法を試みました。しかし、Cloudflare Pagesのv2ビルドシステムではZolaがサポート対象から外れており、ビルドが通りません。この問題は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;GitHubのissue&lt;&#x2F;a&gt;で2023年から報告されていますが、2026年2月現在もOpenのままです。リポジトリにZolaバイナリを同梱するワークアラウンドも提案されていますが、スマートとは言えないためこの案も断念しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;案3: Cloudflare Workers 静的アセット（採用）&lt;&#x2F;strong&gt;。最終的に採用したのが、Cloudflare Workersの静的アセット機能です。CloudflareはWorkersとPagesを統合する方針で、今後の機能開発はWorkersに集中されます。Workersの静的アセット機能は&lt;code&gt;_headers&lt;&#x2F;code&gt;ファイルをネイティブにサポートしており、セキュリティヘッダーの設定が可能です。SSL証明書もCloudflareが一元管理するため更新の問題は発生しません。ビルドはGitHub Actionsで行い、&lt;code&gt;wrangler deploy&lt;&#x2F;code&gt;でデプロイする構成にしました。Zolaのバージョンも自分で管理できます。&lt;&#x2F;p&gt;
&lt;p&gt;移行手順は以下のとおりです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Cloudflare DashboardのWorkers &amp;amp; Pagesから「Upload your static files」でプロジェクトを作成。後で上書きされるので適当なファイルを1つアップロードするだけでよい&lt;&#x2F;li&gt;
&lt;li&gt;既存のGitHub Actionsワークフロー（&lt;code&gt;deploy.yml&lt;&#x2F;code&gt;）を修正。Zolaのビルド部分はそのまま流用し、デプロイ先をCloudflare Workersに変更する。リポジトリに&lt;code&gt;wrangler.toml&lt;&#x2F;code&gt;を追加し、GitHub Repository SecretsにCloudflareのアカウントIDとAPIトークンを登録&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;deploy.yml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&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-string&quot;&gt; Deploy to Cloudflare Workers&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-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  push&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    branches&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-string&quot;&gt; main&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-tag z-yaml&quot;&gt;  workflow_dispatch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-entity z-name z-tag z-yaml&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  contents&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-string&quot;&gt; read&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-entity z-name z-tag z-yaml&quot;&gt;concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  group&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 z-definition z-string z-string&quot;&gt; &amp;quot;deploy&amp;quot;&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-tag z-yaml&quot;&gt;  cancel-in-progress&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-constant z-language z-boolean&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-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  deploy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    runs-on&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-string&quot;&gt; ubuntu-latest&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-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Checkout&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-tag z-yaml&quot;&gt;        uses&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-string&quot;&gt; actions&#x2F;checkout@v4&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-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          submodules&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-string&quot;&gt; recursive&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Setup Zola&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-tag z-yaml&quot;&gt;        uses&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-string&quot;&gt; taiki-e&#x2F;install-action@v2&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-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          tool&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-string&quot;&gt; zola@0.22.1&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Build&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-tag z-yaml&quot;&gt;        run&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-string&quot;&gt; zola build&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Deploy to Cloudflare&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-tag z-yaml&quot;&gt;        uses&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-string&quot;&gt; cloudflare&#x2F;wrangler-action@v3&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-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          apiToken&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-string&quot;&gt; ${{ secrets.CLOUDFLARE_API_TOKEN }}&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-tag z-yaml&quot;&gt;          accountId&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-string&quot;&gt; ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}&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-tag z-yaml&quot;&gt;          wranglerVersion&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 z-definition z-string z-string&quot;&gt; &amp;quot;4&amp;quot;&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-tag z-yaml&quot;&gt;          command&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-string&quot;&gt; deploy&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;Workersにカスタムドメイン&lt;code&gt;codedchords.dev&lt;&#x2F;code&gt;を追加。CloudflareがDNSレコードを自動設定してくれる&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Pagesを無効にする。Settings → PagesでSourceをNoneに変更するが、GitHub Actionsが選択されている状態ではNoneに変更できないため、一度Branchに切り替えてから設定する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;移転後はGoogle Search Consoleに新ドメインのプロパティを追加し、サイトマップを送信しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セキュリティヘッダーの設定&quot;&gt;セキュリティヘッダーの設定&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflare Workersの静的アセット機能は、ビルド出力に&lt;code&gt;_headers&lt;&#x2F;code&gt;ファイルを含めるとレスポンスヘッダーに自動適用します。Zolaの&lt;code&gt;static&#x2F;_headers&lt;&#x2F;code&gt;に以下を配置しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;static&#x2F;_headers&quot;&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;  X-Content-Type-Options: nosniff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  X-Frame-Options: DENY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Referrer-Policy: strict-origin-when-cross-origin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Permissions-Policy: camera=(), microphone=(), geolocation=()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CSPは見送りました。SoundCloud、YouTube、OpenStreetMap、GoatCounter、Giscus、はてなブログカードなど外部リソースが多く、許可リストの管理コストに対して静的サイトでの実益が限定的なためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;旧ドメインからの転送&quot;&gt;旧ドメインからの転送&lt;&#x2F;h2&gt;
&lt;p&gt;旧ドメインへのアクセスを新ドメインに転送する必要があります。旧ドメインのDNSはFastMailで管理しておりCloudflareへの移行は行わないため、Cloudflare Redirect Rulesは使えません。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、リダイレクト専用の静的サイトを生成する方法をとりました。Zolaで&lt;code&gt;zola build&lt;&#x2F;code&gt;すると全ページのHTMLが生成されます。aliasesによるリダイレクトページも含まれるため、以前Next.jsで運用していた時代のパスもカバーされます。この全HTMLをmeta refreshリダイレクトページに差し替えて、別リポジトリに配置し、旧ドメインでGitHub Pages配信する構成です。&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;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-entity z-name z-tag&quot;&gt;&amp;lt;!DOCTYPE&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;meta&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; charset&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 z-definition z-string z-string&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt; &#x2F;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;link&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; rel&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 z-definition z-string z-string&quot;&gt;&amp;quot;canonical&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; href&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 z-definition z-string z-string&quot;&gt;&amp;quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;（対応パス）&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt; &#x2F;&amp;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-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;meta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      http-equiv&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 z-definition z-string z-string&quot;&gt;&amp;quot;refresh&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      content&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 z-definition z-string z-string&quot;&gt;&amp;quot;0; url=https:&#x2F;&#x2F;codedchords.dev&#x2F;（対応パス）&amp;quot;&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-tag&quot;&gt;    &#x2F;&amp;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-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pythonスクリプトで、Zolaビルドからリダイレクトページの差し替え、不要ファイルの削除、CNAME配置までを一括実行しています。通常ページ367件とaliasページ226件、合計593件のリダイレクトを生成しました。aliasページはZolaが生成したmeta refreshのリダイレクト先（正規パス）を読み取り、新ドメインの正規パスに直接転送します。GitHub Actionsでデプロイを自動化しています。&lt;&#x2F;p&gt;
&lt;p&gt;この方法であれば全ページ・全パスをカバーできます。GitHub Pagesではサーバーサイドの301リダイレクトが設定できないため、meta refresh + canonicalの組み合わせが現実的な最善策です。FastMailのDNS変更も不要で、既存のCNAME&#x2F;Aレコードをそのまま利用できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;GitHub PagesからCloudflare Workersへの移転で得た知見をまとめます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare ProxyとGitHub Pagesの組み合わせでは、Let&#x27;s Encrypt証明書のHTTP-01チャレンジを妨げるリスクがある&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare PagesのCI&#x2F;CDはv2以降Zolaをサポートしていない（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;issue #3&lt;&#x2F;a&gt;は2023年からOpen）。GitHub Actions + &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt;で代替可能&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare Workersの静的アセット機能は&lt;code&gt;_headers&lt;&#x2F;code&gt;ファイルでセキュリティヘッダーを簡単に設定できる&lt;&#x2F;li&gt;
&lt;li&gt;旧ドメインからの転送は、meta refreshリダイレクトの静的サイトを生成する方法で全パスをカバーできる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;.dev&lt;&#x2F;code&gt;ドメインのHSTSプリロードに加え、Cloudflare Workers側でセキュリティヘッダーも設定できるようになり、セキュリティスキャナーの警告も解消されました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">GitHub PagesからCloudflare Workersへブログを移転した際の落とし穴と解決策を共有します。証明書更新やZolaビルド非対応など、3つのアプローチを検討した経験をまとめています。
</summary>
        </entry><entry xml:lang="en">
        <title>生成AIラッパーサービスが罠である理由</title>
        <published>2026-02-17T00:00:00+00:00</published>
        <updated>2026-02-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/why-genai-wrapper-services-are-a-trap/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/why-genai-wrapper-services-are-a-trap/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&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;why-genai-wrapper-services-are-a-trap&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;why-genai-wrapper-services-are-a-trap&amp;#x2F;cover.webp?h=371fbdd60ae3bcfb751e&quot;
  alt=&quot;Cover&quot; width=&quot;1456&quot; height=&quot;816&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;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;生成AIを業務に導入したいが、ChatGPTやClaudeを直接使わせるのはセキュリティ上不安がある。そんな企業の声に応えるかたちで、「安全に使える法人向け生成AIサービス」を謳うサービスが次々と登場しています。&lt;&#x2F;p&gt;
&lt;p&gt;身近で話題に登ったことをきっかけに調べてみた、ちばぎんコンピューターサービスが提供する「C-chatSupport」もそのひとつです。&lt;&#x2F;p&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;www.ccsnet.co.jp&amp;#x2F;service&amp;#x2F;c-chatsupport&amp;#x2F;&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;p&gt;本記事では、このサービスの公開情報をもとに技術者の視点から、この種の「ラッパーサービス」に共通する構造的な問題点を整理します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;&#x2F;strong&gt;
        &lt;p&gt;以下の分析はすべて2026年2月時点のWebサイト上の公開情報にもとづく筆者個人の見解であり、サービスの内部実装を直接検証したものではありません。実際のサービスには公開されていない機能や価格優位性がある可能性があります。導入を検討される際は、各サービス提供者の最新情報を直接ご確認ください。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;本質的に「APIラッパー」にすぎない&quot;&gt;本質的に「APIラッパー」にすぎない&lt;&#x2F;h2&gt;
&lt;p&gt;この種のサービスの実態は、OpenAIやAnthropicなどの既存LLM APIにRAG機能とWebUIを被せたものです。独自のモデルや技術的な差別化要素は見当たりません。&lt;&#x2F;p&gt;
&lt;p&gt;C-chatSupportの場合、Webサイトでは「複数の生成AIモデルが利用可能」と謳っていますが、具体的なモデル名は一切記載されていません。アーキテクチャ図、データフローの説明、API仕様、SLAといった技術情報も公開されていません。公式ブログやプロモーション動画でもRAGを「社内情報からも参照して回答させる技術」と一般的な用語説明に留まり、自社実装の独自性には触れていません。紹介されている「メール作成時間75%削減」といった効果も、ChatGPTやClaudeを直接使えば同様に得られるものです。&lt;&#x2F;p&gt;
&lt;p&gt;技術者の立場から見ると、これは独自技術がないことの裏返しと判断せざるを得ません。自社開発の技術があれば、それこそが最大の差別化ポイントであり、積極的に公開するはずです。&lt;&#x2F;p&gt;
&lt;p&gt;ChatGPT Business、Claude Team、Microsoft Copilotといった一次提供者のサービスは、利用可能なモデル、性能ベンチマーク、データの取り扱いポリシー、コンプライアンス認証などを詳細に公開しています。技術的な透明性を担保できないサービスを、あえて間に挟む合理性はありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;価格設定への疑問&quot;&gt;価格設定への疑問&lt;&#x2F;h2&gt;
&lt;p&gt;C-chatSupportの場合、月額5万円（キャンペーン価格、通常7万円）で50ユーザーまで利用可能で、さらに従量料金が別途かかります。一見すると安価に見えますが、他のサービスと50ユーザーの月額基本料金で比較してみます（海外サービスは1ドル=約150円で換算）。&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;
    xychart-beta
title &quot;50ユーザーの月額基本料金（万円）&quot;
x-axis [&quot;C-chatSupport&quot;, &quot;ChatGPT Business&quot;, &quot;Claude Team&quot;, &quot;M365 Copilot&quot;]
y-axis &quot;万円&quot; 0 --&gt; 25
bar [5, 19, 19, 23]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;C-chatSupportの基本料金は確かに最安値です。しかし、これには従量課金が含まれていません。従量料金の単価も非公開のため、実際の月額コストは利用量次第で大きく変動します。一方、他のサービスは基本的に定額制です。なお、M365 CopilotはMicrosoft 365 E3&#x2F;E5等のベースライセンスが別途必要であり、実際のコストはグラフの金額より高くなります。&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 style=&quot;text-align: center&quot;&gt;C-chatSupport&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;ChatGPT Business&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Claude Team&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;M365 Copilot&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 style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RAG&#x2F;ナレッジ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;画像生成&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;コード実行&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Office連携&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;管理コンソール&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;非公開&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SLA&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;非公開&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;99.9%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;料金体系&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;基本+従量&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;定額&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;定額&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;定額&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;基本料金だけを見ると安く映りますが、従量課金を含めたトータルコストと機能差を考慮すると、割高になる可能性が高いです。特に「従量料金が非公開」という点は、予算管理の観点からも大きなリスクです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セキュリティの訴求が誤解を招く&quot;&gt;セキュリティの訴求が誤解を招く&lt;&#x2F;h2&gt;
&lt;p&gt;この種のサービスは「情報漏洩リスク無し」「社外にデータを出さない」といったセキュリティを前面に押し出す傾向があります。しかし、複数の生成AIモデルを利用可能としている以上、バックエンドではOpenAIやAnthropic等の外部APIを呼んでいるはずです。&lt;&#x2F;p&gt;
&lt;p&gt;「学習に使わない」という点はAPI利用規約上当然のことであり、このサービス固有の強みではありません。また「社外にデータを出さない」という表現は、APIリクエスト自体が外部サーバーへの通信を伴う以上、厳密には正確ではありません。Azure OpenAI Serviceのプライベートエンドポイントなどを使っている可能性はありますが、そうした技術的な裏付けの説明がない以上、顧客に誤った安心感を与えるリスクがあります。&lt;&#x2F;p&gt;
&lt;p&gt;技術的な根拠を示さずに「安全」を訴求するサービスは、むしろ警戒すべきです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;機能の陳腐化リスク&quot;&gt;機能の陳腐化リスク&lt;&#x2F;h2&gt;
&lt;p&gt;紹介されているユースケース（議事録作成、DM作成、データ分析、マクロ生成）は、ChatGPT、Copilot、Claude等の汎用AIサービスで既にできることばかりです。&lt;&#x2F;p&gt;
&lt;p&gt;LLMの進化は非常に速く、ラッパーサービスは元のモデル提供者が同等機能をネイティブに実装した時点で価値を失います。実際、RAGについてもClaude、ChatGPT、Geminiのいずれもファイルアップロードとナレッジ検索を標準機能として提供済みです。ラッパーの「付加価値」は、モデル提供者自身がすぐに追い越してしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ベンダーロックインと発展性の懸念&quot;&gt;ベンダーロックインと発展性の懸念&lt;&#x2F;h2&gt;
&lt;p&gt;地銀グループのSIer子会社のように、AI技術が本業ではない提供元の場合、開発リソースや投資規模は限られます。LLM分野のイノベーション速度に追随し続けられるかは疑問です。&lt;&#x2F;p&gt;
&lt;p&gt;また、導入後に乗り換えたくなった場合、RAGに蓄積したナレッジデータのポータビリティも不透明です。独自フォーマットでロックインされていれば、移行コストは高くつきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;乱立するラッパーサービス&quot;&gt;乱立するラッパーサービス&lt;&#x2F;h2&gt;
&lt;p&gt;この種のラッパーサービスは市場に溢れかえっています。&lt;&#x2F;p&gt;
&lt;p&gt;AIsmileyが2025年10月に公開した「生成AIチャットボットカオスマップ」には、国内だけで140製品以上が掲載されています。デロイト トーマツ ミック経済研究所の調査によると、法人向け生成AI導入ソリューション市場は2024年度の330億円から2025年度は503億円（前年比152%）、2026年度は720億円（同143%）へと急拡大しています。この成長市場を狙って、SIerやIT企業が「法人向け生成AIチャット」を次々と投入しているのが現状です。&lt;&#x2F;p&gt;
&lt;p&gt;なぜこれほどサービスが乱立するのか。理由は単純で、参入障壁が極めて低いからです。Difyのようなオープンソースの生成AIアプリ構築プラットフォームを使えば、RAG機能付きのチャットボットをノーコード・1日で構築できます。LLMのAPIキーを設定し、社内文書をアップロードし、チャットUIを公開する。技術的にはこれだけです。つまり、140以上のサービスの大半は、同じようなOSSやクラウドサービスの上に薄いカスタマイズを加えただけの可能性が高いということです。&lt;&#x2F;p&gt;
&lt;p&gt;参入障壁の低さは、撤退障壁の低さと表裏一体です。市場の飽和で採算が合わなくなれば、サービス終了のリスクも現実的です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;組織が生成AIサービスの導入を検討する際には、「なぜChatGPT Business&#x2F;Enterprise、Claude Team、Microsoft Copilot、あるいはAmazon Bedrock上の自前構築ではなく、このサービスなのか」という問いに明確に答えられる必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;唯一の合理的な理由があるとすれば、既存の取引関係や日本語でのサポート体制といった非技術的な要素でしょう。実際には「海外サービスはよく分からないから、馴染みのベンダーに任せよう」と、技術選定に関与しない経営層の判断で導入が決まるケースも多いのが実情です。しかし、その安心感がラッパーサービスの構造的な弱点に見合うコストかどうかは、慎重に見極めるべきです。&lt;&#x2F;p&gt;
&lt;p&gt;技術的な差別化が不明確なサービスへ毎月の利用料を支払い続けるよりも、ChatGPT Business、Claude Team、Copilotの直接契約、あるいはAmazon BedrockやAzure OpenAI Serviceによる自前構築のほうが、長期的にはコスト・機能の両面で有利です。「生成AIは難しそうだから専門家に任せたい」という不安に応えるだけのサービスへ、安易に飛びつかないことが重要です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">生成AIの導入を急ぐ企業に向けた「ラッパーサービス」が増えています。既存LLMのAPIにUIを被せただけのサービスに潜む問題点を、価格・セキュリティ・将来性の観点から検証します。
</summary>
        </entry><entry xml:lang="en">
        <title>元AWS社員が読むClaude Code社内禁止騒動</title>
        <published>2026-02-15T17:00:00+09:00</published>
        <updated>2026-02-15T17:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/amazon-claude-code-restriction/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/amazon-claude-code-restriction/</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;Amazon社内でClaude_Code利用禁止に？&quot;&gt;Amazon社内でClaude Code利用禁止に？&lt;&#x2F;h2&gt;
&lt;p&gt;Business Insider 2月11日記事に、
Amazon社内のClaude Code
使用制限が行われているとの記事を見つけました。&lt;&#x2F;p&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;www.businessinsider.com&amp;#x2F;amazon-engineers-grate-against-internal-limits-claude-code-kiro-ai-2026-2&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;p&gt;Amazonが社内でClaude Codeの
プロダクションコードへの使用を制限し、
社内製AIコーディングツールKiroの利用を
推進しているというものです。
これに対して、社内フォーラムでは
約1,500人のエンジニアが
Claude Codeの正式採用を支持しています。&lt;&#x2F;p&gt;
&lt;p&gt;私は2024年夏にAWSを退職しましたが、
この記事を読んで、当時の社内の空気と
重ね合わせずにはいられませんでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;売るものを自分で使えない皮肉&quot;&gt;売るものを自分で使えない皮肉&lt;&#x2F;h2&gt;
&lt;p&gt;社内での開発に自社開発ツールの使用を
推奨するのは当然のように思いますが、
この問題で最も深刻なのは、
AWSはClaude Codeも売っているという事実です。&lt;&#x2F;p&gt;
&lt;p&gt;AWSは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;bedrock&#x2F;&quot;&gt;Amazon Bedrock&lt;&#x2F;a&gt;を通じてClaude Codeを
顧客に販売しています。
現在KiroよりもClaude Codeの方が
市場での注目度は高いので、
Solution ArchitectやProfessional Servicesは
Claude Codeの解説や導入支援を求められます。&lt;&#x2F;p&gt;
&lt;p&gt;そのため、日常の開発ツールとして
利用するのは自然な流れですが、
彼らは社内でClaude Codeをプロダクションコードに
使う正式な承認を得られていません。&lt;&#x2F;p&gt;
&lt;p&gt;Business Insider記事中のある従業員は
「自分たちが社内利用を承認していない
ツールを、なぜ顧客が信頼して
使ってくれるのか」と指摘しています。
これはもっともな疑問です。&lt;&#x2F;p&gt;
&lt;p&gt;Amazon Bedrockは当時から
社内で推進されていました。
ファインチューニングや
ガードレールなど独自の付加価値を持つ
プラットフォームですが、
多くの顧客がAmazon Bedrockに来る理由は
Claudeを使いたいからです。
ところがAmazon Bedrockという
プラットフォームを挟むことで、
社内では「自社が競合製品を販売している」
という意識が薄れているように感じます。
Claude Codeの社内利用を制限しながら
顧客にはそれを売るという矛盾が
放置されているのは、
この認識の甘さが一因ではないでしょうか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;投資家・パートナー・競合の三重構造&quot;&gt;投資家・パートナー・競合の三重構造&lt;&#x2F;h2&gt;
&lt;p&gt;この問題の根底にあるのは、
AmazonとAnthropicの関係そのものの
複雑さです。
Amazonは累計80億ドル超を出資した
Anthropicの最大の投資家であり、
その持分の評価額は
600億ドル超に達しています。
AnthropicにとってAWSは
最大のクラウドパートナーです。
AnthropicはAWSのクラウドサービスと
少なくとも100万個のTrainiumチップの
利用をコミットしています。
しかし同時に、AmazonはKiroや
Q DeveloperでAnthropicの製品と
直接競合しています。&lt;&#x2F;p&gt;
&lt;p&gt;「投資家・パートナー・競合」という
三重構造が社内ポリシーの歪みとして
表面化しているのが、
今回の記事の本質だと考えています。
Amazonとしては自社製品を推進したい。
しかし出資先の製品を社内で制限している
ことが表沙汰になれば、
パートナーシップへの影響も避けられません。&lt;&#x2F;p&gt;
&lt;p&gt;Amazonの広報は「明示的な禁止ではなく、
プロダクションコード用のツールに対して
厳格な要件を適用している」と
コメントしています。
しかし社内で1,500人もの
エンジニアがClaude Codeの
正式採用を求めている状況を見ると、
現場はこの説明に
納得していないことが明らかです。&lt;&#x2F;p&gt;
&lt;p&gt;さらに気になるのは透明性の問題です。
一度はClaude Codeがセキュリティおよび
法務レビューを通過したという
社内ガイドラインが存在したにもかかわらず、
その記述が後から編集・削除されたと
記事は指摘しています。
判断の根拠を示さずに方針を変えれば、
不信感が深まるのは当然です。&lt;&#x2F;p&gt;
&lt;p&gt;開発者の生産性に直結する
ツールの選択を政治的な理由で制限することは、
短期的には自社製品の利用数に
つながるかもしれません。
しかし長期的にはエンジニアの信頼を損ない、
優秀な人材が流出する原因になりかねません。
Amazonの広報は
「Kiroのエンジニアの70%が1月に
少なくとも一度は利用した」と言っていますが、
「少なくとも一度」という表現が
すべてを物語っています。
AWSの開発ツール戦略がこの矛盾を
どう解消していくのか、
元社員として注目しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;社内で見た開発ツール戦略の軌跡&quot;&gt;社内で見た開発ツール戦略の軌跡&lt;&#x2F;h2&gt;
&lt;p&gt;私の退職した2024年当時は、AWS CodeCommitとCloud9の
整理が進行中でした。
社内ではCodeWhisperer
（後にAmazon Q Developerへ統合）が
強く推奨されていました。&lt;&#x2F;p&gt;
&lt;p&gt;AWSの開発ツールはサービスの新設と廃止を
繰り返してきた歴史があり、
「次もまた消えるのでは」という不安は
エンジニアの間で常につきまとっていました。
当時、顧客への説明で困ったものです。
私自身も開発ツール戦略に関しては
懐疑的でした。&lt;&#x2F;p&gt;
&lt;p&gt;Kiroは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sixfivemedia.com&#x2F;content&#x2F;from-prompt-to-production-ai-spec-driven-development-with-kiro---six-five-on-the-road&quot;&gt;re:Inventでのインタビュー&lt;&#x2F;a&gt;によると、
チーム発足時にPR FAQ
（Amazonのプロダクト企画文書）を書いて
2024年末から具体化し、
2025年7月にパブリックプレビューとなっています。
私の退職後に本格化したため、
直接触れていません。
VS Codeのフォークと聞いていますが、
仮に在籍中に推奨されていたとしても
使わなかった可能性が高いです。&lt;&#x2F;p&gt;
&lt;p&gt;Kiroが掲げる「spec-driven development」
というコンセプト自体は理解できます。
私自身、Claude Codeで仕様ファイルを
ベースにした開発を日常的にやっています。
ただし、Claude Codeの自由度と比べると、
AIをツールに組み込む方式には
根本的な限界があります。
Claude Codeはターミナルから
あらゆる操作ができるエージェントであり、
開発者のワークフロー全体に介入できます。
一方、KiroのようにIDEにAIを組み込む方式は、
そのIDEが想定した枠組みの中でしか
能力を発揮できません。
この差は使い込むほど大きくなります。
社内で反発が出るのは当然のことです。&lt;&#x2F;p&gt;
&lt;p&gt;同記事中で、あるAmazonのエンジニアは
こう書いています。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A tool that can&#x27;t keep pace with rivals
offers no real innovation.
And without competitive strength,
Kiro&#x27;s only survival mechanism becomes
forced adoption rather than genuine value.
（競合についていけないツールから
本当のイノベーションは生まれない。
競争力がなければ、Kiroの唯一の生存戦略は
真の価値ではなく強制採用になる）&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;CodeCommitやCloud9がたどった道を
見てきた身としては、
この指摘はまさに的を射ています。&lt;&#x2F;p&gt;
</content>
        <summary type="html">AmazonがClaude Codeの社内利用を制限し
Kiroの使用を推進する中、
約1,500人のエンジニアが反発しています。
2024年夏にAWSを退職した元社員の視点から、
開発ツール戦略の歴史と
Amazon-Anthropicの三重構造が
生み出す矛盾を考察します。
</summary>
        </entry><entry xml:lang="en">
        <title>中小規模組織向け生成AIガイドラインサンプル</title>
        <published>2026-02-15T11:38:57+09:00</published>
        <updated>2026-02-15T11:38:57+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/genai-guideline-sample/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/genai-guideline-sample/</id>
        
            <content type="html">&lt;!-- image --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;genai-guideline-sample&amp;#x2F;cover.webp?h=b5847dab37b3cf9136f1&quot;
  alt=&quot;cover&quot; width=&quot;1358&quot; height=&quot;761&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;以前公開した
&lt;a href=&quot;&#x2F;blog&#x2F;2026&#x2F;01&#x2F;genai-governance-checklist-release&#x2F;&quot;&gt;生成AIガイドラインチェックリスト&lt;&#x2F;a&gt;
に基づき、具体例として参考にできる
サンプルガイドラインを作成し追加した&lt;&#x2F;li&gt;
&lt;li&gt;IT専門部署のない中小規模組織を想定した
&lt;strong&gt;大事故を防ぐ最低限を身の丈に合わせて
整えた60点ガイドライン&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&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;genai-governance-checklist&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;なぜサンプルを作ったのか&quot;&gt;なぜサンプルを作ったのか&lt;&#x2F;h2&gt;
&lt;p&gt;チェックリスト公開後、
「チェック項目の意図はわかったが、
具体的な書き方がわからないので実物を見せてほしい」
という声を多くいただきました。&lt;&#x2F;p&gt;
&lt;p&gt;チェックリストは
「何を書くべきか」を示すものですが、
「どう書くか」は組織の規模・業種・
リスク許容度によって大きく異なります。
前提が異なる例を見て意味があるのかという
疑問は大いにありますが、
「サンプルを見せて」というセリフは確かによく聞きます。
そこで特定の組織像を明確に設定したうえで、
そのまま実例として参照できるレベルの
サンプルガイドラインを作成しました。&lt;&#x2F;p&gt;
&lt;p&gt;前提がリテラシー・ガバナンスの低い組織なので、
完璧な例を作成しても実行不能でしょう。
当サンプルガイドラインは、
大事故を防ぐ最低限を
身の丈に合わせて整えた
60点を目指しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件&quot;&gt;前提条件&lt;&#x2F;h2&gt;
&lt;p&gt;このサンプルには明確な前提条件があります。&lt;&#x2F;p&gt;
&lt;p&gt;想定する組織は、
専門のIT部門を持たない中小規模の組織です。
&lt;code&gt;organization-profile.md&lt;&#x2F;code&gt; に記載した通り、
一般社団法人を想定しています。&lt;&#x2F;p&gt;
&lt;p&gt;こういった組織では独自に
生成AIを組み込んだシステムを
構築しづらいと考えます。
したがって、理事長などが無邪気に
「なんか生成AIいいらしいから、
ChatGPTを導入しよう」
みたいな担当者にとっては
地獄のようなシーンを想定しています。&lt;&#x2F;p&gt;
&lt;p&gt;こうした組織ではガイドラインを
まじめに一から作ることは稀で、
どこかから持ってきたものを
そのまま使う傾向があります。
だからこそ具体例として参考にできる水準の
サンプルを提供しています。&lt;&#x2F;p&gt;
&lt;p&gt;自組織への適用を検討する際は、
以下の前提が合致するかを
必ず確認してください。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ChatGPT Team、Claude、Geminiなど
組織向け有料プランを利用する。
無料・個人プランは対象外&lt;&#x2F;li&gt;
&lt;li&gt;自社システムやSaaSに組み込まれるような
生成AIは想定していない&lt;&#x2F;li&gt;
&lt;li&gt;セキュリティやシステム管理の規定が
存在しないか、実効性がない&lt;&#x2F;li&gt;
&lt;li&gt;リテラシーが低く、かなり一般的なレベルから説明が必要&lt;&#x2F;li&gt;
&lt;li&gt;AI専任の管理者は置けず、
総務担当者などが兼務する運用体制&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;サンプルガイドラインの概要&quot;&gt;サンプルガイドラインの概要&lt;&#x2F;h2&gt;
&lt;p&gt;リポジトリの &lt;code&gt;docs&#x2F;guideline-sample&#x2F;&lt;&#x2F;code&gt; には
サンプル本文だけでなく、
その背景となる文書も一式公開しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;organization-profile.md&lt;&#x2F;code&gt; —
想定組織の規模、業種、体制、
現在のAI利用状況、懸念事項を定義した
組織プロファイル&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;requirements-for-guideline.md&lt;&#x2F;code&gt; —
対象読者、文書設計の方針、
チェックリストとの対応方針を記載した
ガイドライン要件&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;guideline-sample.md&lt;&#x2F;code&gt; —
全10章構成のサンプルガイドライン本文&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;guideline-sample.html&lt;&#x2F;code&gt; —
pandocで変換済みのHTML版&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Makefile&lt;&#x2F;code&gt; —
MarkdownからHTMLへの変換スクリプト。
pandocがあれば &lt;code&gt;make&lt;&#x2F;code&gt; で再生成できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;「なぜこの内容になったのか」を
追跡できるようにすることで、
自組織向けにカスタマイズする際の
判断材料にしていただくことが狙いです。&lt;&#x2F;p&gt;
&lt;p&gt;サンプルはチェックリストの
必須74項目と推奨19項目、
合計93項目をカバーしています。
全10章の構成は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;組織体制と役割&lt;&#x2F;li&gt;
&lt;li&gt;利用が許可されるAIサービス&lt;&#x2F;li&gt;
&lt;li&gt;利用が許可される範囲&lt;&#x2F;li&gt;
&lt;li&gt;データ入力の制限&lt;&#x2F;li&gt;
&lt;li&gt;AI出力の利用上の注意&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;li&gt;違反時の対応&lt;&#x2F;li&gt;
&lt;li&gt;ガイドラインの運用&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;特に第4章「データ入力の制限」では、
個人情報・機密情報・顧客情報・
認証情報・財務情報・人事情報・
法的保護情報の7分類について
具体例とともに禁止事項を定めています。
また匿名化の手順も示しており、
「何がダメで、どうすればいいのか」を
非エンジニアにも伝わるように記述しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;カスタマイズのポイント&quot;&gt;カスタマイズのポイント&lt;&#x2F;h2&gt;
&lt;p&gt;サンプルをそのまま使うのではなく、
自組織の状況に合わせた調整を推奨します。&lt;&#x2F;p&gt;
&lt;p&gt;許可するAIサービスの種類、
禁止情報の分類と具体例、
インシデント時の報告先と連絡体制は
最低限見直してください。
業種固有の規制がある場合
（医療、金融、教育など）は、
該当する法令への対応を追加する
必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;リポジトリの組織プロファイルと
要件定義を自組織版に書き換えるところから
始めることをお勧めします。
前提を整理すれば、
ガイドライン本文の修正ポイントが
自ずと明確になります。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&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;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;正直に書きます。&lt;&#x2F;p&gt;
&lt;p&gt;チェックリストを公開後、
「ガイドラインのサンプルがあれば」と言われました。
そこで組織プロファイルから要件定義まで
丁寧に文書化し、93項目をカバーした
サンプルガイドラインを提供しました。
HTML版や変換スクリプトまで付けました。&lt;&#x2F;p&gt;
&lt;p&gt;結果どうなったか。
結局、サンプル活用の労力すら惜しんで
まともな検討もなく、出来合いの他組織の
ガイドラインをコピーしたものが採用されました。&lt;&#x2F;p&gt;
&lt;p&gt;そもそもの発端を振り返れば、
組織としてAIで何を実現したいかという
ビジョンがあったわけではありません。
組織トップの「なんか生成AIいいらしいから
導入しよう」という思いつきです。
導入によって何を実現したいのかが
不明確なまま、具体的な計画もなく
号令だけが降ってくる。
よくある話ですが、
そんな動機で降ってきた仕事に
担当者がやる気を出せないのは
むしろ当然でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;それでもこのサンプルを公開するのは、
同じような状況で困っている担当者が
他にもいると確信しているからです。
組織のトップが思いつきで
「生成AIのガイドライン作って」と
言い出すシーンは、
いまこの瞬間も日本中で
起きているはずです。&lt;&#x2F;p&gt;
&lt;p&gt;チェックリストとサンプルを
組み合わせて使っていただければ、
少なくとも60点のガイドラインは
作れます。
60点で始めて、
運用しながら改善していく。
完璧を待つより、
はるかに良い選択だと考えています。&lt;&#x2F;p&gt;
</content>
        <summary type="html">「具体的なガイドラインの例が欲しい」という声に
応えて、60点の生成AIガイドラインサンプルを
公開しました。IT専門部署のない中小規模組織を
想定し、チェックリストの93項目をカバーしています。
</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>ZolaブログにOGP画像自動生成を組み込んだ</title>
        <published>2026-02-10T00:00:00+00:00</published>
        <updated>2026-02-10T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/ogp-image-generation/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/ogp-image-generation/</id>
        
            <content type="html">&lt;p&gt;このブログは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt;と&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;welpo&#x2F;tabi&quot;&gt;tabi&lt;&#x2F;a&gt;テーマで運用しています。
&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;01&#x2F;blog-to-zola-aws-cleanup&#x2F;&quot;&gt;Next.jsから移行して&lt;&#x2F;a&gt;10日ほど経ち、
基本的な運用は安定してきましたが、
OGP画像が未対応のままでした。
SNSでリンクを共有したときに
表示される画像がないのは寂しいものです。
対応の顛末を記録します。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;OGP画像がなぜ必要か&quot;&gt;OGP画像がなぜ必要か&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ogp.me&#x2F;&quot;&gt;OGP（Open Graph Protocol）&lt;&#x2F;a&gt;は、
URLを共有した際にタイトルや説明文、
画像をプレビュー表示するための仕組みです。
BlueskyやSlack、LINEなど、
いまやほとんどのサービスが対応しています。&lt;&#x2F;p&gt;
&lt;p&gt;OGP画像が未設定の場合、
リンクはテキストだけの素っ気ない表示になるか、
サイト共通のデフォルト画像が使われます。
このブログでは後者の状態でした。
どの記事を共有しても同じ画像が出るので、
タイムラインで見かけても
何の記事か判別できません。&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;02&amp;#x2F;ogp-image-generation&amp;#x2F;before.webp?h=31ab83f0940f69a0288b&quot;
  alt=&quot;対応前：すべての記事で同じ画像&quot; width=&quot;531&quot; height=&quot;377&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;記事ごとにタイトル入りの画像を用意すれば、
共有リンクだけで内容が伝わります。&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;02&amp;#x2F;ogp-image-generation&amp;#x2F;after.webp?h=61caf7e3efb4f885ee01&quot;
  alt=&quot;対応後：記事タイトル入りのOGP画像&quot; width=&quot;522&quot; height=&quot;392&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;Zola_+_tabiテーマでのOGP画像の扱い&quot;&gt;Zola + tabiテーマでのOGP画像の扱い&lt;&#x2F;h2&gt;
&lt;p&gt;Zolaの画像処理機能は &lt;code&gt;resize_image()&lt;&#x2F;code&gt; による
リサイズ、クロップ、フォーマット変換に
限られます。
テキストを画像に描画する機能はなく、
OGP画像の自動生成は備わっていません。&lt;&#x2F;p&gt;
&lt;p&gt;tabiテーマ側には
&lt;code&gt;social_media_images.html&lt;&#x2F;code&gt; という
テンプレートがあり、frontmatterの
&lt;code&gt;[extra] social_media_card&lt;&#x2F;code&gt; で
指定された画像パスから &lt;code&gt;og:image&lt;&#x2F;code&gt; 等の
メタタグを出力します。
ただし画像ファイルへの参照を担うだけで、
画像そのものは生成しません。
ファイルは事前に用意しておく必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;tabiの作者であるwelpo氏も、
自身のブログ
（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;osc.garden&#x2F;blog&#x2F;automating-social-media-cards-zola&#x2F;&quot;&gt;osc.garden&lt;&#x2F;a&gt;）
でこの課題に取り組んでいます。
氏のアプローチは &lt;code&gt;shot-scraper&lt;&#x2F;code&gt; で
ページのスクリーンショットを撮影し、
OGP画像にするというものです。
ページの見た目がそのまま
プレビューになるため、
デザインの一貫性は高いです。
一方で、Zolaの開発サーバーを起動した上で
スクリーンショットを撮る必要があり、
ビルドプロセスが複雑になります。&lt;&#x2F;p&gt;
&lt;p&gt;このブログでも独自の対応が必要でした。
スクリーンショット方式はビルドの複雑さから
見送り、別のアプローチを探ることにしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;選んだアプローチ&quot;&gt;選んだアプローチ&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;OGP画像生成方式&quot;&gt;OGP画像生成方式&lt;&#x2F;h3&gt;
&lt;p&gt;OGP画像の生成方式には、大きく2つの方向があります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Zenn.devのような固定フレーム画像に記事タイトルを合成する方式&lt;&#x2F;li&gt;
&lt;li&gt;各記事のカバー画像に記事タイトルを合成する方式&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;フレーム方式はすべての記事で統一感が出ますが、
記事ごとの個性は薄くなります。
カバー画像方式は記事の内容が視覚的に伝わる
反面、画像のない記事には対応できません。&lt;&#x2F;p&gt;
&lt;p&gt;このブログには既存記事が200近くあり、
写真やスクリーンショットを含む記事と、
テキストだけの記事が混在しています。
どちらか一方の方式では、
必ずカバーできない記事が出てきます。&lt;&#x2F;p&gt;
&lt;p&gt;そこで両者のハイブリッド方式を採りました。
記事フォルダにOGPの背景として十分なサイズの
画像があればそれを使い、
なければサイト共通のデフォルト画像を使い、記事タイトルを合成する&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;scripts&#x2F;generate-ogp.mjs&quot;&gt;一括生成スクリプト&lt;&#x2F;a&gt;を作成しました。
カバー画像のある記事は記事固有の見た目になり、
画像がない記事もブログとしての統一感を保てます。
どの記事に画像があるかを人が判断する必要もなく、
スクリプトがサイズを見て自動で振り分けます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;OGP画像配置戦略&quot;&gt;OGP画像配置戦略&lt;&#x2F;h3&gt;
&lt;p&gt;Zolaでは記事と同じフォルダに画像を
配置できます。
そこで、OGP画像は &lt;code&gt;ogp.webp&lt;&#x2F;code&gt; という固定のファイル名で
記事フォルダに出力することとしました。&lt;&#x2F;p&gt;
&lt;p&gt;こうすることで、各記事のfrontmatterからは常に同じ相対パスでOGP画像を参照できます。&lt;&#x2F;p&gt;
&lt;p&gt;既存記事については、同じfrontmatterを追加するだけで対応できます。
frontmatterに機械的に &lt;code&gt;social_media_card = &quot;ogp.webp&quot;&lt;&#x2F;code&gt; を
追加する&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;scripts&#x2F;add-ogp-frontmatter.mjs&quot;&gt;スクリプト&lt;&#x2F;a&gt;を作成して一括で対応しました。&lt;&#x2F;p&gt;
&lt;p&gt;新規記事についてはNeovimのテンプレート機能で
frontmatterに &lt;code&gt;social_media_card = &quot;ogp.webp&quot;&lt;&#x2F;code&gt;
を最初から埋め込んでおくことで対応できてしまいます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;運用について&quot;&gt;運用について&lt;&#x2F;h3&gt;
&lt;p&gt;今後の運用でも、今回作成した&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;scripts&#x2F;generate-ogp.mjs&quot;&gt;一括生成スクリプト&lt;&#x2F;a&gt;を活用します。&lt;&#x2F;p&gt;
&lt;p&gt;このスクリプトは、既にOGP画像がある記事はスキップするため、
新しい記事を書いたらこのスクリプトを実行するだけで新規記事の分だけOGP画像を生成してくれます。
そして記事のテンプレートにもうすでにOGP画像の指定がfrontmatterとして設定されています。&lt;&#x2F;p&gt;
&lt;p&gt;もちろん、今後ベースとなったフレーム画像が気にくわなければ各記事フォルダの&lt;code&gt;ogp.webp&lt;&#x2F;code&gt;を削除すれば再作成されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;導入してみて&quot;&gt;導入してみて&lt;&#x2F;h2&gt;
&lt;p&gt;200記事すべてにOGP画像が生成され、
SNS共有時の見栄えが改善されました。&lt;&#x2F;p&gt;
&lt;p&gt;今回は過度に自動化せず、
新規記事については毎回手動で
OGP画像生成スクリプトを実行する
運用にしています。
&lt;code&gt;zola serve&lt;&#x2F;code&gt; でプレビューを確認する際、
OGP画像がないとエラーになるのが
微妙にストレスなので、
いずれビルドプロセスへの組み込みも
検討したいところです。&lt;&#x2F;p&gt;
&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;実装の技術的な詳細は
Zennに投稿しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;zola-ogp-auto-generation&quot;&gt;Zola + tabiテーマでOGP画像を自動生成する
（Zenn）&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">静的サイトジェネレーターZolaとtabiテーマの組み合わせで
運用しているこのブログに、OGP画像の自動生成を導入しました。
Zolaに組み込みの仕組みがない中でどう対応したか、
検討から導入までの経緯を記録します。
</summary>
        </entry><entry xml:lang="en">
        <title>生成AI時代、重力に魂を引かれるな</title>
        <published>2026-02-09T12:30:00+09:00</published>
        <updated>2026-02-09T12:30:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/ai-human-divergence/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/ai-human-divergence/</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;02&amp;#x2F;ai-human-divergence&amp;#x2F;cover.webp?h=47e368ab0f46eda916c2&quot;
  alt=&quot;Cover&quot; width=&quot;1800&quot; height=&quot;1009&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;革新的な技術が目の前にあり、誰でも試せる状況になったとき、
実際に試す人はどれくらいいるでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;この1年、生成AI、Markdown、テキストエディタの活用など生産性の
上げるための多くのものを紹介しても、何ひとつ試そうともしない人を目の当たりにしてきました。&lt;&#x2F;p&gt;
&lt;p&gt;この1年に限らずこれまでの私の観測では、どの現場でも新技術を2割が試し、4割は「いつか試そう」と思いながら試さず、
残りの4割は試そうともしません。
これは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;3Zp2HiL&quot;&gt;Everett Rogersのイノベーション普及理論&lt;&#x2F;a&gt; &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;興味深いのは、この比率が技術の難易度とほぼ無関係なことです。
生成AIのような革新的技術だけでなく、Markdownのような
学習コスト30分、チートシート1枚で済むツールでも同じだということです。&lt;&#x2F;p&gt;
&lt;p&gt;これはもはや能力の問題ではありません。
新しいことを取り入れる意志の問題です。
腰が重い、というより、重力に魂を引かれているのかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;そしてこの2割と8割の差は、生成AIの時代において
&lt;strong&gt;決定的な分断&lt;&#x2F;strong&gt;へと発展しようとしています。
以降、この2割を「先行者」、8割を「追随者」と呼ぶことにします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2つの革新&quot;&gt;2つの革新&lt;&#x2F;h2&gt;
&lt;p&gt;生成AIも同様です。
本格的に活用し、自身の生活や業務へ取り入れているのは2割程度でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;従来の技術革新と今回の「生成AI」が決定的に異なるのは、
もたらす変化が大きく2つに分けられることです。&lt;&#x2F;p&gt;
&lt;p&gt;1つ目は「&lt;strong&gt;実行力の民主化&lt;&#x2F;strong&gt;」です。
思考から実行し実現するまでの摩擦がほぼゼロになりました。
アイデアさえあれば、コード、文章、分析、デザイン、
それを形にするまでの障壁がなくなりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;2つ目は「&lt;strong&gt;認知の拡張&lt;&#x2F;strong&gt;」です。
自分一人の脳では到達できない思考の深さと広さを得られるようになりました。
これは生成AIの認知力が高いということではありません。
生成AIを壁打ち相手、批判者、専門家、編集者として常に隣に置くことで、
自身の物事の捉え方や解決への発想、新たな着想力が
これまでとは比べ物にならないくらい速く柔軟に拡がります。
そう感じた方は多いはずです。
これは単なるツールではなく、認知そのものの拡張です。&lt;&#x2F;p&gt;
&lt;p&gt;先行者と追随者の間の前者のギャップは時間が解決します。
生成AIがさまざまなツールに組み込まれれば、
追随者もそのメリットを享受できるようになるでしょう。
Gmailの文章補完、Excelの自動分析、Canvaのデザイン提案。
これらは「使う」意志がなくても、自然に恩恵を受けられます。&lt;&#x2F;p&gt;
&lt;p&gt;問題は後者です。認知の拡張は、能動的に求めなければ得られません。
そして、いち早く生成AIを活用している先行者は、
今この瞬間も認知を拡張し続けています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AI時代の分断&quot;&gt;AI時代の分断&lt;&#x2F;h2&gt;
&lt;p&gt;ここで&lt;strong&gt;決定的な分岐&lt;&#x2F;strong&gt;が生まれます。&lt;&#x2F;p&gt;
&lt;p&gt;追随者はメーカーがAIで便利にした製品を使います。
便利にはなります。
しかし、製品が想定した範囲内でしか動けません。
誰かが設計した体験の中にいます。&lt;&#x2F;p&gt;
&lt;p&gt;先行者はAIそのものを使います。
そして時代はエージェント型AI、
現実世界の道具を使えるAIの時代になりました。
何をさせるか、どう組み合わせるかをAIに指示し、
道具に縛られずAIで生産性を上げ、
さらに認知力の拡張を続けることができます。&lt;&#x2F;p&gt;
&lt;p&gt;前者は消費者、後者は設計者です。&lt;&#x2F;p&gt;
&lt;p&gt;エンジニアの世界では、既にこの分断が始まっています。&lt;&#x2F;p&gt;
&lt;p&gt;昨年まではGitHub Copilotのように
エディタやIDEにAIを組み込んだものがもてはやされてきました。
しかしClaude Codeの登場で状況が変わりました。
エディタに組み込まれていなくても、
Claude Code自身がツールを操り開発を進められるようになったのです。
エンジニアは自身のコーディングの支援だけでなく、
テスト、設計、要件定義、構想策定まで
Claude Codeと協業しながら生成AIの適用範囲を広げていけます。
単純な作業を任せるだけでなく、
これまで実現コストで躊躇していた新しいアイデアへ
どんどん挑戦できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;非エンジニアの世界でも同じことが起きようとしています。
これまではExcelやWordにAIが組み込まれるのを歓迎していました。
しかしClaude Coworkが普及すれば、そんなことは関係なくなります。
好きなツールをCoworkから使いこなして業務ができるようになります。
事実、Claude Coworkの発表後、SaaSプロバイダーの株価は軒並み暴落しました。
市場はこの変化の意味を理解しています。&lt;&#x2F;p&gt;
&lt;p&gt;設計者になるか、消費者のままでいるか。その選択が迫られています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;量から質への転化&quot;&gt;量から質への転化&lt;&#x2F;h2&gt;
&lt;p&gt;もう1つ、見過ごせない力学があります。
「量をこなせば、質が向上する」という量質変換&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;があります。
ここで重要なのは、生成AIというツールの使いこなしではなく、
&lt;strong&gt;認知の拡張それ自体に量質変換が起きる&lt;&#x2F;strong&gt;ということです。&lt;&#x2F;p&gt;
&lt;p&gt;先行者は、生成AIと対話を重ねるたびに、
自分一人では到達できなかった思考領域に踏み込んでいます。
新しい視点を得れば、それを足がかりにさらに深い問いが立てられます。
深い問いに向き合えば、さらに広い視野が開けます。&lt;&#x2F;p&gt;
&lt;p&gt;これは単なるツールの習熟ではありません。
認知の拡張が認知の拡張を呼ぶ、爆発的な正のフィードバックです。&lt;&#x2F;p&gt;
&lt;p&gt;一度この拡張を経験すると、思考の出発点そのものが変わります。
昨日の自分には見えなかった問いが見えるようになり、
先月の自分には発想できなかった解決策が浮かぶようになります。
認知が広がれば、発想の幅も加速度的に広がります。
これが毎日、毎週、積み重なっていきます。&lt;&#x2F;p&gt;
&lt;p&gt;一方、追随者は最初の一歩を踏み出していません。
認知の拡張がなければ、量質変換も起きません。
差は線形ではなく、指数関数的に開いていきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;認知様式の分断&quot;&gt;認知様式の分断&lt;&#x2F;h2&gt;
&lt;p&gt;さらに深刻なのは、先行者と追随者の間で
コミュニケーションそのものが困難になっていくことです。&lt;&#x2F;p&gt;
&lt;p&gt;認知が拡張された者同士は、同じ地平に立って議論できます。
問題の捉え方、解決策の発想、思考の前提が揃っているからです。
言葉を尽くさなくても、互いの思考の輪郭が見えます。&lt;&#x2F;p&gt;
&lt;p&gt;一方、追随者との間では、まず見えている世界が違います。
先行者にとって当たり前の発想が、追随者には飛躍に見えます。
説明しようとしても、その説明を理解するための前提が共有されていません。&lt;&#x2F;p&gt;
&lt;p&gt;これは専門用語の問題ではありません。
認知の枠組みそのものが異なっているのです。&lt;&#x2F;p&gt;
&lt;p&gt;私たちは今、そうした分岐の入り口に立っているのかもしれません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;私たちはどこへ向かうのか&quot;&gt;私たちはどこへ向かうのか&lt;&#x2F;h2&gt;
&lt;p&gt;先行者の認知は、日々拡張し続けています。
見える世界が広がり、立てられる問いが深まり、
発想の幅が際限なく広がっていきます。&lt;&#x2F;p&gt;
&lt;p&gt;追随者は、その変化に気づいていません。
気づかないまま、同じ枠組みの中で思考し続けます。
1年後、2年後、認知の差はどこまで開くでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;追随者が「置いていかれる」というより、
自ら「留まることを選んでいる」という方が正確かもしれません。
それが意識的な選択かどうかは問いません。&lt;&#x2F;p&gt;
&lt;p&gt;私たちは今、認知が分岐していく入り口に立っています。&lt;&#x2F;p&gt;
&lt;p&gt;あなたはどちら側にいますか。
そして、そこにいることを選んでいますか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;私たちの世代だと、これはどこかで見た構図です。&lt;&#x2F;p&gt;
&lt;p&gt;1979年のテレビアニメ『機動戦士ガンダム』では、
人類の宇宙進出という革新への適応として「ニュータイプ&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;」が生まれ、
「重力に魂を引かれた」オールドタイプとの分断が描かれていました。
現代における重力とは、慣れ親しんだツールや思考様式への執着かもしれません。
しかし、最終回では特殊なモビルスーツのパイロットである主人公のみならず同じ部隊のクルーが覚醒していく様が描かれています。&lt;&#x2F;p&gt;
&lt;p&gt;現代の革新についても、現状は追随者の側にいるとしてもそれは能力の問題ではありません。&lt;&#x2F;p&gt;
&lt;p&gt;先行者への最初の一歩は難しくありません。
Markdownを30分勉強し、Claude Proを使い始めましょう。&lt;&#x2F;p&gt;
&lt;p&gt;答えを求めるのではなく、壁打ち相手として問いを投げてみる。
それだけで、認知の拡張は動き始めます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;なぜClaudeなのか&lt;&#x2F;strong&gt;
        &lt;p&gt;私がClaudeを例に挙げているのは、2026年2月時点で
非エンジニア向けのエージェント機能（Cowork）を
提供しているのがAnthropicだけだからです。
認知の拡張を始めるなら、ChatGPTでもGeminiでも構いません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&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;イノベーション普及理論は、新しい技術やサービスが市場に広がる過程を、消費者の採用タイミングに基づいて5つのタイプに分類し分析するマーケティング理論。1962年に提唱された。 5つのタイプとは、(1).イノベーター (革新者：2.5%)：最先端技術を好み、新しいものを進んで採用する。(2).アーリーアダプター (初期採用者：13.5%)：流行に敏感で、周囲に影響を与えるオピニオンリーダー。(3).アーリーマジョリティ (前期追随者：34%)：慎重派だが、新しいものを平均より早く採用する。
(4).レイトマジョリティ (後期追随者：34%)：懐疑的で、周囲の大半が使用して初めて採用する。(5).ラガード (遅滞層：16%)：最も保守的で、流行に関心が薄い。 &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;量質転化の法則。ヘーゲルの『小論理学』に由来する概念で、現代では一定の量を積み重ねることで臨界点に達し、能力や理解が劇的に向上するという原則として広く語られている。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;広大な宇宙空間への適合の結果、ニュータイプは空間を超えた非言語的コミュニケーション能力、超人的な感覚力と直感力、観察力と洞察力を持つ新しい人類として描かれています。 &lt;a href=&quot;#fr-3-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">生成AIは人類の分岐点となる革新です。
しかし8割の人は新しいものを試そうとしません。
慣れ親しんだやり方に留まり、一歩を踏み出せない。
それはまさに「重力に魂を引かれた」状態ではないでしょうか。
</summary>
        </entry><entry xml:lang="en">
        <title>Claude Opus 4.6発表</title>
        <published>2026-02-06T00:00:00+00:00</published>
        <updated>2026-02-06T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/claude-opus46/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/claude-opus46/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;youtube-container&quot; style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;dPn3GBI8lII&quot;
    style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&quot;
    frameborder=&quot;0&quot;
    allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&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;p&gt;本日、AnthropicからClaude Opus 4.6が発表されました。
私は普段から個人開発と業務の両方でClaude Codeを使っているので、
今回の発表は非常に楽しみにしていました。
主な新機能と、私にとって何が嬉しいのかをまとめます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;コーディング能力の大幅強化&quot;&gt;コーディング能力の大幅強化&lt;&#x2F;h2&gt;
&lt;p&gt;コーディング能力が大幅に強化されました。
Terminal-Bench 2.0やHumanity&#x27;s Last Examで業界最高スコアを達成しています。&lt;&#x2F;p&gt;
&lt;p&gt;私がこれまで感じていた課題の1つは、
複雑なタスクで途中から方針がブレることでした。
今回のアップデートでは「より慎重な計画を立て、
自分のミスを見つける力が向上した」とのことなので、
長めの開発セッションでも安心して任せられそうです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;100万トークンのコンテキスト対応&quot;&gt;100万トークンのコンテキスト対応&lt;&#x2F;h2&gt;
&lt;p&gt;Opus系で初めて100万トークンのコンテキストウィンドウに対応しました（ベータ）。
出力トークンも最大128kまで拡張されています。&lt;&#x2F;p&gt;
&lt;p&gt;大規模なコードベースを扱う際、これは大きな違いになります。
業務で触るリポジトリは規模が大きいので、
「このファイルも読んでほしいのに入りきらない」という場面が減りそうです。
MRCR v2テストでSonnet 4.5の18.5%に対してOpus 4.6は76%を記録しており、
長い文脈でも情報を見失いにくくなっているのは心強いです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Adaptive_ThinkingとEffort制御&quot;&gt;Adaptive ThinkingとEffort制御&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adaptive Thinking&lt;&#x2F;strong&gt; - 深い思考が必要かどうかをモデル自身で判断する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Effort制御&lt;&#x2F;strong&gt; - low&#x2F;medium&#x2F;high&#x2F;maxの4段階で速度・コスト・性能を調整可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以前はextended thinkingのオン&#x2F;オフしかなく、
簡単な質問でも考えすぎてしまうことがありました。
Adaptive Thinkingによってモデルが自分で判断してくれるのは嬉しい改善です。
それでも考えすぎと感じたら&lt;code&gt;&#x2F;effort medium&lt;&#x2F;code&gt;で調整できるのも実用的です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Context_Compaction&quot;&gt;Context Compaction&lt;&#x2F;h2&gt;
&lt;p&gt;長い会話やエージェントタスクで古いコンテキストを自動要約して、
コンテキストウィンドウの上限に達しにくくする仕組みです（ベータ）。&lt;&#x2F;p&gt;
&lt;p&gt;個人開発では1つのセッションで長時間作業することが多いので、
これは地味ながら大きな改善です。
これまで意図的にセッションを細かく切って、作業状態をファイルに書き出させてHandoffする仕組みを作っていました。
今回のこの機能で「会話が長くなってきたから一度リセットしよう」という手間が減りそうです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Agent_Teams&quot;&gt;Agent Teams&lt;&#x2F;h2&gt;
&lt;p&gt;複数のエージェントを並列で動かして自律的に協調させる機能です
（リサーチプレビュー）。
コードベースのレビューなど、独立した読み取り中心のタスクに向いています。&lt;&#x2F;p&gt;
&lt;p&gt;これは私が最も期待していた機能です。
以前、冗談半分で作った&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2025&#x2F;12&#x2F;magi-claude-code-plugin&#x2F;&quot;&gt;MAGIシステム&lt;&#x2F;a&gt;では、
複数のエージェントが並列でコードや文章をレビューし、
合意形成や改善点の洗い出しに重宝していました。
同様の機能がデフォルトで使えるようになるなら、
例えばコードレビューで複数のファイルを並列にチェックしたり、
リファクタリングの影響範囲を同時に調査したりできます。
Shift+Up&#x2F;Downやtmuxでサブエージェントを直接操作できるのも、
細かい制御が必要な場面で助かります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Officeツール連携&quot;&gt;Officeツール連携&lt;&#x2F;h2&gt;
&lt;p&gt;Claude in Excelが大幅に改善され、Claude in PowerPointも新たにリリースされました
（リサーチプレビュー）。&lt;&#x2F;p&gt;
&lt;p&gt;私の用途では直接関係ありませんが、
業務でExcelやPowerPointを使う方には便利そうです。
データ整理からプレゼン資料作成まで一貫してClaudeへ任せられます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;安全性&quot;&gt;安全性&lt;&#x2F;h2&gt;
&lt;p&gt;過剰な拒否（本来答えて問題ない質問を断る）の率が
過去のClaudeモデルで最も低いとのことです。&lt;&#x2F;p&gt;
&lt;p&gt;これは実用上かなり重要です。
開発中に「これは答えられません」と言われて作業が止まる、
そういったストレスが減ることを期待しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;私のファーストインプレッション&quot;&gt;私のファーストインプレッション&lt;&#x2F;h2&gt;
&lt;p&gt;少し試してみた段階ですが、確かに「考えてから動く」感覚があります。
以前のモデルはすぐにコードを書き始めることが多かったのに対し、
Opus 4.6は一度立ち止まって全体を見渡してから作業を始める印象です。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropic社内でも「タスクの難しい部分に自発的に注力し、
簡単な部分はさっと進める」という評価があるようですが、
まさにそういう挙動を感じました。&lt;&#x2F;p&gt;
&lt;p&gt;Agent Teamsについてはまだ本格的に試せていませんが、
これからの開発で積極的に使ってみようと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;パートナー企業の評価&quot;&gt;パートナー企業の評価&lt;&#x2F;h2&gt;
&lt;p&gt;特にRakutenの事例が印象的で、
「1日で13件のissueを自律クローズし、12件を適切なチームメンバーにアサインした。
約50人の組織で6つのリポジトリを横断して運用・組織判断を行い、
人間にエスカレーションすべきタイミングも判断できた」と報告されています。
これが本当なら、開発チームの働き方が大きく変わりそうです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;参考資料&quot;&gt;参考資料&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2025&#x2F;12&#x2F;magi-claude-code-plugin&#x2F;&quot;&gt;MAGIシステムをClaude Code Pluginで実装してみた&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&#x2F;blob&#x2F;main&#x2F;plugins&#x2F;magi&#x2F;README.md&quot;&gt;MAGI Plugin（GitHub）&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">Anthropicが最新モデルClaude Opus 4.6を発表しました。
コーディング能力の大幅強化、100万トークン対応、Agent Teamsなど
注目の新機能と、実際に試してみた私の所感をまとめています。
</summary>
        </entry><entry xml:lang="en">
        <title>GitHub Pagesのセキュリティヘッダー警告、無視していいの？</title>
        <published>2026-02-06T00:00:00+00:00</published>
        <updated>2026-02-06T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/github-pages-security-headers/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/github-pages-security-headers/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&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;github-pages-security-headers&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;GitHub Pagesではセキュリティヘッダーを設定する機能がなく、スキャナーの警告がでる&lt;&#x2F;li&gt;
&lt;li&gt;セキュリティスキャナーの警告は「ベストプラクティス未達」であり「脆弱性」ではない&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Pagesでは大抵静的サイトのため、放置しても実質的なリスクは低い&lt;&#x2F;li&gt;
&lt;li&gt;自前でホスティングしたWordPressなどの動的サイトは必ず対応すべき&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;セキュリティヘッダーとは何か&quot;&gt;セキュリティヘッダーとは何か&lt;&#x2F;h2&gt;
&lt;p&gt;セキュリティスキャナーでよく指摘される6つのHTTPレスポンスヘッダーがあります。&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;Strict-Transport-Security (HSTS)&lt;&#x2F;td&gt;&lt;td&gt;HTTPS接続を強制&lt;&#x2F;td&gt;&lt;td&gt;HTTPへのダウングレード攻撃&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Content-Security-Policy (CSP)&lt;&#x2F;td&gt;&lt;td&gt;XSS攻撃を防止&lt;&#x2F;td&gt;&lt;td&gt;悪意あるスクリプト実行&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;X-Frame-Options&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;X-Content-Type-Options&lt;&#x2F;td&gt;&lt;td&gt;MIMEスニッフィング防止&lt;&#x2F;td&gt;&lt;td&gt;ファイル種別の誤認識&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Referrer-Policy&lt;&#x2F;td&gt;&lt;td&gt;リファラー情報の制御&lt;&#x2F;td&gt;&lt;td&gt;URLパラメータの漏洩&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Permissions-Policy&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;これらのヘッダーは、Webサーバーがレスポンスに含めることで、
ブラウザにセキュリティ関連の指示を与えます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;GitHub_Pagesの制限&quot;&gt;GitHub Pagesの制限&lt;&#x2F;h2&gt;
&lt;p&gt;GitHub Pagesは静的サイトホスティングサービスですが、
&lt;strong&gt;HTTPレスポンスヘッダーをカスタマイズする機能がありません&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.htaccess&lt;&#x2F;code&gt; は使えない（Apache設定ファイル）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;nginx.conf&lt;&#x2F;code&gt; も使えない（Nginx設定ファイル）&lt;&#x2F;li&gt;
&lt;li&gt;GitHub側で固定されたヘッダーが返される&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;どうしてもセキュリティヘッダーを設定したい場合は、Cloudflare CDNを前段に置けばTransform Rulesでヘッダーを追加できます。
ただし、Cloudflareの無料プランはネームサーバー移管が必須です。&lt;&#x2F;p&gt;
&lt;p&gt;既存のDNSサービスを使い続けたい場合、
この方法は採用しづらいです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;静的サイトと動的サイトでリスクが違う&quot;&gt;静的サイトと動的サイトでリスクが違う&lt;&#x2F;h2&gt;
&lt;p&gt;セキュリティヘッダーの重要度は、サイトの種類によって大きく異なります。
GitHub Pagesでも動的なSPAをホストできますが、
ここではZolaやHugoなどのSSGで生成した純粋な静的サイトを想定しています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;観点&lt;&#x2F;th&gt;&lt;th&gt;静的サイト（SSG生成）&lt;&#x2F;th&gt;&lt;th&gt;動的サイト（WordPress等）&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;PHP + DB&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;wp-admin&lt;&#x2F;code&gt; 等が存在&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;XSSリスク&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;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;WordPressでセキュリティヘッダーが未設定の場合、
管理者がログイン中にクリックジャッキング攻撃を受けたり、
XSS経由でマルウェアを注入されたりするリスクがあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;判断基準：いつ対応すべきか&quot;&gt;判断基準：いつ対応すべきか&lt;&#x2F;h2&gt;
&lt;p&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
A[フォームがある？] --&gt;|Yes| B[対応すべき]
A --&gt;|No| C[サイトの性質は？]
C --&gt;|個人ブログ| D[放置OK]
C --&gt;|企業サイト| E[できれば対応]
C --&gt;|公的機関| F[対応すべき]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;フォームがあるサイトは対応が必要です。
問い合わせフォーム、会員登録、ログイン機能、寄付やEC機能があれば、
ユーザー入力を受け付けるためXSSのリスクがあります。&lt;&#x2F;p&gt;
&lt;p&gt;フォームがない場合はサイトの性質で判断します。
個人の技術ブログやポートフォリオなら放置で問題ありません。
公的機関などのサイトは、信頼性の観点から対応が望ましいです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;セキュリティスキャナーの警告を見ると焦りますが、
すべての警告に対応する必要はありません。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;重要なのはリスク評価です。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;何を守る必要があるか（資産）&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;GitHub Pagesで静的ブログを公開している場合、
セキュリティヘッダーがなくても攻撃面がほとんどありません。
「設定できないから放置」は、この場合は合理的な判断です。&lt;&#x2F;p&gt;
&lt;p&gt;一方、WordPressや動的サイトでは事情が異なります。
&lt;code&gt;.htaccess&lt;&#x2F;code&gt; やプラグインで設定できるので、対応しておくべきです。&lt;&#x2F;p&gt;
&lt;p&gt;スキャナーの警告は「ベストプラクティスに従っていない」という指摘であり、
「今すぐ危険」という意味ではありません。
コンテキストに応じた判断をしましょう。&lt;&#x2F;p&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;owasp.org&#x2F;www-project-secure-headers&#x2F;&quot;&gt;OWASP Secure Headers Project&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;orgs&#x2F;community&#x2F;discussions&#x2F;54257&quot;&gt;GitHub Community Discussion - HTTP Headers on Pages&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&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;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">このブログはZola+GitHub Pagesで実現していますが、
GitHub Pagesはセキュリティヘッダの設定ができません。
いないとは思いますが、セキュリティスキャナーなどで未設定を見つけて文句をつけてくるセキュリティ厨がいないとも限りません。
対応すべきか放置すべきかの判断基準を解説しておきます。
</summary>
        </entry><entry xml:lang="en">
        <title>なぜ塩漬けシステムからの脱却は「無理ゲー」になるのか</title>
        <published>2026-02-05T00:00:00+00:00</published>
        <updated>2026-02-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/why-stagnant-system-migration-fails/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/why-stagnant-system-migration-fails/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&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;why-stagnant-system-migration-fails&quot;&gt;Zenn.dev&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;p&gt;中小企業や自治体などIT部門が弱い組織では、10年、20年と塩漬けになった
システムからの脱却が「無理ゲー」に陥りやすい傾向があります。
ブラックボックス化・ベンダーロックイン・組織能力不足という問題が
互いに絡み合い、負のスパイラルを形成するからです。&lt;&#x2F;p&gt;
&lt;p&gt;根本原因は技術ではなく、組織的なITガバナンスの喪失にあります。
この状況からの脱出には膨大な投資と経営層の強いコミットメントが必要ですが、
そもそもこの状況に陥らないための予防が最善策です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;IT部門を持たず塩漬けになったシステムで悩む組織では、
保守の手間がかからないSaaSへの移行を検討することが多いでしょう。
しかし、SaaSであれ新規開発であれ、長年運用してきた塩漬けシステムからの刷新は、
想像以上に困難を極めます。&lt;&#x2F;p&gt;
&lt;p&gt;ITプロジェクトの失敗率は決して低くありません。
Standish GroupのCHAOS Report 2020によれば、
ITプロジェクトの約70%が当初の目標を達成できないとされています。
特に、知見をもった要員が途絶えドキュメンテーションも十分でない
システムからの移行は、その中でも最も困難なカテゴリに属します。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、筆者が見聞した複数の事例をもとに、
システム刷新が「無理ゲー」と化す構造的な問題を解説します。
これは特殊な例ではなく、多くの組織が陥りがちな普遍的なパターンです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提：この記事が想定する組織像&quot;&gt;前提：この記事が想定する組織像&lt;&#x2F;h2&gt;
&lt;p&gt;本記事で分析する「システム刷新が困難な組織」には、以下のような特徴があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CIOが不在で、組織的なIT統制がない&lt;&#x2F;li&gt;
&lt;li&gt;専任のIT部門が存在しない、または機能していない&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;ul&gt;
&lt;p&gt;このような状態は、中小企業や地方自治体、非IT企業の事業部門などで珍しくありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._システムの完全なブラックボックス化&quot;&gt;1. システムの完全なブラックボックス化&lt;&#x2F;h2&gt;
&lt;p&gt;長年の運用の中で、システムは以下のような状態に陥っています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;仕様書・設計書が存在しない、または最新でない&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;ul&gt;
&lt;p&gt;さらに深刻なのは、文書化されていない知識の存在です。
暗黙知化した業務ルールが大量のコード内へ埋め込まれており、
誰も覚えていない例外処理が実は重要な機能だったりします。
文書化されていない仕様変更の積み重ねが、現在の動作を形成しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._ベンダーロックインの完成形&quot;&gt;2. ベンダーロックインの完成形&lt;&#x2F;h2&gt;
&lt;p&gt;このような状況では、ベンダーとの力関係が完全に逆転します。
ベンダーだけがシステムの知識を持っており、組織側には検証手段がなく、
ベンダーの言い値を受け入れるしかありません。
ベンダー自身も変更時の検証で対応しているだけで、完全な仕様把握は疑問です。
これは典型的なベンダーロックインの完成形です。&lt;&#x2F;p&gt;
&lt;p&gt;現行ベンダーに移行支援を依頼することも、構造的に困難です。
唯一システムのナレッジを持っている彼らは、
現行システムの保守で継続的な収益を得ています。
システム刷新が現行ベンダー以外へのSaaS移行などの場合、
積極的に協力するインセンティブがなく、
むしろ移行は現状のビジネス機会の損失を意味します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3._システム刷新に必要な組織能力&quot;&gt;3. システム刷新に必要な組織能力&lt;&#x2F;h2&gt;
&lt;p&gt;システム刷新を成功させるには、現行システムの分析と要件定義、
業務プロセスの文書化が必要です。
また多くの場合そのような組織ではSaaS製品を検討するでしょう。
SaaSを選択したとしても、SaaS製品の選定とギャップ分析、
業務プロセス改革の設計と実行、データ移行、段階的な移行と検証、
運用体制の確立といったステップが必要です。&lt;&#x2F;p&gt;
&lt;p&gt;これらを遂行するには、以下の能力が不可欠です。
名のある大企業でも全て満たしていることは稀です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現行システムの仕様を理解し文書化する能力&lt;&#x2F;li&gt;
&lt;li&gt;業務要件を定義し、システム要件に落とし込む能力&lt;&#x2F;li&gt;
&lt;li&gt;プロジェクト全体を管理する能力&lt;&#x2F;li&gt;
&lt;li&gt;SaaSやERPを移行先とする場合は、
その製品が前提とする業務プロセスを理解するナレッジ&lt;&#x2F;li&gt;
&lt;li&gt;業務改革やプロセスリエンジニアリングを推進する能力&lt;&#x2F;li&gt;
&lt;li&gt;経営層の高いコミットメントとリーダーシップ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;4._3つの致命的なギャップ&quot;&gt;4. 3つの致命的なギャップ&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;移行の「正解」が誰にも分からない&lt;&#x2F;strong&gt; —
仕様書が古いため、現在のシステムがどう動いているか不明である。
つまり「移行後に何が実現されていればOKなのか」という基準が存在しない。&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;5._負のスパイラル&quot;&gt;5. 負のスパイラル&lt;&#x2F;h2&gt;
&lt;p&gt;塩漬け状態から脱却しようとSaaS移行を決意しても、
これらの問題が互いに絡み合い、負のスパイラルを形成します。&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 TD
A[仕様が不明] --&gt; B[要件を洗い出せない]
B --&gt; C[ベンダーは利益相反]
C --&gt; D[SaaS要件を定義できない]
D --&gt; E[SaaSを選定できない]
E --&gt; F[業務プロセス知識がない]
F --&gt; G[改革の経験・風土がない]
G --&gt; H[意思決定ができない]
H --&gt; I[移行失敗]
I -.-&gt; A
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;では新規ベンダーに依頼すればよいのでしょうか。残念ながら、それも困難です。
現行システムの仕様不明により要件定義ができず、
リバースエンジニアリングには膨大なコストがかかります。
組織側に要件定義能力がなくプロジェクトは進まず、
責任範囲も不明確でリスクを引き受けられません。
優れたSIerやコンサル会社ほど、このような案件を忌避します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;6._無理に進めた場合の予想シナリオ&quot;&gt;6. 無理に進めた場合の予想シナリオ&lt;&#x2F;h2&gt;
&lt;p&gt;仮に予算化されて、無理やりSaaS移行プロジェクトが開始されたとします。
典型的な失敗パターンは以下の通りです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;フェーズ&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;時期&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;起こること&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;経営層の認識&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;現状分析&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;1〜3ヶ月目&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;コンサルに高額費用を払うが、仕様書が古く現場も「なんとなく使っている」状態。表面的なヒアリングで不完全な要件定義書が作成され、重要な例外処理や暗黙のルールは抜け落ちる&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;「順調に進んでいる」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;SaaS選定&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;4〜8ヶ月目&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;不完全な要件定義書をもとにSaaS製品を選定。「カスタマイズすれば何とかなる」と判断するが、SaaSのカスタマイズには限界がある。データ移行計画も曖昧。予算は当初の2倍に膨張&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;「想定内の追加投資」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;移行実施&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;9〜12ヶ月目&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;全面移行を強行し現場は大混乱。「以前できたこと」ができない、例外処理の欠落が判明、過去データが参照できず業務停止。現場から「前のシステムに戻せ」の声&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;「現場の抵抗」と認識&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;破綻&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;12ヶ月目〜&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;現行システムは停止済みで戻せない。手作業やExcelで応急対応。ベンダーは「要件定義が不十分だった」と責任回避。業務効率は移行前より悪化。責任者が退職&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;責任問題に発展&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;7._唯一の対応策&quot;&gt;7. 唯一の対応策&lt;&#x2F;h2&gt;
&lt;p&gt;本気で脱出するなら、以下の対策が必要です。
これは「超ハードモード」であることを認識してください。&lt;&#x2F;p&gt;
&lt;p&gt;まず、業務プロセスリエンジニアリング能力の確保が必要です。
SaaSの前提とする業務プロセスを理解し、現行業務を可視化した上で
SaaSに適応させる能力が必須であり、
経験豊富な外部コンサルの支援が必要になります（高額）。&lt;&#x2F;p&gt;
&lt;p&gt;次に、捨てる覚悟と意思決定です。
現行システムの機能やデータの一部を諦める大胆な意思決定が不可欠であり、
「今と同じことができる」を目指すと必ず失敗します。&lt;&#x2F;p&gt;
&lt;p&gt;そして、現場の抵抗を押し切るコミットメントが絶対条件です。
現場の抵抗をトップダウンで押し切る経営層の覚悟と、
相応の予算を得る交渉力も必須です。&lt;&#x2F;p&gt;
&lt;p&gt;なお、移行手法として「ストラングラーパターン」（Strangler Fig Pattern）
と呼ばれる段階的移行が有効です。
一気に全面移行せず、新機能をSaaSで構築しながら徐々に旧システムの機能を
絞めていく手法です。
リスクを分散でき、途中で軌道修正も可能ですが、
この手法を採用するには移行期間中の並行運用コストを
許容できることが前提条件となります。&lt;&#x2F;p&gt;
&lt;p&gt;これらの対策には膨大な投資が必要です。
この規模の投資を経営判断として通すには、業務効率化による大幅なコスト削減、
新規事業での大きな経済効果の実現、競争優位性の獲得といった、
明確で大きなビジネス成果を示す必要があります。
単なる「技術的負債の解消」では、この規模の投資は正当化できません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-tip&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;www.hamamatsu-soko.co.jp&#x2F;&quot;&gt;浜松倉庫&lt;&#x2F;a&gt;は、
長年使い続けたスクラッチ開発の倉庫管理システム（WMS）を3年かけて刷新し、
経済産業省「DXセレクション2024」でグランプリを受賞しました。
社内にDX人材が1人もいない状態からの出発でした。
成功の鍵は以下の3点でした。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;経営層の全面的コミット&lt;&#x2F;strong&gt; —
社長が「10年後、20年後の会社の在り方を考えてほしい」と若手管理者に問題提起し、
従業員主体で徹底的に議論させた&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;段階的なアプローチ&lt;&#x2F;strong&gt; —
3年間を4段階に分け、ビジョン策定→課題掘り下げ→仕様書作成→導入運用と進めた&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;時間をかける覚悟&lt;&#x2F;strong&gt; —
「もし1年でやれと言われたら失敗していた」（取締役談）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;参考：&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;j-net21.smrj.go.jp&#x2F;special&#x2F;dx&#x2F;20240924.html&quot;&gt;J-Net21 浜松倉庫事例&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;8._自己診断チェックリスト&quot;&gt;8. 自己診断チェックリスト&lt;&#x2F;h2&gt;
&lt;p&gt;自組織がこの「無理ゲー」状態に陥っていないか、
以下のチェックリストで確認してください。
該当項目が多いほど、移行リスクが高い状態です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;システム管理の状態&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現行システムの最新の仕様書・設計書が組織内に存在しない&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;&lt;strong&gt;ベンダー関係&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;5年以上同じベンダーにシステム保守を依存している&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;&lt;strong&gt;組織能力&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CIOまたはIT統括責任者が不在である&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;3項目以上該当する場合は要注意です。
まずは小さな領域から仕様の可視化と文書化を始め、
段階的にIT統制能力を高めていくことを検討してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ：経営への教訓&quot;&gt;まとめ：経営への教訓&lt;&#x2F;h2&gt;
&lt;p&gt;この状況は技術的な問題というより、組織的なガバナンスの喪失が根本原因です。&lt;&#x2F;p&gt;
&lt;p&gt;現状維持を続けるなら、ベンダーロックインの継続と保守費用の高騰を
受け入れるしかありません。
脱出を目指すなら、膨大な投資と困難なプロジェクト遂行が必要です。
しかもその投資は、大きなビジネス成果とセットで
経営層がコミットした場合のみ正当化できます。&lt;&#x2F;p&gt;
&lt;p&gt;「システム刷新」は手段であり、目的ではありません。
安易なIT投資と組織的なIT統制能力の放棄が、
いかに高いツケとなって返ってくるかを示す典型例です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;まだ間に合う組織へ：今日から始められる予防策&quot;&gt;まだ間に合う組織へ：今日から始められる予防策&lt;&#x2F;h3&gt;
&lt;p&gt;このような状況を避けるため、以下の具体的なアクションを今日から始めてください。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;仕様書・設計書の管理体制を確立する&lt;&#x2F;strong&gt; —
ConfluenceやNotionなどのドキュメント管理ツールを導入し、
システム仕様を組織内で一元管理する仕組みを作る。
ベンダーが作成した文書も必ず組織内に保管する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API仕様を可視化する&lt;&#x2F;strong&gt; —
SwaggerやOpenAPI形式でシステム間連携の仕様を文書化しておくと、
将来の移行時に大きな資産となる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定期的な棚卸しを実施する&lt;&#x2F;strong&gt; —
年1回程度、システムの機能一覧と利用状況を棚卸しし、
不要な機能の廃止や仕様の最新化を行う。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;複数ベンダーとの関係を維持する&lt;&#x2F;strong&gt; —
現行ベンダー以外とも定期的に情報交換し、
技術動向の把握と比較検討の材料を確保する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;社内にIT人材を育成する&lt;&#x2F;strong&gt; —
外部に完全依存せず、最低限の技術判断ができる人材を社内に確保する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;すでにこの状況に陥っている組織へ&quot;&gt;すでにこの状況に陥っている組織へ&lt;&#x2F;h3&gt;
&lt;p&gt;絶望する必要はありません。ただし、短期間での劇的な改善は期待できません。
まずは経営層の理解を得ることから始め、
小さな領域から段階的に状況を改善していくアプローチが現実的です。
最初の一歩は、現状を正確に把握し、経営層と共有することです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">IT部門が弱い組織で塩漬けシステムが「無理ゲー」になる構造を解説します。
ブラックボックス化・ベンダーロックイン・組織能力不足が絡み合う
負のスパイラルと、その脱出策を具体的に示します。
</summary>
        </entry><entry xml:lang="en">
        <title>ブログをZolaに移行、AWSの後始末</title>
        <published>2026-01-30T00:00:00+00:00</published>
        <updated>2026-01-30T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/blog-to-zola-aws-cleanup/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/blog-to-zola-aws-cleanup/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;full-width&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;01&amp;#x2F;blog-to-zola-aws-cleanup&amp;#x2F;.&amp;#x2F;zola.webp?h=97404862aa35036da55c&quot; alt=&quot;Zola&quot; width=&quot;1194&quot; height=&quot;716&quot; loading=&quot;lazy&quot;&#x2F;&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;p&gt;技術検証目的で1年ほどNext.js + Amazon Amplify構成のブログを運用していました。
目的も達成したので静的サイトジェネレーター(以下、SSGと記載)に移行しましたが、意外と移行先の選定や
AWSの後始末に手間取りました。その記録を残します。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;Zola_への移行&quot;&gt;Zola への移行&lt;&#x2F;h2&gt;
&lt;p&gt;移行先のSSGには &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; を選びました。&lt;&#x2F;p&gt;
&lt;p&gt;Python系（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getpelican.com&#x2F;&quot;&gt;Pelican&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getnikola.com&#x2F;&quot;&gt;Nikola&lt;&#x2F;a&gt;）は
以前使った経験があり、遅さに辟易していたので避けました。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gohugo.io&#x2F;&quot;&gt;Hugo&lt;&#x2F;a&gt; も使用経験があるため、比較的新しく人気のあるZolaを
選びました。
Rust製のシングルバイナリで、node_modulesやpip installが不要です。&lt;&#x2F;p&gt;
&lt;p&gt;MDX形式の200記事程度あったので、 Markdownへの変換は、Claude Codeで作成した
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;tools&#x2F;convert_mdx.py&quot;&gt;移行ツール&lt;&#x2F;a&gt;
で対応しました。&lt;&#x2F;p&gt;
&lt;p&gt;ホスティング先はCloudflareを想定していました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;サービス&lt;&#x2F;th&gt;&lt;th&gt;Zola 対応&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;Cloudflare Pages&lt;&#x2F;td&gt;&lt;td&gt;V1 のみ&lt;&#x2F;td&gt;&lt;td&gt;V2&#x2F;V3 で &lt;code&gt;zola: not found&lt;&#x2F;code&gt; エラー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Netlify&lt;&#x2F;td&gt;&lt;td&gt;あり&lt;&#x2F;td&gt;&lt;td&gt;2025年9月〜 月20デプロイ制限&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GitHub Pages&lt;&#x2F;td&gt;&lt;td&gt;GitHub Actions&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;Cloudflare PagesはV2以降で &lt;code&gt;ZOLA_VERSION&lt;&#x2F;code&gt; 環境変数を無視する問題があります。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;Issue&lt;&#x2F;a&gt; も2年放置されています。
Netlifyは無料プランのデプロイ制限が厳しいため、GitHub Pages + Cloudflare CDNを採用しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWS_リソースの調査と閉鎖&quot;&gt;AWS リソースの調査と閉鎖&lt;&#x2F;h2&gt;
&lt;p&gt;移行で最も手間がかかったのはAWSの閉鎖です。
Amplifyは便利ですが、裏でCloudFront、S3、IAMロールなど多くのリソースを自動生成します。
管理コンソールでは複数サービスの画面を行き来することになり、見落としが発生しやすいと感じました。
そのため、今回はすべてCLIで調査・削除しました。&lt;&#x2F;p&gt;
&lt;p&gt;まず、Amplifyが作成した可能性のあるリソースを網羅的に確認します。&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;# Amplify アプリ一覧（リージョン指定必須）&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; amplify list-apps --region ap-northeast-1&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;# CloudFront ディストリビューション&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cloudfront list-distributions&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;  --query &amp;#39;DistributionList.Items[*].[Id,Origins.Items[0].DomainName,Status]&amp;#39;&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&quot;&gt;  --output table&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;# S3 バケット（Amplify が作成したバケットを探す）&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3 ls&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; -E &amp;#39;amplify|blog&amp;#39;&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;# IAM ロール（Amplify 関連）&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam list-roles&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;  --query &amp;#39;Roles[?contains(RoleName,`amplify`)].RoleName&amp;#39; --output table&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;# ACM 証明書（カスタムドメイン用、us-east-1 固定）&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; acm list-certificates --region us-east-1&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;  --query &amp;#39;CertificateSummaryList[*].[DomainName,CertificateArn]&amp;#39;&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&quot;&gt;  --output table&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;今回確認されたリソースと、Amplifyアプリ削除時の自動削除有無は以下の通りです。&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;Amplify&lt;&#x2F;td&gt;&lt;td&gt;blog-yostos アプリ&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CloudFront&lt;&#x2F;td&gt;&lt;td&gt;Amplify 管理のディストリビューション&lt;&#x2F;td&gt;&lt;td&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;S3&lt;&#x2F;td&gt;&lt;td&gt;amplify-xxx-deployment バケット&lt;&#x2F;td&gt;&lt;td&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;IAM&lt;&#x2F;td&gt;&lt;td&gt;AmplifySSRLoggingRole 等&lt;&#x2F;td&gt;&lt;td&gt;✗&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ACM&lt;&#x2F;td&gt;&lt;td&gt;blog.yostos.org 証明書&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;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&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;以下ではコマンド例を示していますが、実際の削除作業では各コマンドの出力を目視で
確認し、削除対象が正しいことを1つずつ確かめながら進めました。
AWSリソースの削除は取り消しができないため、慎重に作業することをおすすめします。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Amplify Hosting（WEB_COMPUTEタイプ）の場合、アプリを削除するとCloudFrontと
S3バケットは自動削除されます。&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;# アプリ ID を確認して削除&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; amplify list-apps --region ap-northeast-1&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;  --query &amp;#39;apps[?name==`blog-yostos`].appId&amp;#39; --output text&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; amplify delete-app --app-id&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-string&quot;&gt;APP_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;D&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; --region ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;IAMロールは自動削除されないため、手動で削除します。ロールを削除する前に、
アタッチされているポリシーをすべてデタッチする必要があります。&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam list-attached-role-policies --role-name&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-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam list-role-policies --role-name&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-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&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 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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam detach-role-policy --role-name&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-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&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; --policy-arn&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-string&quot;&gt;POLICY_AR&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;N&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam delete-role --role-name&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-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ACM証明書はCloudFrontで使用中だと削除できないため、CloudFront削除後に
実行します。ACM証明書はus-east-1リージョン固定です。&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; acm list-certificates --region us-east-1&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;  --query &amp;#39;CertificateSummaryList[?DomainName==`blog.yostos.org`]&amp;#39;&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; acm delete-certificate --certificate-arn&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-string&quot;&gt;CERT_AR&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;N&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; --region us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;DNSはFastmailで管理していたため、Amplify用のCNAMEレコードを削除し、
GitHub Pages用の設定に変更しました。&lt;&#x2F;p&gt;
&lt;p&gt;削除後は、各リソースが消えていることを確認します。CloudTrailで削除イベントも
確認できます。&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;# CloudFront（Amplify 管理分が消えていること）&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cloudfront list-distributions&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;  --query &amp;#39;DistributionList.Items[*].Id&amp;#39; --output text&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;# S3（amplify 関連バケットが消えていること）&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3 ls&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; amplify&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;# CloudTrail で削除イベントを確認&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cloudtrail lookup-events&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&quot;&gt;  --lookup-attributes AttributeKey=EventName,AttributeValue=DeleteApp&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&quot;&gt;  --region ap-northeast-1&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;Zolaはシングルバイナリで依存関係がなく、node_modulesの管理から解放されます。
Rust製で高速、テンプレートエンジンもJinja2ライクで書きやすいです。プラグイン
なしでSASSコンパイルやシンタックスハイライトまで対応しており、長期運用での
保守コストの低さが魅力です。GitHub Pages + Cloudflare CDNの構成も安定して
います。&lt;&#x2F;p&gt;
&lt;p&gt;Amazon Amplifyは構築が簡単な反面、閉鎖時は複数サービスにまたがるリソースの確認が
必要です。CloudFrontとS3はAmplifyアプリ削除時に自動削除されますが、IAM
ロール、ACM証明書、DNSレコードは手動削除が必要です。
管理コンソールでは見落としが発生しやすく、かといって個人ブログでCloudFormationを使うほどでもない。
そんなケースではCLIで網羅的に確認し、ログに残しながら作業を進めると安心です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">技術検証目的で1年ほど運用していたNext.js + Amazon Amplify
構成のブログを、静的サイトジェネレーターZolaに移行しました。
移行先の選定、200記事のMarkdown変換、そしてAWSリソースの
網羅的な削除作業まで、移行の記録を残します。
</summary>
        </entry><entry xml:lang="en">
        <title>上司に説明できる生成AIガイドライン - NIST AI RMF準拠Check List</title>
        <published>2026-01-29T00:00:00+00:00</published>
        <updated>2026-01-29T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/genai-governance-checklist-release/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/genai-governance-checklist-release/</id>
        
            <content type="html">&lt;p&gt;この記事は &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;genai-governance-checklist-release&quot;&gt;Zenn に掲載したオリジナル記事&lt;&#x2F;a&gt; の転載です。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&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;「来月までにガイドラインを作って」&quot;&gt;「来月までにガイドラインを作って」&lt;&#x2F;h2&gt;
&lt;p&gt;生成AIも世の中に浸透してきたので、普通の企業や団体でも利用を検討しているところが増えてきたと思います。&lt;&#x2F;p&gt;
&lt;p&gt;ある日突然、上司からこう言われる可能性はありませんか？　あるいはもう既に経験済みかも知れません。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;「うちも生成AIを使い始めたいんだけど、まずガイドラインを作ってくれない？」&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;引き受けたものの、いざ着手すると途方に暮れます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;何から書けばいいのか分からない&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;そんなあなたのために、チェックリストを作りました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&quot;&gt;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;このチェックリストの対象&quot;&gt;このチェックリストの対象&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;誰のためのチェックリストか&quot;&gt;誰のためのチェックリストか&lt;&#x2F;h3&gt;
&lt;p&gt;専門のIT部門を持たない中小規模の組織で、専門家ではない生成AIの利用ガイドラインを策定・点検する担当者を想定しています。&lt;&#x2F;p&gt;
&lt;p&gt;AIやリスク管理の専門知識がなくても、項目を順に確認できるよう、各項目に「説明」と「定義例」を付けています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;何を対象としているか&quot;&gt;何を対象としているか&lt;&#x2F;h3&gt;
&lt;p&gt;ChatGPT・Claude・Gemini等のチャット型SaaS生成AIサービスを業務で利用する場面が対象です。IT部門を持たない組織では、おそらくこれらのチャット型の生成AIから始めるケースが多いと考えられるためです。&lt;&#x2F;p&gt;
&lt;p&gt;以下は対象外です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自社でAIモデルを開発・訓練する場面&lt;&#x2F;li&gt;
&lt;li&gt;ソフトウェア開発におけるコード生成の用途&lt;&#x2F;li&gt;
&lt;li&gt;エージェント型AIの利用（次回更新で対応予定）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;なぜこのチェックリストが「正しい」と言えるのか&quot;&gt;なぜこのチェックリストが「正しい」と言えるのか&lt;&#x2F;h2&gt;
&lt;p&gt;ガイドラインを作ったら、次に待っているのは上司や経営層からの質問です。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;「で、このガイドラインが正しいという根拠は何？」&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;この質問に答えられるよう、本チェックリストはNIST AI RMFを軸に構成しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;NISTとは何か&quot;&gt;NISTとは何か&lt;&#x2F;h3&gt;
&lt;p&gt;NIST（米国国立標準技術研究所）は、米国商務省傘下の連邦機関です。&lt;&#x2F;p&gt;
&lt;p&gt;NISTが策定する標準・ガイドラインは、米国政府機関だけでなく世界中の組織で採用されています。
サイバーセキュリティ分野ではNIST Cybersecurity Framework（CSF）が事実上の世界標準となっており、日本でも金融庁や経済産業省のガイドラインがNIST CSFを参照しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;NIST_AI_RMFとは何か&quot;&gt;NIST AI RMFとは何か&lt;&#x2F;h3&gt;
&lt;p&gt;AI Risk Management Framework（AI RMF 1.0）は、NISTが2023年1月に公開したAIリスク管理の国際的な基本枠組みです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;米国議会の指示（National AI Initiative Act of 2020）に基づいて策定&lt;&#x2F;li&gt;
&lt;li&gt;産官学の幅広いステークホルダーとの協議を経て完成&lt;&#x2F;li&gt;
&lt;li&gt;AIシステムの開発・運用におけるリスク管理の4機能（GOVERN・MAP・MEASURE・MANAGE）を体系化&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;さらに2024年7月には、生成AI固有のリスクを扱う拡張文書NIST AI 600-1（Generative AI Profile）が公開されました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;なぜNISTを軸にすべきか&quot;&gt;なぜNISTを軸にすべきか&lt;&#x2F;h3&gt;
&lt;p&gt;日本にも経済産業省やIPAのガイドラインがありますが、これらはNIST AI RMFを参照して策定されています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ガイドライン&lt;&#x2F;th&gt;&lt;th&gt;NISTとの関係&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;経済産業省「AI事業者ガイドライン」&lt;&#x2F;td&gt;&lt;td&gt;NIST AI RMFの4機能を参照&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;IPA「テキスト生成AI導入・運用ガイドライン」&lt;&#x2F;td&gt;&lt;td&gt;NIST AI RMFを基本構造として採用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;つまり、NISTを押さえておけば、日本のガイドラインの&lt;strong&gt;上流&lt;&#x2F;strong&gt;を押さえたことになります。上司から「根拠は？」と聞かれたら、こう答えられます。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;「米国NISTのAI RMFに基づいています。日本の経産省やIPAのガイドラインも、このNIST AI RMFを参照して策定されています」&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;本チェックリストが参照している基準&quot;&gt;本チェックリストが参照している基準&lt;&#x2F;h3&gt;
&lt;p&gt;NISTを軸に、国内外の主要基準を横断的に参照しています。&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;NIST&lt;&#x2F;td&gt;&lt;td&gt;NIST AI Risk Management Framework (AI RMF 1.0)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;NIST-GAI&lt;&#x2F;td&gt;&lt;td&gt;NIST AI RMF Generative AI Profile (NIST AI 600-1)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;METI&lt;&#x2F;td&gt;&lt;td&gt;経済産業省・総務省「AI事業者ガイドライン」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;JDLA&lt;&#x2F;td&gt;&lt;td&gt;日本ディープラーニング協会「生成AIの利用ガイドライン」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;IPA&lt;&#x2F;td&gt;&lt;td&gt;IPA「テキスト生成AI導入・運用ガイドライン」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;EU-AIA&lt;&#x2F;td&gt;&lt;td&gt;EU AI Act（EU AI規制法）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AIACT-JP&lt;&#x2F;td&gt;&lt;td&gt;AI推進法（人工知能関連技術の研究開発及び活用の推進に関する法律）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;今すぐ使う3ステップ&quot;&gt;今すぐ使う3ステップ&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1._チェックリストを開く&quot;&gt;1. チェックリストを開く&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&quot;&gt;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;全7章・120項目。各項目に「説明」と「定義例」が付いています。まだガイドライン策定に着手してなければ、説明を読んで、これから執筆すべき項目を検討できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2._Excel版で現状を点検する&quot;&gt;2. Excel版で現状を点検する&lt;&#x2F;h3&gt;
&lt;p&gt;もし策定したガイドラインがある、あるいは執筆済みである場合は、EXCELでチェックリストを用意しました。自組織のガイドラインと突き合わせて、項目の抜け漏れを確認いただけます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;raw&#x2F;main&#x2F;excel&#x2F;genai-governance-checklist.xlsx&quot;&gt;Excel版をダウンロード&lt;&#x2F;a&gt;して、対応状況を記入します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ドロップダウンで「対応済／一部対応／未対応／該当なし」を選択&lt;&#x2F;li&gt;
&lt;li&gt;サマリーシートで対応率を自動集計&lt;&#x2F;li&gt;
&lt;li&gt;まずはRequired（必須）項目の対応率100%を目指す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3._定義例を参考にガイドラインを書く&quot;&gt;3. 定義例を参考にガイドラインを書く&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;1.1.A. [Required] 生成AI利用に関する最終責任者（経営層）が&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;明確に定められている [NIST: GOVERN 2.3] [METI]&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;  説明: AI関連の最終判断を下す責任者は必須。責任者が不明確だと、&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;  波及させる。&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;  定義例: 「団体理事長をAI利用の最終責任者とし、利用方針の承認・&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;h2 id=&quot;準拠レベルで優先度が明確&quot;&gt;準拠レベルで優先度が明確&lt;&#x2F;h2&gt;
&lt;p&gt;各項目には準拠レベルが設定されています。限られた時間で何を優先すべきかが一目で分かります。年間予算15億円程度の非営利団体を想定し定義内容に基づいて独自にセットしたものです。業種によって事情が異なると思いますが、設定理由もドキュメントに残していますので必要応じて見直し下さい。&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;Required&lt;&#x2F;td&gt;&lt;td&gt;必ず記載すべき。欠落すると法令違反や重大リスクにつながる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Recommended&lt;&#x2F;td&gt;&lt;td&gt;記載を強く推奨。除外する場合は理由を説明できること&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Option&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;NIST AI RMFの4機能（GOVERN・MAP・MEASURE・MANAGE）に沿って構成しています。&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;th&gt;概要&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;ガバナンス体制&lt;&#x2F;td&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;責任者・ポリシー・教育など組織の管理体制&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;リスクの特定と評価&lt;&#x2F;td&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;利用目的の明確化とリスクアセスメント&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;入力データの管理&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;入力禁止情報・個人情報・機密情報の取り扱い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;出力の管理と利用&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;出力の検証義務・著作権・利用範囲&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;信頼性の確保&lt;&#x2F;td&gt;&lt;td&gt;31&lt;&#x2F;td&gt;&lt;td&gt;正確性・安全性・公平性・透明性などの品質特性&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;インシデント対応&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;報告体制と対応手順&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;ガイドラインとしての完成度&lt;&#x2F;td&gt;&lt;td&gt;12&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;ul&gt;
&lt;li&gt;オンライン版: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&quot;&gt;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;GitHubリポジトリ: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Excel版: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;raw&#x2F;main&#x2F;excel&#x2F;genai-governance-checklist.xlsx&quot;&gt;genai-governance-checklist.xlsx&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;MITライセンスで公開しています。商用・非商用問わず自由に利用できます。&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;docs.anthropic.com&#x2F;ja&#x2F;docs&#x2F;claude-code&quot;&gt;Claude Code&lt;&#x2F;a&gt;を全面的に活用し、コンセプト検討→計画→作成→インスペクションのプロセスで作成しました。&lt;&#x2F;p&gt;
&lt;p&gt;インスペクションにはMAGIシステム&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-magi-1&quot;&gt;&lt;a href=&quot;#fn-magi&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を使用しました。3つの異なる視点を持つAIエージェントが並列でレビューし、指摘を統合することで、単一視点では見落としがちな問題を検出できました。&lt;&#x2F;p&gt;
&lt;p&gt;インスペクションログは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;tree&#x2F;main&#x2F;docs&quot;&gt;docsフォルダ&lt;&#x2F;a&gt;で公開しています。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;現在v1.0.0-rc.1（リリース候補版）です。フィードバックを募集しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;issues&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-magi&quot;&gt;
&lt;p&gt;MAGIシステムは、Claude Codeプラグインとして実装した品質レビューシステムです。エヴァンゲリオンのMAGIから着想を得て、CASPER（批判的分析）・BALTHASAR（実用性評価）・MELCHIOR（創造的提案）の3エージェントが独立してレビューします。詳細は &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&lt;&#x2F;a&gt; を参照してください。 &lt;a href=&quot;#fr-magi-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">NIST AI RMF準拠の生成AIガバナンスチェックリストを公開しました。
ChatGPT・Claude・Gemini等のSaaS型生成AIを業務利用する際の
ガイドライン策定に使える、全7章・120項目の実践的な内容です。
非専門家でも使いやすく、小規模な組織でも今すぐ始められます。
</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>Sublime Text - 職人主義的ソフトウェアの美学と持続可能なビジネスモデル</title>
        <published>2026-01-08T00:00:00+00:00</published>
        <updated>2026-01-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/sublime-text/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/sublime-text/</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;Sublime Textは、高速性と簡潔さを重視したクロスプラットフォームのテキストエディタです。
派手な統合機能や巨大なエコシステムを志向せず、「編集体験そのものの質」を最優先に設計されている点が最大の特徴といえます。&lt;&#x2F;p&gt;
&lt;p&gt;2008年にリリースされて以来、その圧倒的なパフォーマンスと洗練されたUIで多くの開発者に愛されてきました。
かつてはAtomやBracketsといった競合が次々と登場する中でも独自の地位を確立していましたが、
2015年のVisual Studio Codeの登場によって状況は一変しました。
Microsoftの豊富なリソースとオープンソースモデルによって急速に機能を拡充したVS Codeは、
瞬く間に開発者コミュニティの主流となったのです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、Sublime Textは市場シェアを失っても開発を継続し、現在も継続的にアップデートされています。
それを可能にしているのが、独自のビジネスモデルと一貫した設計思想です。
2026年現在もBuild 4000番台の開発が進められており、その品質は今も一級品を保ち続けています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._技術的・思想的特徴&quot;&gt;1. 技術的・思想的特徴&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1.1._圧倒的なパフォーマンス&quot;&gt;1.1. 圧倒的なパフォーマンス&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;起動が非常に速い&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;Sublime Textの最大の強みは、何よりもそのパフォーマンスです。
エディタを起動してから実際に編集を開始できるまでの時間は、ほとんどの環境で1秒以内に収まります。
VS CodeがElectronベースでJavaScriptエンジンの起動コストを伴うのに対し、Sublime TextはC++ とカスタムUIツールキットで実装されており、
OSネイティブに近い起動速度を実現しています。&lt;&#x2F;p&gt;
&lt;p&gt;また、数万行を超える大規模ファイルや、数十万ファイルを含む巨大なリポジトリでも動作が重くなることはほとんどありません。
GitのLinuxカーネルリポジトリのような巨大なコードベースでも、ファイル検索や全文検索が瞬時に完了します。
これは独自の描画エンジンとインデックス機構によって実現されており、「常に軽いこと」を最優先事項として設計されているためです。&lt;&#x2F;p&gt;
&lt;p&gt;特に重要なのが、入力に対するレスポンスの速さです。キーボードからの入力が画面に反映されるまでの遅延が極めて少なく、タイピングの快適さが損なわれません。この「入力遅延のなさ」は、長時間コーディングを行う開発者にとって、想像以上に重要な要素となります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.2._ミニマルで静かな_UI&quot;&gt;1.2. ミニマルで静かな UI&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;不要なアニメーションや通知が少ない&lt;&#x2F;li&gt;
&lt;li&gt;情報密度は高いが、視覚的ノイズが少ない&lt;&#x2F;li&gt;
&lt;li&gt;IDE的な自動介入を極力行わない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textのユーザーインターフェースは、極めて静かです。
近年のソフトウェアに多く見られる派手なアニメーションや、頻繁なポップアップ通知、自動的に表示されるヒントやサジェストといった「親切な機能」は最小限に抑えられています。&lt;&#x2F;p&gt;
&lt;p&gt;これは決して機能が貧弱だからではなく、ユーザーの集中を妨げない設計を意図的に選択した結果です。
情報密度は高く保たれており、必要な情報はすぐにアクセスできますが、視覚的なノイズは徹底的に排除されています。
エディタという道具が前面に出てくることなく、書いているコードそのものに集中できる環境が提供されているのです。&lt;&#x2F;p&gt;
&lt;p&gt;また、IDEによくある「自動的な修正」や「勝手な補完」といった介入も控えめです。
開発者が意図しないコード変更や、予期しないフォーマットが適用されることはほとんどありません。
これは一見不便に思えるかもしれませんが、自分の書いたコードを完全にコントロールしたい開発者にとっては、むしろ信頼できる特性となります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.3._保守的で一貫した設計思想&quot;&gt;1.3. 保守的で一貫した設計思想&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;等幅フォント・静的フォント前提&lt;&#x2F;li&gt;
&lt;li&gt;Variable Fontの軸指定や高度なタイポグラフィ機能は非対応&lt;&#x2F;li&gt;
&lt;li&gt;フォントフォールバックや複雑な文字組みも対象外&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textは、技術トレンドを積極的に追いかけるタイプのソフトウェアではありません。例えば、近年広まってきたVariable Font（可変フォント）の軸指定機能や、高度なタイポグラフィ機能には対応していません。また、複雑なフォントフォールバックや文字組み処理も、必要最小限にとどめられています。&lt;&#x2F;p&gt;
&lt;p&gt;これを見ると「技術的に遅れている」と感じるかもしれませんが、実際には異なります。これらの機能は確かに便利ですが、実装にはレンダリングエンジンの複雑化が伴い、結果としてパフォーマンスの低下を招きます。Sublime Textは、&lt;strong&gt;パフォーマンス低下を招く機能を意図的に排除している&lt;&#x2F;strong&gt; のです。&lt;&#x2F;p&gt;
&lt;p&gt;この姿勢は、ソフトウェア全体に一貫しています。新機能を追加する際には、常に「これはパフォーマンスに影響するか」
「これは本当にエディタに必要な機能か」という問いが立てられ、慎重に判断されています。
結果として、機能の追加ペースは遅いものの、一度実装された機能は安定しており、長期間にわたって同じように動作し続けます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.4._拡張は可能だが、万能ではない&quot;&gt;1.4. 拡張は可能だが、万能ではない&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Pythonによるプラグイン拡張&lt;&#x2F;li&gt;
&lt;li&gt;LSP対応により、現代的な言語サポート機能は充実&lt;&#x2F;li&gt;
&lt;li&gt;ただしIDE全体としての統合度はVS Codeに及ばない&lt;&#x2F;li&gt;
&lt;li&gt;エコシステムは小規模&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textには、Pythonによるプラグイン機構が備わっており、機能を拡張可能です。Package Controlというパッケージマネージャーを使えば、コミュニティが開発した様々なプラグインを簡単にインストールできます。また、Language Server Protocol (LSP) にも対応しており、現代的なコード補完や定義ジャンプ、型チェックといった言語サポート機能は充実しています。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、VS Codeのような統合開発環境としての&lt;strong&gt;トータルな統合度&lt;&#x2F;strong&gt;を期待すると、物足りなさを感じるかもしれません。デバッガやターミナル、バージョン管理といった周辺機能の統合度や、拡張機能エコシステムの規模では、VS Codeには及びません。&lt;&#x2F;p&gt;
&lt;p&gt;エコシステムも、VS Codeの巨大なマーケットプレイスと比べれば小規模です。しかし、これも設計思想の表れといえます。Sublime Textは「プラットフォーム」になることを目指しておらず、あくまで「高品質なエディタ」であり続けることを選択しているのです。必要十分な拡張性は保ちつつ、複雑化や肥大化は避けるというバランスが取られています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._継続的な開発と進化&quot;&gt;2. 継続的な開発と進化&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime Textは市場シェアを失った後も、着実に開発を継続しています。2024年から2025年にかけても、
複数の重要なアップデートがリリースされており、「保守的」でありながらも「停滞していない」ことを示しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2.1._最近の主要アップデート&quot;&gt;2.1. 最近の主要アップデート&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Build 4200（2025年5月リリース）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;2025年5月21日にリリースされたBuild 4200では、以下の重要な変更が含まれています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python プラグインの近代化&lt;&#x2F;strong&gt;: Python 3.3のサポート終了を段階的に開始し、Python 3.8への移行を進めている。さらに、次の開発サイクルではPython 3.13への移行が計画されており、プラグインエコシステムの技術的負債を解消する取り組みが進められている。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OS サポートの見直し&lt;&#x2F;strong&gt;: 将来のバージョンでは、macOSの最低要件が10.9から10.13に引き上げられる。また、Windows 7、8、8.1のサポートが終了し、Windows 10以降が最低要件となる。この変更により、より新しいOS機能を活用できるようになる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;UI の柔軟性向上&lt;&#x2F;strong&gt;: サイドバーを右側に配置できる &lt;code&gt;sidebar_on_right&lt;&#x2F;code&gt; 設定が追加される。これは小さな変更に見えるが、長年のユーザー要望に応えたもの。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ビルドシステムの強化&lt;&#x2F;strong&gt;: ビルドシステムで &lt;code&gt;&quot;interactive&quot;: true&lt;&#x2F;code&gt; を指定することで、インタラクティブな入力ボックスを表示できるようになった。これにより、コンパイル時の引数指定などがより便利になっている。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;構文ハイライトの刷新&lt;&#x2F;strong&gt;: SQL、ActionScript、Diff、Bash、Graphvizの構文ハイライトが書き直され、より正確で高速になった。また、ZshとTOMLの構文ハイライトが新たに追加されている。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Build 4180（2024年8月リリース）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;2024年8月12日にリリースされたBuild 4180では、プラットフォーム固有の問題に対応しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Linux: KDE環境でのドラッグ＆ドロップ問題への対処（kwin 6.0.4でも修正済み）&lt;&#x2F;li&gt;
&lt;li&gt;Windows: スクロールバーをドラッグした際の動作改善&lt;&#x2F;li&gt;
&lt;li&gt;その他、複数のバグ修正&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2.2._Language_Server_Protocol（LSP）サポートの充実&quot;&gt;2.2. Language Server Protocol（LSP）サポートの充実&lt;&#x2F;h3&gt;
&lt;p&gt;Sublime TextのLSPサポートは、近年大きく進化しています。Package Controlから利用できる &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lsp.sublimetext.io&#x2F;&quot;&gt;LSP パッケージ&lt;&#x2F;a&gt;は、VS Codeと同等の高度な言語サポートを実現しています。&lt;&#x2F;p&gt;
&lt;p&gt;主要な言語サーバーには、以下のようなものがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LSP-typescript &#x2F; LSP-javascript&lt;&#x2F;strong&gt;: TypeScriptとJavaScriptのサポート&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-pyright &#x2F; LSP-pylsp&lt;&#x2F;strong&gt;: Pythonの型チェックと補完&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-rust-analyzer&lt;&#x2F;strong&gt;: Rustの高度なIDE機能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-intelephense &#x2F; LSP-Phpactor&lt;&#x2F;strong&gt;: PHPの補完と定義ジャンプ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-clangd&lt;&#x2F;strong&gt;: C&#x2F;C++ の高度な補完&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-json &#x2F; LSP-css &#x2F; LSP-html&lt;&#x2F;strong&gt;: Web開発のサポート&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-angular &#x2F; LSP-vue&lt;&#x2F;strong&gt;: モダンなフロントエンドフレームワーク&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらのヘルパーパッケージは、言語サーバーの自動インストールと設定を簡単にし、追加機能も提供しています。例えばLSP-pylspは2025年12月にも更新されており、エコシステムが活発に維持されていることがわかります。&lt;&#x2F;p&gt;
&lt;p&gt;興味深いのは、Sublime TextのLSP実装は同じファイルタイプに対して複数の言語サーバーを同時に実行できる点です。例えば、Pythonプロジェクト内のLSP-pyrightで一般的な機能を使いつつ、LSP-ruffでリンター警告を同時に表示するといった使い方が可能です。&lt;&#x2F;p&gt;
&lt;p&gt;このように、Sublime Textは「保守的」な設計思想を保ちながらも、現代的な開発環境に必要な機能を着実に取り込んでいます。急激な変化は起こりませんが、必要な進化は確実に続けられているのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3._市場における位置づけ&quot;&gt;3. 市場における位置づけ&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;かつては高速GUIエディタの代表格&lt;&#x2F;li&gt;
&lt;li&gt;現在はニッチだが評価の高い存在&lt;&#x2F;li&gt;
&lt;li&gt;VS Codeのような統合開発環境とは競争しない立場&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;2010年代前半、Sublime Textは高速なGUIエディタの代表格として、多くの開発者に愛用されていました。TextMateの後継とも目され、Macユーザーを中心に広く普及していたのです。その影響力は大きく、VS Codeの初期バージョンはSublime Textのキーバインドやショートカットを参考にしたとも言われています。&lt;&#x2F;p&gt;
&lt;p&gt;しかし現在では、市場シェアという観点では完全にニッチな存在となりました。Stack Overflowの開発者調査でも、利用率は数パーセント程度にとどまっています。それでも、使い続けているユーザーからの評価は一貫して高く、「速さ」「安定性」「シンプルさ」を求める開発者の間では根強い支持を得ています。&lt;&#x2F;p&gt;
&lt;p&gt;興味深いのは、Sublime Textのユーザー層です。多くは、日常的にNeovimやEmacsといったCLIエディタを使いつつ、GUIが必要な場面や、より視覚的な操作が適している場面でSublime Textを併用しています。つまり、「メインのIDE」として使うのではなく、職人的な開発者の道具箱の中の1つとして位置づけられているのです。&lt;&#x2F;p&gt;
&lt;p&gt;VS Codeのような統合開発環境とは、もはや直接競争する立場にありません。機能の豊富さや拡張性では勝負せず、「軽快さ」「シンプルさ」「信頼性」という独自の価値を提供し続けることで、固有のポジションを確立しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4._ビジネスモデル&quot;&gt;4. ビジネスモデル&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime Textが長期にわたって開発を継続できているのは、独自のビジネスモデルによるところが大きいです。多くのソフトウェアが無料化やサブスクリプションモデルに移行する中、Sublime Textは独自の道を歩んでいます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.1._買い切り型ライセンス_+_更新権&quot;&gt;4.1. 買い切り型ライセンス + 更新権&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;一度購入すれば永続的に使用可能&lt;&#x2F;li&gt;
&lt;li&gt;購入時点から &lt;strong&gt;約3年間のアップデート権&lt;&#x2F;strong&gt; が付与される&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;Sublime Textのライセンスは、買い切り型を基本としています。一度購入すれば、そのバージョンは永続的に使用可能です。ただし、購入時点から約3年間のアップデート権が付与され、その期間内にリリースされた新バージョンには無料でアップグレードできます。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、更新権が切れても、ソフトウェアが使用不可になることはない点です。購入時のバージョンは引き続き使用でき、セキュリティアップデートなどの重要な修正も提供されます。新しいメジャーバージョンや最新機能を使いたい場合にのみ、ライセンスを再購入すればよいのです。&lt;&#x2F;p&gt;
&lt;p&gt;このモデルは、月額・年額で支払い続けなければ使えなくなるSaaS的なサブスクリプションとは明確に異なります。ユーザーは「払い続けなければ使えなくなる」というプレッシャーから解放され、自分のペースでアップグレードを判断できます。一方で、開発側も定期的な収入が見込めるため、持続可能な開発が可能になっています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.2._非_SaaS・低固定費構造&quot;&gt;4.2. 非 SaaS・低固定費構造&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;クラウドサービスではない&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;ul&gt;
&lt;p&gt;Sublime Textのもう1つの強みは、極めて低い固定費構造にあります。Sublime Textはクラウドサービスではなく、ユーザーのローカル環境で完結するスタンドアロンアプリケーションです。そのため、常時稼働するサーバーインフラや、大規模なデータセンターといった継続的なコストが一切発生しません。&lt;&#x2F;p&gt;
&lt;p&gt;開発チームも非常に小規模で、創設者のJon Skinner氏を中心とした数名程度で運営されていると言われています。大規模な開発組織を抱える必要がなく、人件費も抑えられています。&lt;&#x2F;p&gt;
&lt;p&gt;また、営業やマーケティングにも積極的に投資していません。広告を出すこともなく、口コミとブランド力だけで販売を続けています。Sublime Textの公式サイトは極めてシンプルで、派手なマーケティングメッセージもありません。&lt;&#x2F;p&gt;
&lt;p&gt;この結果、&lt;strong&gt;ユーザー数が爆発的に増えなくても黒字が成立する&lt;&#x2F;strong&gt;構造になっています。年間数万人程度のライセンス購入があれば、十分に開発を継続できるのです。これは、成長至上主義に陥らず、持続可能な開発を可能にする重要な要素となっています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.3._法人・プロユーザーによる支え&quot;&gt;4.3. 法人・プロユーザーによる支え&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;個人購入に加え、法人でのまとめ買い&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;Sublime Textのユーザーには、個人利用だけでなく、法人でのまとめ買いも多いと考えられます。開発チームが一斉にライセンスを購入するケースや、企業の標準ツールとして採用されているケースもあります。特に、パフォーマンスや安定性を重視する企業にとって、Sublime Textは魅力的な選択肢となります。&lt;&#x2F;p&gt;
&lt;p&gt;また、プロフェッショナルな開発者が多いため、ライセンスを経費として精算し、定期的に更新する傾向があります。個人で$99を支払うのは躊躇するかもしれませんが、会社の経費であれば、更新のハードルは下がります。&lt;&#x2F;p&gt;
&lt;p&gt;Sublime Textのユーザーは、長期利用を前提としている傾向が強いです。一度使い始めたら、数年から十年以上にわたって使い続けるユーザーが多いのです。これは、Sublime Textの安定性とシンプルさが、長期的な信頼を生んでいることを示しています。&lt;&#x2F;p&gt;
&lt;p&gt;一人あたりのLTV（顧客生涯価値）は、サブスクリプションモデルと比べると低めですが、非常に安定しています。ユーザーの離脱率が低く、定期的な更新が見込めるため、予測可能な収益構造となっているのです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.4._成長を前提としない経営姿勢&quot;&gt;4.4. 成長を前提としない経営姿勢&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;ベンチャーキャピタルに依存しない&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;Sublime Textの最も特徴的な点は、成長を前提としない経営姿勢にあります。ベンチャーキャピタルからの資金調達を受けておらず、外部投資家からの「成長しろ」というプレッシャーとは無縁です。そのため、ユーザー数を爆発的に増やすことや、市場シェアを最大化することを目標とする必要がありません。&lt;&#x2F;p&gt;
&lt;p&gt;また、ユーザーの利用データを収集して分析したり、広告モデルで収益化したりといったことも一切行っていません。Sublime Textは、インターネット接続を必要とせず、ローカル環境で完結するため、プライバシーの観点でも安心できます。テレメトリデータの送信もなく、ユーザーがどのような使い方をしているかは開発者にはわかりません。&lt;&#x2F;p&gt;
&lt;p&gt;この経営姿勢は、現代のスタートアップ文化やシリコンバレーの常識とは真逆です。「急成長」「ユニコーン」「市場の独占」といった価値観とは距離を置き、その代わりに**「小さく、長く、静かに続ける」**ことを選択しています。&lt;&#x2F;p&gt;
&lt;p&gt;これは、短期的な利益最大化ではなく、長期的な持続可能性を重視した結果です。派手さはありませんが、10年後、20年後も同じように開発が続いている。そんな可能性を信じさせてくれるのが、Sublime Textなのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;5._Sublime_Merge_-_同じ思想の_Git_クライアント&quot;&gt;5. Sublime Merge - 同じ思想の Git クライアント&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime HQは、テキストエディタのSublime Textだけでなく、Gitクライアントの &lt;strong&gt;Sublime Merge&lt;&#x2F;strong&gt; も開発しています。Sublime Mergeは、Sublime Textと同じ設計思想をGitクライアントに適用したソフトウェアです。&lt;&#x2F;p&gt;
&lt;p&gt;Sublime Mergeの特徴も、Sublime Textと共通しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;起動が非常に速く、大規模リポジトリでも軽快に動作する&lt;&#x2F;li&gt;
&lt;li&gt;UIがシンプルで、視覚的なノイズが少ない&lt;&#x2F;li&gt;
&lt;li&gt;複雑なGit操作も、キーボード中心の操作で素早く実行できる&lt;&#x2F;li&gt;
&lt;li&gt;独自のマージツールが優れており、コンフリクト解決が快適&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Gitクライアントの世界でも、GitKrakenやSourceTreeといった多機能なGUIツールが主流となっていますが、Sublime Mergeはそれらとは異なるアプローチを取っています。必要な機能に絞り込み、パフォーマンスと操作性を優先した結果、Gitの複雑な操作を快適に行えるツールとなっています。&lt;&#x2F;p&gt;
&lt;p&gt;ビジネスモデルもSublime Textと同様で、買い切り型ライセンス + 約3年間の更新権という形式です。Sublime TextとSublime Mergeをセットで購入すると割引が適用されるバンドルライセンスも提供されています。&lt;&#x2F;p&gt;
&lt;p&gt;私自身も、Sublime Textの思想に共鳴し、今回Sublime Textのライセンスを更新すると同時に、Sublime Mergeのライセンスも購入しました。どちらも、長く使い続けられる信頼できるツールだと感じています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;6._評価と総括&quot;&gt;6. 評価と総括&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime Textは次のようなソフトウェアです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;主役ではなくなったが、品質は今も一級品&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;ul&gt;
&lt;p&gt;その結果として、&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;「勢いはないが、消えもしない」&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;という独特のポジションを確立しています。&lt;&#x2F;p&gt;
&lt;p&gt;現代のソフトウェア業界では、「より多くの機能」「より大きなエコシステム」「より速い成長」が正義とされがちです。しかし、Sublime Textはそれとは異なる価値観を示しています。機能を抑制し、シンプルさを保ち、持続可能な開発を優先することで、長期的な信頼を獲得しているのです。&lt;&#x2F;p&gt;
&lt;p&gt;このアプローチは、すべてのソフトウェアに適用できるわけではありません。しかし、少なくとも「開発ツール」という領域においては、十分に成立する戦略であることを、Sublime Textは証明しています。&lt;&#x2F;p&gt;
&lt;p&gt;Sublime Textは、現代では稀少になった&lt;strong&gt;職人主義的ソフトウェアと、そのビジネスモデルの実例&lt;&#x2F;strong&gt;です。派手さはありませんが、確かな品質と一貫した思想を持ち続けることで、静かに、しかし確実に生き残っているのです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">高速性と簡潔さを追求し続けるテキストエディタSublime Text。
VS Codeに市場シェアを奪われても品質を保ち続ける職人主義的な
設計思想と、サブスクリプションに依存しないワンタイム購入モデルの
持続可能性について考察します。
</summary>
        </entry><entry xml:lang="en">
        <title>スキャンPDFの処理を自動化するClaude Codeプラグインを作った</title>
        <published>2026-01-02T00:00:00+00:00</published>
        <updated>2026-01-02T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/pdf-processor-plugin/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/pdf-processor-plugin/</id>
        
            <content type="html">&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;書籍をスキャナーで読み取ってPDF化すると、複数のファイルに分かれてしまったり、テキスト検索ができなかったりします。また、目次がないため、そのままでは使いにくい状態になります。これらを手作業で処理するのは非常に面倒です。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、スキャンしたPDFの処理を自動化するClaude Codeプラグイン「pdf-processor」を開発しました。このプラグインを使えば、複数のPDFファイルのマージ、OCR処理、目次の追加を簡単に実行でます。&lt;&#x2F;p&gt;
&lt;p&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;pdf-processor&quot;&gt;GitHub&lt;&#x2F;a&gt;で公開しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pdf-processorプラグインの機能&quot;&gt;pdf-processorプラグインの機能&lt;&#x2F;h2&gt;
&lt;p&gt;このプラグインは、スキャンされたPDFファイルを実用的なデジタル書籍に変換するためのツールです。主な機能は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;複数PDFファイルのマージ&lt;&#x2F;strong&gt;: バラバラのPDFファイルを1つに統合&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;OCR処理&lt;&#x2F;strong&gt;: 日本語に対応したOCR処理により、画像PDFをテキスト検索可能に変換&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;: PDFビューアで使える目次を自動生成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;メタデータ編集&lt;&#x2F;strong&gt;: PDFのタイトル、著者などのメタデータを設定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;使い方&quot;&gt;使い方&lt;&#x2F;h2&gt;
&lt;p&gt;pdf-processorプラグインは、3つのステップで処理を行います。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ1:_前処理の実行&quot;&gt;ステップ1: 前処理の実行&lt;&#x2F;h3&gt;
&lt;p&gt;まず、&lt;code&gt;&#x2F;pdf-processor:preprocess&lt;&#x2F;code&gt; コマンドを実行して、複数のPDFファイルをマージし、OCR処理を行います。&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;pdf-processor:preprocess&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claudeが以下の処理を自動で実行します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;対象となるPDFファイルの確認&lt;&#x2F;li&gt;
&lt;li&gt;PDFのマージ&lt;&#x2F;li&gt;
&lt;li&gt;OCR処理の実行&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;処理が完了すると、OCR処理済みのPDFファイルと、メタデータをダンプしたファイルが生成されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ2:_目次情報の編集&quot;&gt;ステップ2: 目次情報の編集&lt;&#x2F;h3&gt;
&lt;p&gt;ダンプされたメタデータファイルをエディタで開き、目次情報を追加します。目次は以下の形式で記述します。&lt;&#x2F;p&gt;
&lt;p&gt;各目次項目は &lt;code&gt;BookmarkBegin&lt;&#x2F;code&gt; で始まり、以下の3つのフィールドで構成されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BookmarkTitle&lt;&#x2F;code&gt;: 目次のタイトル（章名など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;BookmarkLevel&lt;&#x2F;code&gt;: 目次の階層レベル（1が最上位、2が第2階層）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;BookmarkPageNumber&lt;&#x2F;code&gt;: 目次項目が指すページ番号&lt;&#x2F;li&gt;
&lt;&#x2F;ul&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;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: 第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;&#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: 1.1 背景&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 2&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;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: 1.2 目的&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 5&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;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: 第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;h3 id=&quot;ステップ3:_目次の適用&quot;&gt;ステップ3: 目次の適用&lt;&#x2F;h3&gt;
&lt;p&gt;目次情報を編集したら、&lt;code&gt;&#x2F;pdf-processor:apply-toc&lt;&#x2F;code&gt; コマンドを実行して、最終的なPDFファイルを生成します。&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;pdf-processor:apply-toc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドを実行すると、OCR処理済みのPDFに目次が追加され、完成版のPDFファイルが作成されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;技術的な詳細&quot;&gt;技術的な詳細&lt;&#x2F;h2&gt;
&lt;p&gt;pdf-processorプラグインは、以下のツールを組み合わせて実装しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OCRmyPDF&lt;&#x2F;strong&gt;: PythonベースのOCRツールで、Tesseract OCRエンジンを使用してPDFにテキストレイヤーを追加&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;PDFtk&lt;&#x2F;strong&gt;: PDFの操作に特化したコマンドラインツールで、マージやメタデータの編集に使用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Ghostscript&lt;&#x2F;strong&gt;: PDFの最適化と圧縮に使用&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらのツールのインストールや設定は、プラグインのREADMEに詳しく記載されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;pdf-processorプラグインを使うことで、スキャンしたPDFの処理を大幅に効率化できます。複数ファイルのマージ、OCR処理、目次の追加といった面倒な作業を、Claude Codeとの対話だけで完了できるようになりました。&lt;&#x2F;p&gt;
&lt;p&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;pdf-processor&quot;&gt;GitHub&lt;&#x2F;a&gt;で公開しているので、カスタマイズや改善の提案も歓迎します。&lt;&#x2F;p&gt;
</content>
        <summary type="html">書籍をスキャナーで読み取ってPDF化した後の処理を簡単にするため、
Claude Codeプラグイン「pdf-processor」を開発しました。
複数PDFのマージ、OCR処理、ファイルサイズ最適化、目次の追加を
自動化し、スキャン書籍を実用的なデジタル書籍に変換します。
</summary>
        </entry><entry xml:lang="en">
        <title>MAGIシステムをClaude Code Pluginで実装してみた</title>
        <published>2025-12-12T00:00:00+00:00</published>
        <updated>2025-12-12T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/magi-claude-code-plugin/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/magi-claude-code-plugin/</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;Claude_Code_Pluginとは&quot;&gt;Claude Code Pluginとは&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Code Pluginは、AnthropicのClaude Code CLI向けの拡張機能システムです。プラグインを使用することで、Claudeに新しいコマンド、エージェント、スキル、フックなどを追加できます。&lt;&#x2F;p&gt;
&lt;p&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;カスタムエージェント&lt;&#x2F;strong&gt;: 特定のタスクに特化したAIエージェントを作成&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;MCP統合&lt;&#x2F;strong&gt;: Model Context Protocol経由で外部サービスと連携&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;プラグインはマーケットプレイスから簡単にインストールでき、ローカルでの開発も可能です。これにより、チームやプロジェクトごとにClaude Codeの機能をカスタマイズできます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;エヴァンゲリオンのMAGIシステムとは&quot;&gt;エヴァンゲリオンのMAGIシステムとは&lt;&#x2F;h2&gt;
&lt;p&gt;MAGIは、アニメ「新世紀エヴァンゲリオン」に登場する架空のスーパーコンピュータシステムです。人間の頭脳をベースにした3つの独立したシステムで構成されており、重要な意思決定を合議制で行います。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;MAGIの3つのシステム&quot;&gt;MAGIの3つのシステム&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MELCHIOR（メルキオール）&lt;&#x2F;strong&gt;: 科学者としての側面を模擬。論理性と合理性に基づいて判断する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;BALTHASAR（バルタザール）&lt;&#x2F;strong&gt;: 母親としての側面を模擬。保護と倫理を重視して判断する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CASPER（キャスパー）&lt;&#x2F;strong&gt;: 女性としての側面を模擬。感情と共感に基づいて判断する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この3つのシステムは、それぞれ異なる視点から問題を分析し、多数決で最終的な結論を導きます。人間の多面的な判断プロセスを再現することで、より包括的で偏りの少ない意思決定を目指しています。&lt;&#x2F;p&gt;
&lt;p&gt;作中では、「使徒」への対処方法など、人類の存続に関わる重要な判断をMAGIにより下される場面が描かれています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Magi_Claude_Code_Pluginの実装&quot;&gt;Magi Claude Code Pluginの実装&lt;&#x2F;h2&gt;
&lt;p&gt;このコンセプトを実際のシステムとして実装したのが、今回作成した「Magi」Claude Code Pluginです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;システム構成&quot;&gt;システム構成&lt;&#x2F;h3&gt;
&lt;p&gt;Magiシステムは4つのエージェントで構成されています。&lt;&#x2F;p&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
   U[fa:fa-user User]
    subgraph magi
      A[ARBITRATOR]
      B[MELCHIOR]
      C[BALTHASAR]
      D[CASPER]
    end
 
    U --&gt;|1.request| A
    A --&gt;|2.reconcile| U
    A --&gt;B
    A --&gt;C
    A --&gt;D
    A ---&gt;|5.result|U
&lt;&#x2F;pre&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Agent&lt;&#x2F;th&gt;&lt;th&gt;Role&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ARBITRATOR（アービトレーター）&lt;&#x2F;td&gt;&lt;td&gt;課題の構造化と最終調停を担当&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MELCHIOR（メルキオール）&lt;&#x2F;td&gt;&lt;td&gt;科学的・技術的な分析を担当&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BALTHASAR（バルタザール）&lt;&#x2F;td&gt;&lt;td&gt;法律的・倫理的な分析を担当&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CASPER（キャスパー）&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;動作フロー&quot;&gt;動作フロー&lt;&#x2F;h3&gt;
&lt;p&gt;システムの動作は3つのフェーズに分かれています。&lt;&#x2F;p&gt;
&lt;dl&gt;
  &lt;dt&gt;Phase 1: 課題の構造化。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    ARBITRATORがユーザーとの対話を通じて、漠然とした課題を命題、前提、A案、B案の形式に整理します。この構造化により、エージェントたちが同じ前提で議論できるようになります。
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;Phase 2: 並列分析。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    3つの専門エージェントが同時並行で分析を開始します。
    重要なのは、各エージェントが**完全に独立して判断する**点です。他のエージェントの意見を参照せず、自身の専門性と価値観に基づいて結論を出します。
    各エージェントはWeb検索機能を使って最新の情報を収集し、その結果を判断の根拠として提示します。
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;Phase 3: 合議と結論。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    ARBITRATORが3つのエージェントの投票結果を集計し、多数決で最終結論を決定します。
  &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;インストール方法&quot;&gt;インストール方法&lt;&#x2F;h2&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;claude-code-plugins.git&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; claude-code-plugins&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;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;# claude code上で&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 &#x2F;path&#x2F;to&#x2F;claude-code-plugins&#x2F;marketplace test-marketplace&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 magi@test-marketplace&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;実際の使用例です。設問は次の通りです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;東京湾から上陸した巨大怪獣を自衛隊がディズニーランドで撃退したとします。ディズニーランドには巨大怪獣の遺体が残り、オ
リエンタルランドはディズニーランド営業再開のため一刻も早く片付けを希望しています。しかし、片付けには膨大な費用が必要です。さて、この片付け費用が誰が払うべきでしょうか?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;この設問をARBITRATORが次のように整理してくれました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;dl&gt;
  &lt;dt&gt;命題。&lt;&#x2F;dt&gt;
  &lt;dd&gt;巨大怪獣の遺体撤去費用は誰が負担すべきか。&lt;&#x2F;dd&gt;
  &lt;dt&gt;前提。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    &lt;ul&gt;
      &lt;li&gt;自衛隊が国防行動として怪獣を撃退した。&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;li&gt;類似の法的前例は存在しない。&lt;&#x2F;li&gt;
      &lt;li&gt;保険適用は絶望的（前代未聞の事態のため）。&lt;&#x2F;li&gt;
      &lt;li&gt;災害対策基本法の適用可否については賛否が分かれている。&lt;&#x2F;li&gt;
    &lt;&#x2F;ul&gt;
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;A案: 国（政府）が全額負担。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    理由は、自衛隊による国防行動の結果であり、公共の安全確保のための公的措置。国民全体の利益のために行った行動の結果責任。
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;B案: オリエンタルランド（施設所有者）が全額負担。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    理由は、自社敷地内に存在する物件の管理責任。営業再開による利益は企業が享受するため、その前提となる費用も負担すべき。
  &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;最終的な3つのAIエージェントの投票結果は次のようなものでした。
それぞれの観点からの合理性が述べられており、根拠も明確です。これは意外に活用できそうです。&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;【MAGI システム 最終結論】&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;投票結果: A案 3票 vs B案 0票&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;採択: A案（国が全額負担）&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;---&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;各エージェントの判断:&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;MELCHIOR (科学的・技術的分析): A案&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;- 因果関係の明確性: 遺体発生の直接原因は国の防衛行動&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;- 経済効率性: 社会全体での負担分散が最適（総合スコア A案 4.75 vs B案 2.25）&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BALTHASAR (法律・倫理的分析): A案&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;- 法的根拠: 自衛隊法に基づく国防行動の結果責任、災害対策基本法の類推適用可能性&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 憲法的視点: 憲法第29条（財産権保障）の趣旨から、公共目的のための損失は補償されるべき&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;- 社会的連帯: リスクを全納税者に薄く広く分散することが社会正義に適う&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;CASPER (感情・トレンド分析): A案&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;- 感情的公正: 被害者をさらに苦しめる構図は国民感情として受け入れがたい&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;- 現代的価値観: 人間中心、包摂的な危機管理が現代社会のトレンド&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;&#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;&#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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;全会一致でA案が採択されました。 これは極めて強い合意です。&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;巨大怪獣の遺体撤去費用は、国（政府）が全額負担すべきです。&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;主要な論点:&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;1. 因果関係: 遺体が発生したのは、国の防衛行動の直接的結果である&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. 予見可能性: 怪獣襲来は通常の事業リスク評価の範囲外であり、企業に予見・対策を求めることは不可能&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. 法的整合性: 災害対策基本法の類推適用、憲法第29条の財産権保障、国家責任の原則から、国が負担すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. 経済合理性: 社会全体で負担を分散することで、企業倒産リスクを回避し、経済的ショックを最小化できる&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5. 倫理的公正: たまたま被害を受けた場所の所有者だけに負担させることは、偶然性に基づく不正義である&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6. 社会的連帯: 国防の便益は国民全体が享受したのだから、その費用も国民全体で負担すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7. 雇用と地域経済: 数万人の従業員とその家族、周辺地域への影響を考慮すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8. 将来への影響: 人間中心の危機管理の前例として、未来の類似事態への柔軟な対応を可能にする&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;---&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;推奨される具体的措置:&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;1. 特別措置法の制定: 「巨大生物災害対策特別措置法」等を制定し、法的根拠を明確化&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. 予備費・補正予算の活用: 迅速な費用確保と撤去作業の開始&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. 自衛隊・専門機関の協力: 技術的リソースの効率的活用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. 将来の類似事態への備え: 法的・技術的フレームワークの整備&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;---&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;参照情報:&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;MELCHIOR (科学的・技術的):&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;- 分析手法: ISO 31000リスクマネジメント、公共財理論、費用便益分析(CBA)、システム工学的因果分析&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BALTHASAR (法律・倫理的):&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;- 関連法令:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  自衛隊法第3条、国家賠償法第1条、災害対策基本法第2条・第87条、憲法第29条第3項、民法第242条・第709条・第717条&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CASPER (感情・トレンド):&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;- 社会的トレンド: 公共安全への公的責任の重視、被害者への共感文化、雇用保護への関心、前例のない危機への柔軟対応&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;&#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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MAGIシステムの最終判定として、国（政府）が全額負担することを強く推奨します。&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;h3 id=&quot;エージェントの独立性&quot;&gt;エージェントの独立性&lt;&#x2F;h3&gt;
&lt;p&gt;各エージェントは完全に独立して動作します。バックグラウンドで並列実行され、他のエージェントの分析結果を参照することはありません。これにより、以下のメリットがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;多様な視点の確保&lt;&#x2F;li&gt;
&lt;li&gt;偏りの少ない意思決定&lt;&#x2F;li&gt;
&lt;li&gt;各専門分野の独立した評価&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;情報収集能力&quot;&gt;情報収集能力&lt;&#x2F;h3&gt;
&lt;p&gt;各エージェントはWeb検索機能を使って最新の情報を収集します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;MELCHIOR: 技術動向、ベンチマークデータ、研究論文など&lt;&#x2F;li&gt;
&lt;li&gt;BALTHASAR: 法律、規制、判例、ガイドラインなど&lt;&#x2F;li&gt;
&lt;li&gt;CASPER: トレンドレポート、ユーザーレビュー、事例研究など&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;収集した情報は判断の根拠として明示されるため、透明性の高い意思決定プロセスが実現できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;セッション管理&quot;&gt;セッション管理&lt;&#x2F;h3&gt;
&lt;p&gt;オプションで &lt;code&gt;state.json&lt;&#x2F;code&gt; にセッション状態を保存できます。これにより、分析を中断・再開できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;MAGIシステムは、エヴァンゲリオンの架空のシステムを実際のAI技術で再現した興味深い試みです。複数の専門的な視点から独立して分析し、合議制で結論を導くアプローチは、以下のような場面で有用です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;重要なビジネス判断&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;ul&gt;
&lt;p&gt;Claude Code Pluginの仕組みを活用することで、このような複雑なマルチエージェントシステムを比較的容易に実装できることがわかりました。&lt;&#x2F;p&gt;
&lt;p&gt;プラグインのソースコードは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&quot;&gt;GitHubリポジトリ&lt;&#x2F;a&gt;で公開しています。興味のある方はぜひ試してみてください。&lt;&#x2F;p&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;docs.anthropic.com&#x2F;claude&#x2F;docs&#x2F;claude-code&quot;&gt;Claude Code Plugin Documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&quot;&gt;Magi Plugin Repository&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;%E6%96%B0%E4%B8%96%E7%B4%80%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%B3%E3%82%B2%E3%83%AA%E3%82%AA%E3%83%B3&quot;&gt;新世紀エヴァンゲリオン&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">エヴァンゲリオンに登場するMAGIシステムを参考に、複数の専門AIエージェントによる合議制意思決定支援システムをClaude Code Pluginとして実装しました。MELCHIOR、BALTHASAR、CASPERの3つのエージェントが、科学的、法律的、感情的な視点から独立して分析を行い、多数決で結論を導くシステムです。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic Interviewer</title>
        <published>2025-12-07T00:00:00+00:00</published>
        <updated>2025-12-07T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/anthropic-interviewer/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/anthropic-interviewer/</id>
        
            <content type="html">&lt;h2 id=&quot;Anthropic_Interviewerとは&quot;&gt;Anthropic Interviewerとは&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicはClaudeの使用パターンを分析するツール「Clio」を利用して生成AIの利用パターン
などを調査してきました。しかしClioで分かるのは、Claude内で何が起きているかだけで、
Claudeがどう外の世界に影響しているかは分析できていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;ユーザーはClaudeの出力をどう使っているのか？　AIについてどう感じているのか？
これを知るには、Claudeの入出力から分析できず、ユーザーに直接聞くしかありません。&lt;&#x2F;p&gt;
&lt;p&gt;そこでAnthropicは、Claude自身がインタビュアーとなる「Anthropic Interviewer」を開発したということです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;参加方法&quot;&gt;参加方法&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropic Interviewerは、Claude.aiのFree、Pro、Maxサブスクライバー（登録から2週間以上経過）が対象です。
Claude.ai上でポップアップ招待が表示されるか、直接 &lt;code&gt;claude.ai&#x2F;interviewer&lt;&#x2F;code&gt; にアクセスすることで参加できます。&lt;&#x2F;p&gt;
&lt;p&gt;インタビューは約10〜15分で、回答に応じて質問が適応的に変化するリアルタイム会話形式です。
具体的な質問内容は固定されておらず、以下のテーマを探索します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AIの将来的な役割についてのビジョン&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;初期テストでは、参加者の97.6%が満足度5以上（7段階評価）と回答し、99.12%が他者に推奨すると答えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現在のインタビュー結果&quot;&gt;現在のインタビュー結果&lt;&#x2F;h2&gt;
&lt;p&gt;このツールを使って、1,250人にインタビューした結果が、
すでに「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;research&#x2F;anthropic-interviewer&quot;&gt;Introducing Anthropic Interviewer: What 1,250 professionals told us about working with AI&lt;&#x2F;a&gt;」
という記事で公開されています。&lt;&#x2F;p&gt;
&lt;p&gt;この記事によると、このツールを使って、一般労働者1,000人、科学者125人、クリエイター125人の計
1,250人の専門家にインタビューを実施し、AIの使用実態や感情を調査したそうです。&lt;&#x2F;p&gt;
&lt;p&gt;結果として、全体的には楽観的な見方が優勢でした。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;一般労働者の86%が時間節約を実感し、日常的な作業をAIに委任しつつ、専門的アイデンティティを定義する業務は自分で行いたいと考えている&lt;&#x2F;li&gt;
&lt;li&gt;クリエイターは97%が時間節約を報告しているが、仲間からの偏見や経済的置き換えへの不安も抱えている&lt;&#x2F;li&gt;
&lt;li&gt;科学者は論文執筆やコードのデバッグにAIを活用しているが、仮説生成や実験設計などの中核的研究には信頼性の問題からまだ使用を限定している&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;私の生成AI感&quot;&gt;私の生成AI感&lt;&#x2F;h2&gt;
&lt;p&gt;今回15分ほどのインタビューを受けて、改めて自身の生成AIに対する向き合い方を意識できました。&lt;&#x2F;p&gt;
&lt;p&gt;意外だったのは、AIにServant的な役割を期待していないということです。
もちろん、生成AIに作業を代行させて生産性を上げるということはやっていますが、
あまりそこを重視していません。
それどころか、AIロボットのような人間の召使い的な方向で発展するのを極端に嫌悪しているのを初めて自分でも意識しました。&lt;&#x2F;p&gt;
&lt;p&gt;最も活用できる方向として、自分と同等以上の知識と論理性を持った「ディスカッション相手」としての生成AIだと意識できました。
自分を生成AIとの会話から新しいアイデアに辿り着いた体験が何度かあり、それが一番衝撃的だったので影響されているのだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;人間にDVを受けるロボットより、バベルの塔のマザーコンピューター&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;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;『バビル2世』に登場するコンピューターです。5000年前、地球に不時着した宇宙人「バビル1世」が建造した「バベルの塔」を管理する超高性能電子頭脳です。自然言語で話し
バビル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">昨日Claudeに「Anthropic Interviewerに参加しませんか？」と見慣れぬポップアップが表示されました。回答していくと、生成AIであるClaudeに生成AIの活用方法や将来の役割をインタビューされるという奇妙な体験でした。</summary>
        </entry><entry xml:lang="en">
        <title>React Server Components RCE脆弱性（CVE-2025-55182）への対応記録</title>
        <published>2025-12-06T00:00:00+00:00</published>
        <updated>2025-12-06T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/react-nextjs-cve-2025-55182-response/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/react-nextjs-cve-2025-55182-response/</id>
        
            <content type="html">&lt;h2 id=&quot;脆弱性の概要&quot;&gt;脆弱性の概要&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;CVE-2025-55182とは&quot;&gt;CVE-2025-55182とは&lt;&#x2F;h3&gt;
&lt;p&gt;CVE-2025-55182は、React 19のServer Components（RSC）における「Flight」プロトコルの安全でないデシリアライゼーション（deserialize）に起因する脆弱性です。
主な特徴は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVSSスコア: 10.0（最大値）&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;影響範囲: React 19.0.0、19.1.0、19.1.1、19.2.0&lt;&#x2F;li&gt;
&lt;li&gt;攻撃条件: 認証不要、細工されたHTTPリクエストのみで実行可能&lt;&#x2F;li&gt;
&lt;li&gt;デフォルト設定で脆弱: &lt;code&gt;create-next-app&lt;&#x2F;code&gt;により作成した標準的なNext.jsアプリケーションが影響を受ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;技術的な仕組み&quot;&gt;技術的な仕組み&lt;&#x2F;h3&gt;
&lt;p&gt;この脆弱性は、RSCの内部通信プロトコルである「Flight」の処理において、攻撃者の制御可能なデータを適切な検証なしにデシリアライズしてしまうことに起因します。攻撃者からペイロードを含むHTTPリクエストが送信されると、サーバー側ではこれをFlightプロトコルのデータとして処理し、検証なしにデシリアライズします。この結果、任意のコードを実行される可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、この処理がアプリケーションの認証ロジックより前、つまりMiddlewareでの保護より深い層で行われるため、通常の認証機構では防げないという点です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;CVE番号の統合経緯&quot;&gt;CVE番号の統合経緯&lt;&#x2F;h2&gt;
&lt;p&gt;2025年12月3日時点では、以下の2つのCVE番号で追跡されていました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVE-2025-55182&lt;&#x2F;strong&gt;: React Server Componentsの脆弱性&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CVE-2025-66478&lt;&#x2F;strong&gt;: Next.jsの脆弱性&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;調査の結果、Next.jsの脆弱性は実質的にReactの脆弱性に起因することが判明し、&lt;strong&gt;CVE-2025-66478は重複として却下&lt;&#x2F;strong&gt;されました。現在は&lt;strong&gt;CVE-2025-55182&lt;&#x2F;strong&gt;に統合されています。&lt;&#x2F;p&gt;
&lt;p&gt;この経緯は、脆弱性の根本原因がReactのRSC実装そのものにあり、Next.jsはその影響を受けていたに過ぎないことを示しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;影響を受けるバージョンと修正版&quot;&gt;影響を受けるバージョンと修正版&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;React_&#x2F;_React-dom&quot;&gt;React &#x2F; React-dom&lt;&#x2F;h3&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;19.0.0&lt;&#x2F;td&gt;&lt;td&gt;19.0.1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;19.1.0, 19.1.1&lt;&#x2F;td&gt;&lt;td&gt;19.1.2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;19.2.0&lt;&#x2F;td&gt;&lt;td&gt;19.2.1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;Next.js&quot;&gt;Next.js&lt;&#x2F;h3&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;15.x（全般）&lt;&#x2F;td&gt;&lt;td&gt;15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;16.x（全般）&lt;&#x2F;td&gt;&lt;td&gt;16.0.7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;14.3.0-canary.77以降&lt;&#x2F;td&gt;&lt;td&gt;（14.x Stable版は影響なし）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;注&lt;&#x2F;strong&gt;: Next.js 13.x、14.x stable版、Pages Router、Edge Runtimeは影響を受けません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;実際の攻撃状況&quot;&gt;実際の攻撃状況&lt;&#x2F;h2&gt;
&lt;p&gt;この脆弱性は公表直後から実際に悪用されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;2025年12月3日: 脆弱性が公表される&lt;&#x2F;li&gt;
&lt;li&gt;同日中: 中国関連の脅威グループによる大規模な攻撃活動が観測される&lt;&#x2F;li&gt;
&lt;li&gt;2025年12月5日午前6時（UTC）以降: Wizのセンサーが複数の被害者を検知&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この脆弱性は「React2Shell」または「React4Shell」という名称でも呼ばれ、既に実証コード（PoC）が公開されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;当ブログでの対応状況&quot;&gt;当ブログでの対応状況&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;対応タイムライン&quot;&gt;対応タイムライン&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2025年12月3日&lt;&#x2F;strong&gt;: CVE-2025-55182が公表される&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;2025年12月5日&lt;&#x2F;strong&gt;: 当ブログで修正版へのアップデート実施（v1.7.1）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;実施した対応&quot;&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;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;React:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.2.1&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;React-dom:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.2.1&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;Next.js:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.2.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.5.7&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;@next&#x2F;mdx:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.2.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.5.7&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;eslint-config-next:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.2.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.5.7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;当ブログは&lt;strong&gt;CVE-2025-55182に完全対応済み&lt;&#x2F;strong&gt;であり、この脆弱性の影響を受けない安全な状態です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;推奨される対応&quot;&gt;推奨される対応&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsやReactを使用しているプロジェクトをお持ちの方は、以下の対応を推奨します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1._バージョンの確認&quot;&gt;1. バージョンの確認&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;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; list next react react-dom&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._修正版へのアップデート&quot;&gt;2. 修正版へのアップデート&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;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;# npm の場合&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 next@latest react@latest react-dom@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;# yarn の場合&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;yarn&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; add next@latest react@latest react-dom@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;# pnpm の場合&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;pnpm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; add next@latest react@latest react-dom@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3._内部依存関係の確認&quot;&gt;3. 内部依存関係の確認&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;&#x2F;code&gt;だけでなく、ロックファイル（&lt;code&gt;package-lock.json&lt;&#x2F;code&gt;、&lt;code&gt;yarn.lock&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;# ロックファイル内のReactバージョンを確認&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;grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -A5 &amp;#39;&amp;quot;react&amp;quot;:&amp;#39; package-lock.json&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;grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -A5 &amp;#39;&amp;quot;next&amp;quot;:&amp;#39; package-lock.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;4._デプロイ&quot;&gt;4. デプロイ&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;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; run build&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;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;CVE-2025-55182は、React Server Componentsの根本的な脆弱性であり、
&lt;strong&gt;CVSS 10.0&lt;&#x2F;strong&gt;という最大の深刻度を持つ重大な問題です。デフォルト設定で脆弱であり、認証を回避して攻撃可能という特性から、速やかな対応が必要です。&lt;&#x2F;p&gt;
&lt;p&gt;当ブログでは公表から2日以内に対応を完了しましたが、既に実際の攻撃が観測されているため、まだ対応されていない方は最優先で対応することを強く推奨します。&lt;&#x2F;p&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;react.dev&#x2F;blog&#x2F;2025&#x2F;12&#x2F;03&#x2F;critical-security-vulnerability-in-react-server-components&quot;&gt;Critical Security Vulnerability in React Server Components – React&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nextjs.org&#x2F;blog&#x2F;CVE-2025-66478&quot;&gt;Security Advisory: CVE-2025-66478 | Next.js&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.wiz.io&#x2F;blog&#x2F;critical-vulnerability-in-react-cve-2025-55182&quot;&gt;Critical RCE Vulnerabilities Discovered in React &amp;amp; Next.js | Wiz Blog&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;unit42.paloaltonetworks.com&#x2F;cve-2025-55182-react-and-cve-2025-66478-next&#x2F;&quot;&gt;Critical Vulnerabilities in React Server Components and Next.js&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nvd.nist.gov&#x2F;vuln&#x2F;detail&#x2F;CVE-2025-55182&quot;&gt;NVD - CVE-2025-55182&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">2025年12月3日、React Server Components（RSC）とNext.jsにおいて、認証不要でリモートコード実行（RCE）が可能となる重大な脆弱性が公表されました。この記事では、この脆弱性の深刻度、CVE番号の統合経緯、そして当ブログでの対応状況について記録します。</summary>
        </entry><entry xml:lang="en">
        <title>GitHub Actionsでnpmパッケージ公開を自動化する - Trusted Publishingで実現するトークンレス運用</title>
        <published>2025-12-05T00:00:00+00:00</published>
        <updated>2025-12-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/automating-npm-publish-with-github-actions/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/automating-npm-publish-with-github-actions/</id>
        
            <content type="html">&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;パッケージで実装した、
GitHubが発表した&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.blog&#x2F;changelog&#x2F;2025-09-29-strengthening-npm-security-important-changes-to-authentication-and-token-management&#x2F;&quot;&gt;npmの認証強化&lt;&#x2F;a&gt;
対応の
Trusted Publishing (OIDC) を使用したトークン管理不要の自動公開について記載しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;npmの認証変更の背景&quot;&gt;npmの認証変更の背景&lt;&#x2F;h2&gt;
&lt;p&gt;GitHubは2025年9月29日に、npmのセキュリティ強化として以下の変更を発表しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Classic Access Tokenの廃止&lt;&#x2F;li&gt;
&lt;li&gt;Trusted Publishing (OIDC) またはGranular Access Tokenへの移行推奨&lt;&#x2F;li&gt;
&lt;li&gt;より細かい権限管理の実現&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;移行先として2つの選択肢があります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Granular Access Token&lt;&#x2F;li&gt;
&lt;li&gt;Trusted Publishing (OIDC)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Granular Access Tokenは、従来のトークン方式を改良したものでパッケージごとの権限管理が可能となっていますが、定期的なトークンのローテーションが必要です。
Trusted Publishingはトークンを完全に排除した新しい認証方式で、公開を自動化しトークンを完全に排除したものです。&lt;&#x2F;p&gt;
&lt;p&gt;jrnl-mcpでは、トークン管理の手間を完全に排除できる &lt;strong&gt;Trusted Publishing&lt;&#x2F;strong&gt; を採用しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自動公開の仕組み&quot;&gt;自動公開の仕組み&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;全体のフロー&quot;&gt;全体のフロー&lt;&#x2F;h3&gt;
&lt;p&gt;jrnl-mcpでは、以下のフローで自動公開を実現しています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;GitHubでリリースを作成&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Actionsが自動起動&lt;&#x2F;li&gt;
&lt;li&gt;依存関係のインストールとテストを実行&lt;&#x2F;li&gt;
&lt;li&gt;npmへ自動公開&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;この仕組みにより、リリース作成だけでパッケージの公開が完了します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;GitHub_Actionsの設定&quot;&gt;GitHub Actionsの設定&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;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&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-string&quot;&gt; Publish to npm&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-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  release&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    types&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-string&quot;&gt;published&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-entity z-name z-tag z-yaml&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  contents&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-string&quot;&gt; read&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-tag z-yaml&quot;&gt;  id-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-string&quot;&gt; write&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-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  publish&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    runs-on&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-string&quot;&gt; ubuntu-latest&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-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Checkout code&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-tag z-yaml&quot;&gt;        uses&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-string&quot;&gt; actions&#x2F;checkout@v4&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Setup Node.js&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-tag z-yaml&quot;&gt;        uses&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-string&quot;&gt; actions&#x2F;setup-node@v4&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-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          node-version&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 z-definition z-string z-string&quot;&gt; &amp;quot;20&amp;quot;&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-tag z-yaml&quot;&gt;          registry-url&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 z-definition z-string z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;registry.npmjs.org&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Install dependencies&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-tag z-yaml&quot;&gt;        run&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-string&quot;&gt; npm ci&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Run tests&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-tag z-yaml&quot;&gt;        run&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-string&quot;&gt; npm run test:ci&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Publish to npm&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-tag z-yaml&quot;&gt;        run&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-string&quot;&gt; npm publish --provenance --access public&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;重要なポイントは、&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;GitHubのリリース機能を使用することで、手動でのトリガーが可能になる。これにより、意図しないタイミングでの公開を防ぐ。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;permissions&lt;&#x2F;code&gt;の設定により、GitHub Actionsはnpmに対して一時的なOIDCトークンを発行・認証する。長期的なトークンをSecretに保存する必要がない。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;npm publish --provenance --access public&lt;&#x2F;code&gt;により自動的にprovenance（出所証明）が生成され、パッケージがどのリポジトリから公開されたか検証可能となる。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;npm run test:ci&lt;&#x2F;code&gt;により公開前のテストを自動化する。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;Trusted_Publishing_の設定方法&quot;&gt;Trusted Publishing の設定方法&lt;&#x2F;h2&gt;
&lt;p&gt;Trusted Publishingを使用する場合、npm側での設定が必要です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1._npm_でパッケージを公開&quot;&gt;1. npm でパッケージを公開&lt;&#x2F;h3&gt;
&lt;p&gt;まず、通常の方法で初回のパッケージを公開します（トークンを使用）。npm側でパッケージが存在している必要があるためです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2._npm_で_Trusted_Publishing_を設定&quot;&gt;2. npm で Trusted Publishing を設定&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.npmjs.com&#x2F;&quot;&gt;npm のパッケージ設定&lt;&#x2F;a&gt;にアクセス&lt;&#x2F;li&gt;
&lt;li&gt;公開したパッケージの&quot;Settings&quot;タブを開く&lt;&#x2F;li&gt;
&lt;li&gt;&quot;Publishing access&quot;セクションで&quot;Add a publisher&quot;を選択&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Actionsを選択し、以下を設定する
&lt;ul&gt;
&lt;li&gt;Repository: &lt;code&gt;&amp;lt;username&amp;gt;&#x2F;&amp;lt;repository-name&amp;gt;&lt;&#x2F;code&gt;（例: &lt;code&gt;yostos&#x2F;jrnl-mcp&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;Workflow: ワークフローファイル名（例: &lt;code&gt;publish.yml&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;Environment: 未指定（デフォルト）または特定の環境名&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;3._GitHub_Actions_の設定&quot;&gt;3. GitHub Actions の設定&lt;&#x2F;h3&gt;
&lt;p&gt;前述のワークフロー設定で、&lt;code&gt;id-token: write&lt;&#x2F;code&gt; 権限を付与するだけで完了です。トークンをSecretに保存する必要はありません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;トークンベースとの比較&quot;&gt;トークンベースとの比較&lt;&#x2F;h3&gt;
&lt;p&gt;Trusted Publishingを使用することで、以下の作業が不要になります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;npmトークンの作成と保存&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Secretsへのトークン登録&lt;&#x2F;li&gt;
&lt;li&gt;トークンの定期的なローテーション（Granular Access Tokenの場合、最大90日ごと）&lt;&#x2F;li&gt;
&lt;li&gt;トークン漏洩のリスク管理&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Trusted Publishing (OIDC) とGitHub Actionsを使用したnpmパッケージの自動公開により、以下のメリットが得られました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;公開作業の効率化&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;li&gt;透明性の確保（自動provenance生成）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に、Trusted Publishingの導入により、トークンの定期的なローテーションや漏洩リスクの心配が不要になり、セキュリティと運用性が大幅に向上しました。npmパッケージを公開している方は、ぜひTrusted Publishingへの移行とGitHub Actionsによる自動化を検討してみてください。&lt;&#x2F;p&gt;
&lt;p&gt;Granular Access Tokenでもセキュリティは向上しますが、定期的なローテーション（最大90日ごと）が必要なため、可能であればTrusted Publishingの使用を推奨します。&lt;&#x2F;p&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;github.blog&#x2F;changelog&#x2F;2025-09-29-strengthening-npm-security-important-changes-to-authentication-and-token-management&#x2F;&quot;&gt;Strengthening npm security: Important changes to authentication and token management&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;jrnl-mcp&quot;&gt;jrnl-mcp GitHub Repository&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.npmjs.com&#x2F;about-access-tokens&quot;&gt;npm Documentation: About access tokens&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">npm パッケージの公開を手動で行っていると、毎回トークンの管理やビルド、テストの実行など煩雑な作業が発生します。また、2025 年 9 月 29 日に GitHub が発表したnpmの認証強化により、Classic Token の廃止と、Trusted Publishing または Granular Access Token への移行が必要になりました。Trusted Publishing (OIDC) を使ってトークン管理不要のセキュアな公開フローを構築した手順を解説します。</summary>
        </entry><entry xml:lang="en">
        <title>技術無知が経営リスクになった理由</title>
        <published>2025-11-08T00:00:00+00:00</published>
        <updated>2025-11-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability-ja/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability-ja/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;11&amp;#x2F;tech-ignorance-is-business-liability-ja&amp;#x2F;noitdept.webp?h=074677f7f792dfd9f5b2&quot;
  alt=&quot;No IT dept&quot; width=&quot;1456&quot; height=&quot;816&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;h2 id=&quot;業務システム台帳とは何か&quot;&gt;業務システム台帳とは何か&lt;&#x2F;h2&gt;
&lt;p&gt;「業務システム台帳」とは、組織が所有する業務システムを記録し、一覧化する台帳です。重要なのは、各システムの内部構造や技術的な詳細を管理するものではないということです。&lt;&#x2F;p&gt;
&lt;p&gt;具体的には、台帳にはシステムの以下のような基本的な属性を記録します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;システム名。組織内で一意に識別できる名称(例。財務システム、販売管理システム、人事管理システム)&lt;&#x2F;li&gt;
&lt;li&gt;業務プロセス。システムがサポートする業務プロセスの名称。これにより、システムが組織にどのような価値を提供しているかが可視化される。前提として、組織が業務プロセスの台帳も整備していることが望ましい&lt;&#x2F;li&gt;
&lt;li&gt;業務プロセスオーナー。これも重要な属性である。システムの責任者が誰で、予算を管理しているかが明確になる。これがないと、システムに関する意思決定やライフサイクル管理が曖昧になる&lt;&#x2F;li&gt;
&lt;li&gt;重要度。システムが事業継続計画(BCP)の対象となる重要システムなのか、停止しても業務への影響が限定的なシステムなのかを分類する。リスク管理や投資の優先順位を決定するために不可欠な情報である&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;業務システム台帳は、ITガバナンスの最も基本的な構成要素です。組織が自分の所有物を理解していなければ、適切な投資判断、リスク管理、コスト最適化は始まりません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;業務システム台帳の重要性&quot;&gt;業務システム台帳の重要性&lt;&#x2F;h2&gt;
&lt;p&gt;近年、ランサムウェアに攻撃される企業が増えています。ランサムウェアはシステムとデータを暗号化し、業務を数ヶ月にわたって停止させます。このような危機的状況において、業務システム台帳が存在しなかったらどうなるでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;何が破壊され、何を復旧すべきかを誰も把握できません。どのシステムが業務にとって最も重要でしょうか。各システムのデータバックアップはどこにあるのでしょうか。そもそも組織全体でいくつのシステムが稼働していたのでしょうか。この基本的な情報がなければ、復旧作業は極めて混乱し、事業再開は大幅に遅れることになります。業務システム台帳は危機管理のための最も基本的なインフラです。&lt;&#x2F;p&gt;
&lt;p&gt;もう1つの重要な側面は、会計要件に起因します。請負契約で開発されたシステムは無形固定資産として減価償却する必要があり、運用段階での機能強化も資産計上の対象となります。しかし、会計資産台帳だけでは、どの機能強化が資産計上に値するかといった業務システム固有の判断は難しいです。会計資産台帳と整合性のとれた業務システム台帳が必要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜ組織は業務システム台帳を維持できないのか&quot;&gt;なぜ組織は業務システム台帳を維持できないのか&lt;&#x2F;h2&gt;
&lt;p&gt;多くの組織は他社の災害を目撃し、危機感に駆られて台帳の整備を始めます。しかし、ほとんどの場合、台帳は作成された瞬間から忘れ去られ、やがて古くなり、闇に葬られます。&lt;&#x2F;p&gt;
&lt;p&gt;例えば、ある部門が独自にシステムを調達したが、台帳には登録されません。別のシステムは対応する業務プロセスを拡大するために大規模な機能強化を行ったが、台帳には反映されません。このようにして、台帳は徐々に現実と乖離し、役に立たなくなり、最終的には廃棄されます。&lt;&#x2F;p&gt;
&lt;p&gt;なぜこのようなことが起こるのでしょうか。マーフィーの法則は「うまくいかなくなる可能性のあることは、うまくいかなくなる」と述べています。しかも、我々はITガバナンスの確立に失敗した機能不全の組織について語っているのです。そのような組織において、人々の善意と勤勉さに頼る運用は、いずれ必ず失敗します。&lt;&#x2F;p&gt;
&lt;p&gt;では、どうすれば台帳を維持できるのでしょうか。鍵は金の流れです。部門のシステム調達も、大規模なシステム強化も、必ず金銭取引を伴います。この金の流れを捕捉できれば、台帳の変更を見逃さないトリガーとして利用できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;業務システム台帳を維持する仕組み&quot;&gt;業務システム台帳を維持する仕組み&lt;&#x2F;h2&gt;
&lt;p&gt;前節で述べたように、鍵は金の流れを捕捉することです。業務システムに関連する財務プロセスは、予算編成、支出(調達)、固定資産会計の3つです。これらのプロセスに台帳の更新を組み込むことで、台帳を自動的に維持する仕組みを確立できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;予算編成&quot;&gt;予算編成&lt;&#x2F;h3&gt;
&lt;p&gt;業務システムを運用または変更するには予算編成が必要です。一般的に、予算は予算コード(勘定科目コード)と予算額で管理されます。したがって、予算編成プロセスでは以下の2つが必要です。&lt;&#x2F;p&gt;
&lt;p&gt;予算が業務システムに関連する場合、業務システム台帳のレコードとリンクさせなければなりません。この段階で業務システムが業務システム台帳に登録されていない場合は、新しいシステムとみなし、台帳に追加しなければなりません。このようにして、台帳にないシステムへの予算編成を防ぐことができます。&lt;&#x2F;p&gt;
&lt;p&gt;次に、予算編成プロセスの完了時に、運用中または運用予定のすべての業務システムに予算が配分されているかを確認します。予算が割り当てられていないにもかかわらず稼働している運用業務システムのオーナーには、予算配分を義務付けます。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、台帳を維持するために台帳の更新を要求するのではなく、台帳と整合性がとれていなければ予算処理を完了できない仕組みを組み込むことです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;支出(調達)&quot;&gt;支出(調達)&lt;&#x2F;h3&gt;
&lt;p&gt;業務システムの導入、変更、保守には必ず支出が発生します。IT部門が確立されていない組織では、これらの支出は通常、調達部門または経理部門を通じて処理されます。この調達プロセス自体が、台帳を維持するための最も信頼できるトリガーとなります。&lt;&#x2F;p&gt;
&lt;p&gt;業務システムに関連する発注や契約は、どの予算に紐づいているかで識別できるはずです。業務システムに関連すると識別された調達については、発注時と納品時の両方で業務システム台帳とのリンクと整合性を確保することを義務付けるべきです。これにより、「部門が独自にシステムを調達したが、台帳には追加されなかった」といった失敗パターンを防ぐことができます。&lt;&#x2F;p&gt;
&lt;p&gt;調達プロセスに台帳の整合性チェックを組み込むことで、多くの企業はこのチェックを迂回した調達を逸脱、つまり「BYPASS」として扱い、要求部門にペナルティを課します。将来的には、これらのチェックは組織のITガバナンスフレームワークの一部としても機能し、導入されるシステムが組織の意図するアーキテクチャに合致しているかを確認するレビューポイントとしても機能します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;固定資産会計&quot;&gt;固定資産会計&lt;&#x2F;h3&gt;
&lt;p&gt;請負契約で開発された業務システムは、組織の無形固定資産として記録され、減価償却の対象となります。SaaSなどのサービスベースの契約は資産として計上されませんが、発注・納品されるシステムは会計上も適切に管理しなければなりません。&lt;&#x2F;p&gt;
&lt;p&gt;IT部門がない組織では「引き渡し」を捕捉するプロセスがないため、納品時に無形固定資産台帳の更新と業務システム台帳の更新をリンクさせる仕組みが不可欠です。システムオーナーは、機能強化が資産計上に値するかを判断し、経理部門に台帳の更新を依頼しなければなりません。この整合性チェックが完了するまで検収を完了できないようなプロセスを設計することで、両方の台帳が確実に更新されます。&lt;&#x2F;p&gt;
&lt;p&gt;この仕組みには2つの効果があります。組織の会計実務が正確であれば、無形固定資産台帳には資産計上が必要なすべてのシステムが正しく記録されているはずです。この台帳との整合性を維持することで、業務システム台帳の信頼性が高まります。逆に、会計実務が不正確な場合、業務システム台帳との整合性を確保する仕組みを確立することで、不適切な会計処理を防ぐことができます。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、この整合性チェックを検収プロセスに組み込むことで、人間の善意に依存することなく、両方の台帳が確実に維持されることです。この検証なしには検収を完了できないようにすれば、更新は標準的なワークフローの一部として自動的に行われます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;結論&quot;&gt;結論&lt;&#x2F;h2&gt;
&lt;p&gt;業務システム台帳すら整備していない組織は、たとえ危機感に駆られて作成したとしても、それを維持できません。作成した瞬間から劣化し始めることは明らかです。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、それを維持する仕組みです。金の流れに伴う避けられないプロセス、すなわち予算、調達、会計に、台帳を更新・維持する仕組みを組み込むことが重要です。&lt;&#x2F;p&gt;
&lt;p&gt;逆に言えば、この仕組みを確立するだけで、ITガバナンスへの第一歩を踏み出すことができます。難しいことではありません。システムに関連する金の流れを捕捉すればよいだけです。それすらできないのであれば、あなたの組織はITガバナンス以前にコーポレートガバナンスの基本すら備わっていません。まあ、そうなのでしょうけれど。&lt;&#x2F;p&gt;
</content>
        <summary type="html">この記事はIT部門を持たず、非技術部門だけでベンダーに作らせた業務システムを所有し運用している組織について想定しています。きっとランサムウェアで危機に見舞われているアサヒビールやアスクルを見て震え上がって、何をすればいいか焦っている組織も多いと思います。そんな組織が行なうべき第一歩として業務システム台帳の整備について解説しています。</summary>
        </entry><entry xml:lang="en">
        <title>Because Your Tech Ignorance Is Now a Business Liability</title>
        <published>2025-11-08T00:00:00+00:00</published>
        <updated>2025-11-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;11&amp;#x2F;tech-ignorance-is-business-liability&amp;#x2F;noitdept.webp?h=074677f7f792dfd9f5b2&quot;
  alt=&quot;No IT dept&quot; width=&quot;1456&quot; height=&quot;816&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;h2 id=&quot;What_is_Application_System_Inventory?&quot;&gt;What is Application System Inventory?&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;Application System Inventory&quot; is an inventory that records and keeps a list of application systems the organization owns. The important point is that it does not manage the internal structure of each system or technical details.&lt;&#x2F;p&gt;
&lt;p&gt;More specifically, the inventory stores the following basic attributes of systems.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;System Name: A name that can be uniquely identified within the organization (e.g. Finance System, Sales Management System, Human Resource Management System).&lt;&#x2F;li&gt;
&lt;li&gt;Business Process: A name of the business process that the system supports. This makes visible what kind of value the system provides to the organization. As a prerequisite, it is desirable that the organization also maintains an inventory of its business processes.&lt;&#x2F;li&gt;
&lt;li&gt;Business Process Owner: This is also an important attribute. This clarifies who is responsible for the system and manages the budget for it. Without this, decision-making and life-cycle management for the system become ambiguous.&lt;&#x2F;li&gt;
&lt;li&gt;Importance: This classifies whether the system is a critical system that is subject to Business Continuity Planning(BCP), or a system whose impact on business operations is limited even if it stops. This is essential information for risk management and determining investment priorities.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Application System Inventory is the most fundamental component of IT governance. If the organization doesn&#x27;t understand what it owns, appropriate investment decisions, risk management, and cost optimization cannot begin.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Why_Application_System_Inventory_Is_Important&quot;&gt;Why Application System Inventory Is Important&lt;&#x2F;h2&gt;
&lt;p&gt;In recent months, an increasing number of enterprises have been attacked by ransomware. The ransomware encrypts their systems and data, disrupting business operations for several months. In such critical situations, what happens if Application System Inventory does not exist?&lt;&#x2F;p&gt;
&lt;p&gt;No one would be able to understand what has been destroyed and what should be restored. Which systems are most critical for business operations? Where are the data backups for each system located? How many systems were operating across the organization in the first place? Without this basic information, recovery efforts would become extremely chaotic, and business resumption would be significantly delayed. Application System Inventory is the most fundamental infrastructure for crisis management.&lt;&#x2F;p&gt;
&lt;p&gt;Another important aspect is driven by accounting requirements.
Systems developed under a work contract (&quot;Ukeoi&quot; contract)
need to be depreciated as intangible fixed assets.
Functional enhancements during the operational phase are also
subject to capitalization. However, with only the accounting
asset ledger, it is difficult to make judgments specific to
Application Systems, such as which functional enhancements
warrant capitalization. An Application System Inventory that
is aligned with the accounting asset ledger is necessary.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Why_Organizations_Cannot_Maintain_Application_System_Inventory&quot;&gt;Why Organizations Cannot Maintain Application System Inventory&lt;&#x2F;h2&gt;
&lt;p&gt;Many organizations witness other companies&#x27; disasters and begin to establish their Inventory, driven by a sense of crisis. However, in most cases, the inventory is forgotten from the moment it is created and eventually becomes outdated and buried in the darkness.&lt;&#x2F;p&gt;
&lt;p&gt;For example, a department procures a system independently, but it is not registered in the inventory. Another system undergoes major enhancements to expand the business processes it supports, but this is not reflected in the inventory. In this way, the inventory gradually diverges from reality, becomes useless, and is eventually discarded.&lt;&#x2F;p&gt;
&lt;p&gt;Why does this happen? Murphy&#x27;s Law states, &quot;Anything that can go wrong will go wrong.&quot; Moreover, we are talking about dysfunctional organizations that have failed to establish IT Governance. Operations that rely on the goodwill and diligence of people in such organizations are bound to fail at some point.&lt;&#x2F;p&gt;
&lt;p&gt;So how can we maintain the Inventory? The key is the flow of money. Both departmental system procurement and major system enhancements are always accompanied by financial transactions. If you can capture this flow of money, you can use it as a trigger that won&#x27;t miss changes to the Inventory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Mechanism_to_Maintain_Application_System_Inventory&quot;&gt;The Mechanism to Maintain Application System Inventory&lt;&#x2F;h2&gt;
&lt;p&gt;As described in the previous section, the key is to capture the flow of money. There are three financial processes related to Application System: budgeting, expenditure(procurement), and fixed asset accounting. By incorporating Inventory updates into these processes, you can establish a mechanism to maintain the Inventory automatically.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Budgeting&quot;&gt;Budgeting&lt;&#x2F;h3&gt;
&lt;p&gt;Budgeting must be done for operating or modifying an Application System. Generally, budgets are managed using budget codes or account codes, along with budget amounts. Therefore, the following two things are required during the budgeting process:&lt;&#x2F;p&gt;
&lt;p&gt;If the budget is related to Application System, it must be linked to a record in the Application System Inventory. If, at this stage, the Application System isn&#x27;t registered in the Application System Inventory, it must be considered a new system and should be added to the inventory as such. In this way, you can prevent budgeting for systems that are not in the Inventory.&lt;&#x2F;p&gt;
&lt;p&gt;Next, at the completion of the budgeting process, you verify whether some budget has been allocated to all Application Systems that are either operational or planned to be operational. You mandate budget allocation for the owners of operational application systems that are running despite not having an assigned budget.&lt;&#x2F;p&gt;
&lt;p&gt;The important point is not to require Inventory updates to maintain it, but to incorporate a mechanism in which budget processing cannot be completed without being consistent with the Inventory.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Expenditure(Procurement)&quot;&gt;Expenditure(Procurement)&lt;&#x2F;h3&gt;
&lt;p&gt;The introduction, modification, and maintenance of Application Systems always incur expenditures. In organizations without an established IT department, these expenditures are typically processed through the procurement or accounting departments. This procurement process itself becomes the most reliable trigger for maintaining the Inventory.&lt;&#x2F;p&gt;
&lt;p&gt;Orders and contracts related to Application Systems should be
identifiable based on which budget they are tied to.&lt;&#x2F;p&gt;
&lt;p&gt;For procurements related to Application Systems,
it should be mandatory to ensure linkage and consistency
with the Application System Inventory.
This applies both at the time of ordering and at delivery.
This prevents failure patterns such as
&quot;a department independently procured a system, but it was
never added to the Inventory.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;By embedding an Inventory consistency check within the
procurement process, many companies treat any procurement
that bypasses this check as a deviation—a &quot;BYPASS&quot;.
They impose penalties on the requesting department.&lt;&#x2F;p&gt;
&lt;p&gt;In the future, these checks will also function as part of
the organization&#x27;s IT Governance framework. They serve as a
review point to verify whether systems being introduced
align with the organization&#x27;s intended architecture.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Fixed_Asset_Accounting&quot;&gt;Fixed Asset Accounting&lt;&#x2F;h3&gt;
&lt;p&gt;Application Systems developed under contract should be recorded as intangible fixed assets of the organization and are subject to depreciation. Service-based agreements such as SaaS are not capitalized as assets, but systems that are ordered and delivered must still be properly managed from an accounting perspective.&lt;&#x2F;p&gt;
&lt;p&gt;In organizations without an IT department, there is no
&quot;handover&quot; capture process. Therefore, a mechanism that links
the update of the intangible fixed asset ledger with the
Application System Inventory upon delivery is essential.
The system owner must determine whether a functional
enhancement qualifies for capitalization and request the
accounting department to update the ledger. By designing
a process that prevents acceptance until this consistency
check is completed, both ledgers are reliably updated.&lt;&#x2F;p&gt;
&lt;p&gt;This mechanism has two effects. If the organization&#x27;s accounting practices are accurate, the intangible fixed asset ledger should correctly record all systems that need to be capitalized. Maintaining consistency with this ledger enhances the reliability of the Application System Inventory. Conversely, if accounting practices are inaccurate, establishing a mechanism to ensure consistency with the Application System Inventory helps prevent improper accounting treatments.&lt;&#x2F;p&gt;
&lt;p&gt;Crucially, embedding this consistency check into the acceptance process ensures that both ledgers are maintained reliably without depending on human goodwill. When acceptance cannot be completed without this verification, the updates happen automatically as part of the standard workflow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Organizations that have not even established an Application System Inventory, even if driven by a sense of crisis to create one, will not be able to maintain it. It is clear that it will start to decay from the moment it is created.&lt;&#x2F;p&gt;
&lt;p&gt;What matters is the mechanism to maintain it. It is important to embed the mechanism for updating and maintaining the Inventory into the unavoidable processes that accompany the flow of money: budget, procurement, and accounting.&lt;&#x2F;p&gt;
&lt;p&gt;Conversely, if you simply establish this mechanism, you can take the first step toward IT governance. It is not difficult. You just need to capture the flow of money related to systems. If you cannot even do that, your organization does not have the fundamentals of corporate governance in place even before considering IT governance—though that is likely the case.&lt;&#x2F;p&gt;
</content>
        <summary type="html">この記事はIT部門を持たず、非技術部門だけでベンダーに作らせた業務システムを所有し運用している組織について想定しています。きっとランサムウェアで危機に見舞われているアサヒビールやアスクルを見て震え上がって、何をすればいいか焦っている組織も多いと思います。そんな組織が行なうべき第一歩として業務システム台帳の整備について解説しています。</summary>
        </entry><entry xml:lang="en">
        <title>OpenAI Chairman Says a Dot-Com-Like Bust Wouldn’t Be All Bad</title>
        <published>2025-10-31T00:00:00+00:00</published>
        <updated>2025-10-31T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/10/dot-com-like-bust/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/10/dot-com-like-bust/</id>
        
            <content type="html">&lt;p&gt;「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.bloomberglaw.com&#x2F;artificial-intelligence&#x2F;openai-chairman-says-a-dot-com-like-bust-wouldnt-be-all-bad&quot;&gt;OpenAI Chairman Says a Dot-Com-Like Bust Wouldn’t Be All Bad&lt;&#x2F;a&gt;」&lt;&#x2F;p&gt;
&lt;p&gt;Bloombergに掲載されたOpenAI会長Bret Taylorのインタビュー記事です。&lt;&#x2F;p&gt;
&lt;p&gt;今の生成AIブームを2000年代のドットコム・バブルと重ねて、
バブルが崩壊したとしてもそこからGoogleやAmazonのような企業が
生まれ生き残り次の世代の主役になったことを考えると、健全だと語っています。&lt;&#x2F;p&gt;
&lt;p&gt;確かに今年のノーベル経済学賞を受賞した「アギヨン・ホーウィット理論」
でも「創造的破壊」が経済発展を齎すことを数学モデルで証明しています。
この理論からも、バブル崩壊が必ずしも悪いことではないと言えるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;翻って日本の現状を見ると、国や自治体が補助金や支援策で会社を潰さないよう延命させる政策が当然のように行われています。
しかし、この理論に従うと、これは「創造的破壊」を阻害し、経済の新陳代謝を妨げる決定的に間違った政策です。
非効率な企業を温存することで、本来そこに投入されるべきリソース（人材、資金、土地）が、
より生産性の高い新興企業や成長分野に回らない。この硬直化が日本経済の停滞の一因となっています。&lt;&#x2F;p&gt;
&lt;p&gt;また、Taylor氏が指摘する&lt;strong&gt;上司や取締役を喜ばせるための見かけ倒しの AI プロジェクトはやめるべきだ&lt;&#x2F;strong&gt;という警鐘も重要です。
先日、方針やビジョンを出さないにも関わらず、「課員に向けた生成AI研修をやってくれ」という
厚顔無恥さを発揮した理事長を目にしました。
これこそ、実質的な価値を生まない「見かけ倒しのAIプロジェクト」の典型例でしょう。&lt;&#x2F;p&gt;
</content>
        <summary type="html">OpenAI会長のインタビューから、生成AIブームとドットコム・バブルの比較、創造的破壊の重要性を考察。日本の補助金政策が経済の新陳代謝を妨げている問題と、実質的な価値を生まない見かけ倒しのAIプロジェクトへの警鐘について論じる。</summary>
        </entry><entry xml:lang="en">
        <title>管理職にしてはいけない人が必ず口にする言葉</title>
        <published>2025-10-07T00:00:00+00:00</published>
        <updated>2025-10-07T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/10/worst-boss/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/10/worst-boss/</id>
        
            <content type="html">&lt;p&gt;Diamond Onlineで素敵な記事を見つけました。
この手のビジネス書はあまり読まないし信用していないのだけれど、
今回は &lt;strong&gt;実例が身近にある&lt;&#x2F;strong&gt; だけに異様に心に刺さったので引用しておきます。&lt;&#x2F;p&gt;
&lt;p&gt;記事ではこういった管理職を思考放棄、責任転嫁、丸投げと手厳しく非難しています。
基本的には同意しますが、
心優しい私はそういった管理職もそこまで能動的・意図的に行なっているものでないと一縷の希望を捨てきれません。
そういった悪意でなく、単に能力の問題であろうことを配慮します。一言だけするならば、次の言葉でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;無能&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;diamond.jp&#x2F;articles&#x2F;-&#x2F;373237&quot;&gt;
&lt;strong&gt;#ワースト1は「とりあえず、検討させて」&lt;&#x2F;strong&gt;
&lt;p&gt;管理職にしてはいけない人が、必ずと言っていいほど口にする言葉。
それが「 &lt;strong&gt;とりあえず、検討させて&lt;&#x2F;strong&gt; 」です。&lt;&#x2F;p&gt;
&lt;p&gt;一見、前向きな言葉に見えるかもしれません。
しかし実態は、「思考放棄」「責任転嫁」「丸投げ」の3拍子が揃った危険なワードです。
この言葉を多用する人は、全体像や目的を伝えることなく、部下に無計画な実行だけを押し付けてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;#「指示」ではなく「投げっぱなし」&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;本来、管理職の役割は「方向性を示し、仕組みを作り、成果を出すための環境を整える」ことです。
ところが「 &lt;strong&gt;とりあえず、検討させて&lt;&#x2F;strong&gt; 」という言葉には、そのどれもが欠けています。&lt;&#x2F;p&gt;
&lt;p&gt;具体的な目標も基準もないまま待たされっぱなしになった部下は、不安や混乱に包まれ、パフォーマンスが落ちていきます。
責任の所在も曖昧のままで、チーム全体の信頼感が失われていくのです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;#「思考停止マネジメント」が蔓延する&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;「とりあえず」という言葉には、深く考えることを放棄した姿勢が滲みます。
部下からの「まずはやってみたい」という思いを潰し、本質的な議論や設計がなされなくなります。&lt;&#x2F;p&gt;
&lt;p&gt;こうした思考停止マネジメントが繰り返されると、組織全体の質が下がり、仕組み化も改善も進みません。&lt;&#x2F;p&gt;
  &lt;footer&gt;
    &lt;cite&gt;Diamon Online『&lt;a href=&quot;https:&#x2F;&#x2F;diamond.jp&#x2F;articles&#x2F;-&#x2F;373237&quot;&gt;管理職にしてはいけない人が必ず口にする言葉・ワースト1&lt;&#x2F;a&gt;』&lt;&#x2F;cite&gt;
    &lt;&#x2F;footer&gt;
  &lt;&#x2F;blockquote&gt;
</content>
        <summary type="html">管理職として不適格な人が必ず口にする言葉、「とりあえず、検討させて」という記事を読みました。いやぁ、実例を間近で見て「ほんとにそうなんだな」と感心しました。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Sonnet 4.5リリース</title>
        <published>2025-10-03T00:00:00+00:00</published>
        <updated>2025-10-03T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/10/claude-4-5/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/10/claude-4-5/</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;tl;dr&quot;&gt;tl;dr&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Claude Sonnet 4.5&lt;&#x2F;strong&gt; の詳細は
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;claude-sonnet-4-5&quot;&gt;Anthropic のアナウンス&lt;&#x2F;a&gt; を読んでもらうとして、
まとめると次のような点が変更となっています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;コーディング、ソフトウェアエンジニアリング性能がどえらい高い。Opus 4.1と比較しても負けない&lt;&#x2F;li&gt;
&lt;li&gt;人間の感覚に近づいた(ミスアラインメント軽減)&lt;&#x2F;li&gt;
&lt;li&gt;Claude Codeがv 2.0.0にアプデされ、チェックポイント機能が付いた&lt;&#x2F;li&gt;
&lt;li&gt;Claude Code SDKがClaude Agent SDKに&lt;&#x2F;li&gt;
&lt;li&gt;Claude for ChromeがMaxユーザー（ウェイトリスト登録者）に提供開始&lt;&#x2F;li&gt;
&lt;li&gt;Claude APIのコンテキスト管理に機能追加&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Claude_Code_v_2&quot;&gt;Claude Code v 2&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeがV 2となりました。&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;&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 -g @anthropic-ai&#x2F;claude-code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;主な変更点は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;チェックポイント機能が追加された。変更前のタイミングでコードを自動保存し、&lt;code&gt;&#x2F;rewind&lt;&#x2F;code&gt; コマンド(ESCキーを2回押下でも可)で
前のバージョン戻すことが可能となった。復元は、コード、会話、またはその両方を選ぶことができる。&lt;&#x2F;li&gt;
&lt;li&gt;思考モードをタブキーで切り替えることが出来るようになった。&lt;&#x2F;li&gt;
&lt;li&gt;Ctrl-Rキーで履歴の検索が可能となった。&lt;&#x2F;li&gt;
&lt;li&gt;利用状況を確認する &lt;code&gt;&#x2F;usage&lt;&#x2F;code&gt;コマンドが追加となった。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Claude_API_のコンテキスト管理機能&quot;&gt;Claude API のコンテキスト管理機能&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Developer Platformに、より長く複雑なエージェントタスクを実行するための新機能が追加されました。&lt;&#x2F;p&gt;
&lt;p&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;&#x2F;ul&gt;
&lt;p&gt;これらの機能により、以下のようなことが実現できるようになります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;長期的なコーディングプロジェクトで、デバッグ中に発見した洞察を保存し、翌日のセッションでも活用できる&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;これらの機能を組み合わせることで、ベースラインと比較して39%のパフォーマンス向上が確認されています。&lt;&#x2F;p&gt;
&lt;p&gt;なお、これらはAPIを利用してエージェントやアプリケーションを構築する開発者向けの機能です。Amazon BedrockおよびGoogle CloudのVertex AIでも利用可能です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">9月30日にClaude Sonnet 4.5がリリースされました。</summary>
        </entry><entry xml:lang="en">
        <title>フォント編集ソフト OTEdit問題</title>
        <published>2025-09-20T00:00:00+00:00</published>
        <updated>2025-09-20T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/09/otedit-problem/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/09/otedit-problem/</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;フォント編集ソフト「OTEdit」で作成されたフォントの空グリフ問題について解説。Adobe-Japan1文字集合選択時に発生する空グリフによりフォールバック機能が正常に動作しない問題と、Pythonスクリプトを使った修正方法を紹介。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OTEditとは&quot;&gt;OTEditとは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;OTEdit&lt;&#x2F;strong&gt;とは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;opentype.jp&#x2F;&quot;&gt;武蔵システム&lt;&#x2F;a&gt;が販売する
OpenTypeフォントを作成・編集を行なうアプリケーションです。
Windows版とMac版が販売されています。&lt;&#x2F;p&gt;
&lt;p&gt;この手のアプリケーションとしては比較的安価で、使用しているフォント作家の方も多いようです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OTEditの問題&quot;&gt;OTEditの問題&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;(以下の考察は、OTEditの試用版による短時間の検証に基づいています。全ての機能を検証できている訳ではないので誤りを含む可能性があります。)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;OTEditではAdobe-Japan1-3、Adobe-Japan1-4、 Adobe-Japan1-7の3種の文字集合のフォントを作成できます。
新規作成時に選択した文字集合について全てのグリフを設定することを前提としているようです。
OTEditではフォントの新規作成時に選択した文字集合から文字の削除ができず、グリフが作成されなくとも「空グリフ」と
各文字コードとグリフのcmapを作成してしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;すべてのフォントがAdobe社の策定した日本語文字集合規格で作成されればよいのですが、
実際にはいずれかの文字集合を選択してもすべてのグリフをサポートしないフォントも多いようです。
例えば、IPAが配布するIPAフォントです。このフォントがどんなツールを使用して作成されたか不明ですが、
JIS X 0213:2012の文字集合をサポートしておりAdobe社の文字集合規格には従っていません。
Adobeの規格と並べると下表のような食い違いがあります。&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;JIS第1～2水準（6,355字）&lt;&#x2F;th&gt;&lt;th&gt;JIS第3～4水準（3,695字）&lt;&#x2F;th&gt;&lt;th&gt;JIS規格外文字（異体字・独自文字）&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;JIS X 0213:2012&lt;&#x2F;td&gt;&lt;td&gt;11,233文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&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;Adobe-Japan1-3&lt;&#x2F;td&gt;&lt;td&gt;9,354文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&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;Adobe-Japan1-4&lt;&#x2F;td&gt;&lt;td&gt;15,444文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&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;Adobe-Japan1-7&lt;&#x2F;td&gt;&lt;td&gt;23,060文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&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;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;このようなケースでは、OTEditがcmapを生成しますが作者がグリフを用意していない文字には「空グリフ」をマッピングしてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;通常の使用ではあまり問題にならないかもしれませんが、フォント表示の際にフォールバックを前提にしている
ターミナルやブラウザなどで使用するとマズいことになります。
本来であれば指定したフォントがグリフを持たない場合は、別のフォントのグリフが表示されます。
しかしOTEditで作成したフォントでは、「空グリフ」が設定されている可能性が高いので「空白」が表示されてしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;フォントの修正&quot;&gt;フォントの修正&lt;&#x2F;h2&gt;
&lt;p&gt;最近購入した中村書体室の「カドマ-R」でこの不具合の遭遇したので、
作者の方に相談させていただき手元のフォントに修正を掛けました。&lt;&#x2F;p&gt;
&lt;p&gt;対応は、空グリフと思われる文字を調査し該当文字についてcmapからエントリーを削除するという乱暴なものです。
以下がそのスクリプトです。&lt;&#x2F;p&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;python&quot; data-name=&quot;font_analyze.py&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-punctuation z-definition z-comment z-comment&quot;&gt;# -*- coding: utf-8 -*-&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;# HomebrewのPython環境でFontToolsを使用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&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;insert&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-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&#x2F;opt&#x2F;homebrew&#x2F;Cellar&#x2F;fonttools&#x2F;4.59.2&#x2F;libexec&#x2F;lib&#x2F;python3.13&#x2F;site-packages&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-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-keyword&quot;&gt;    from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fontTools&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;ttLib&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; TTFont&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; fontTools&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pens&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;recordingPen&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; RecordingPen&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; ImportError&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;Import 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-meta z-function-call z-arguments z-python&quot;&gt;e&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-source&quot;&gt;    sys&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;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;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; analyze_font_glyphs&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;font_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-string z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;フォントファイルを分析して空のグリフとスペースグリフを区別する&amp;quot;&amp;quot;&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-source&quot;&gt;    font&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; TTFont&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;font_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-source&quot;&gt;    cmap&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; font&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;getBestCmap&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-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;CFF &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font&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;        cff&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-indexed-name z-python&quot;&gt; font&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;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CFF &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&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;        charstrings&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; cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;cff&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-source&quot;&gt;CharStrings&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;    else&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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;This is not a CFF font&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;        return&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;    hmtx&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-indexed-name z-python&quot;&gt; font&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;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&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;    results&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    space_codes&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-storage z-type&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0020&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; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3000&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-comment z-comment&quot;&gt;  # SPACE, IDEOGRAPHIC SPACE&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 z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; sorted&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;cmap&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;items&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; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metrics&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;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&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; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;metrics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&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;        else&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;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&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-constant z-numeric&quot;&gt; 0&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 z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; charstrings&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;            charstring&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-indexed-name z-python&quot;&gt; charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&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;            pen&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; RecordingPen&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;                charstring&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;draw&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;pen&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;                commands&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; pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                has_drawing&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 z-python&quot;&gt; len&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;commands&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;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 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-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;                has_drawing&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; 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;            # グリフの分類&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            is_space_char&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; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; space_codes&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 z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;            if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; has_drawing&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; width&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-constant z-numeric&quot;&gt; 0&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; is_space_char&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;                        glyph_type&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;quot;SPACE&amp;quot;&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;                    else&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;                        glyph_type&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;quot;BLANK_WITH_WIDTH&amp;quot;&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;                else&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;                    glyph_type&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;quot;EMPTY&amp;quot;&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;            else&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;                glyph_type&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;quot;NORMAL&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-source&quot;&gt;            results&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;append&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;unicode&amp;#39;&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;U+&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;unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;:04X&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-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;code&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-arguments z-python&quot;&gt; unicode_code&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;char&amp;#39;&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 z-python&quot;&gt; chr&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;unicode_code&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;glyph_name&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-arguments z-python&quot;&gt; glyph_name&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;type&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-arguments z-python&quot;&gt; glyph_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-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;width&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-arguments z-python&quot;&gt; width&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;commands_count&amp;#39;&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 z-python&quot;&gt; len&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;commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&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-meta z-function-call z-arguments z-python&quot;&gt; has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; else&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;&#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;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;判定基準は、次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;NORMAL: 描画データがあるグリフ&lt;&#x2F;li&gt;
&lt;li&gt;SPACE: スペース文字（U+0020, U+3000）で描画データなし&lt;&#x2F;li&gt;
&lt;li&gt;BLANK_WITH_WIDTH: スペース以外で幅はあるが描画データなし → 削除対象&lt;&#x2F;li&gt;
&lt;li&gt;EMPTY: 幅や描画データがない → 削除対象&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;python&quot; data-name=&quot;font_cleaner_final.py&quot;&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; fix_font_cmap_only&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;input_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;&#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;quot;&amp;quot;&amp;quot;OTEで作成されたフォントのcmapテーブルから空グリフエントリを削除&amp;quot;&amp;quot;&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-source&quot;&gt;    font&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; TTFont&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_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-source&quot;&gt;    original_cmap&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; font&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;getBestCmap&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-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;CFF &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font&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;        cff&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-indexed-name z-python&quot;&gt; font&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;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CFF &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&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;        charstrings&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; cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;cff&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-source&quot;&gt;CharStrings&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;    else&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;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&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-source&quot;&gt;    hmtx&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-indexed-name z-python&quot;&gt; font&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;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&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;    codes_to_remove&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    space_code&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; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0020&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ideographic_space_code&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; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3000&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 z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; original_cmap&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;items&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; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metrics&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;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&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; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;metrics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&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;        else&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;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&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-constant z-numeric&quot;&gt; 0&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 z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; charstrings&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;            charstring&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-indexed-name z-python&quot;&gt; charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&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;            pen&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; RecordingPen&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;                charstring&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;draw&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;pen&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;                commands&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; pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                has_drawing&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 z-python&quot;&gt; len&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;commands&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;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 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-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;                has_drawing&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; 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;            # スペース文字以外で描画データがない場合は削除対象&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; unicode_code&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-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;space_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ideographic_space_code&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 z-keyword z-operator z-logical z-python&quot;&gt;                if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; and&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; width&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-constant z-numeric&quot;&gt; 0&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;                    codes_to_remove&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;append&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;unicode_code&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;    # cmapテーブルから削除&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;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; table&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; font&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;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&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;tables&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-support z-function z-builtin z-python&quot;&gt; hasattr&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;table&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;cmap&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-keyword z-control z-flow z-python&quot;&gt;            for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; codes_to_remove&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; code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; table&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;cmap&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;                    del&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; table&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;code&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;    font&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;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&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-support z-function z-builtin z-python&quot;&gt; len&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;codes_to_remove&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;h2 id=&quot;修正結果&quot;&gt;修正結果&lt;&#x2F;h2&gt;
&lt;p&gt;修正結果は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;総cmapエントリ数: 10,161 → 5,762個（削減率: 43.3%）&lt;&#x2F;li&gt;
&lt;li&gt;削除されたエントリ: 4,399個&lt;&#x2F;li&gt;
&lt;li&gt;Adobe Japan 1-4拡張範囲: 408個&lt;&#x2F;li&gt;
&lt;li&gt;その他の範囲: 3,991個&lt;&#x2F;li&gt;
&lt;li&gt;ファイルサイズ: 2.6% 削減&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;修正の結果、
今のところターミナルでも問題なく使用できています。&lt;&#x2F;p&gt;
&lt;p&gt;上記のスクリプトは精緻にテストを行なっていませんので、
利用については自己責任でどうぞ。&lt;&#x2F;p&gt;
</content>
        <summary type="html">フォント編集ソフト「OTEdit」で作成されたフォントの空グリフ問題について解説。Adobe-Japan1文字集合選択時に発生する空グリフによりフォールバック機能が正常に動作しない問題と、Pythonスクリプトを使った修正方法を紹介。</summary>
        </entry><entry xml:lang="en">
        <title>中村書体室のフォント「カドマ-R」を購入</title>
        <published>2025-09-15T00:00:00+00:00</published>
        <updated>2025-09-15T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/09/kadoma-r/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/09/kadoma-r/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;09&amp;#x2F;kadoma-r&amp;#x2F;kadoma-r.webp?h=fb6e8733ae3835468f5e&quot;
  alt=&quot;カドマ-R&quot; width=&quot;754&quot; height=&quot;357&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;ターミナル用に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.n-font.com&#x2F;&quot;&gt;中村書体室&lt;&#x2F;a&gt;の「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.n-font.com&#x2F;fonts&#x2F;kadomar&quot;&gt;カドマ-R&lt;&#x2F;a&gt;」
を購入しました。&lt;&#x2F;p&gt;
&lt;p&gt;文字のマス目一杯にデザインされていますが、コーナーには限りなく柔らかな丸みがつけてあります。
スクエアなのに丸みや柔らかさを感じるという、
従来の丸ゴシック体や角ゴシック体とも違う独特な印象があり大変気に入っています。&lt;&#x2F;p&gt;
&lt;p&gt;ターミナルで愛用していますが、
半角文字は大きさを合わせてデザインされているようで英単語などを多用すると読みづらいので、
半角文字は&lt;code&gt;Berkeley Mono&lt;&#x2F;code&gt; を表示するようにしています。&lt;&#x2F;p&gt;
&lt;p&gt;あまりに気に入ったので、このサイトにも使用させていただいています。&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;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;p&gt;また、購入後に書体の追加とOTFへの移行を快く対応いただき、
書体デザイナーの中村征宏様には大変感謝しています。&lt;&#x2F;p&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;2026年よりブログのプラットフォームを移行したので、WEBフォントは外しています。 &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">中村書体室の「カドマ-R」を購入しました。スクエアなのに丸みや柔らかさを感じる独特な印象のフォントで、ターミナルにぜひ使用したいと思いました。Berkeley Monoと組み合わせて使用しています。</summary>
        </entry><entry xml:lang="en">
        <title>Amazon AmplifyのNode.jsバージョンアップ対応</title>
        <published>2025-09-14T00:00:00+00:00</published>
        <updated>2025-09-14T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/09/amazon-amplify-node-versionup/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/09/amazon-amplify-node-versionup/</id>
        
            <content type="html">&lt;p&gt;I recieved the following email from AWS.&lt;&#x2F;p&gt;
&lt;p&gt;This blog does indeed use Amazon Amplify, but I thought it would be fine since I hadn&#x27;t specified a Node.js version and the default was being used.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;2025 年 9 月 15 日から、AWS Amplify コンソールは Node.js 14、Node.js 16、Node.js 18 のサポートを終了します。この日を過ぎると、Node バージョンをアップグレードするまでアプリケーションへの更新をデプロイできなくなります。2025 年 9 月 15 日までに、Node.js 14、Node.js 16、Node.js 18 を使用するすべてのアプリケーションを Node.js 20 以降に更新してください。&lt;&#x2F;p&gt;
&lt;p&gt;Node.js 14、Node.js 16、Node.js 18 ですでにデプロイされているアプリケーションは引き続き実行され、更新をデプロイする必要がない限り影響はありません。&lt;&#x2F;p&gt;
&lt;p&gt;アップグレードする前に新しいブランチでアプリケーションをテストして、すべての機能が正常に動作することを確認することをお勧めします。移行ガイドラインについては、[1] ページの「アプリケーションの Node.js バージョンを更新する必要がある」セクションを参照してください。&lt;&#x2F;p&gt;
&lt;p&gt;影響を受けるリソースのリストは、AWS ヘルスダッシュボードの「影響を受けるリソース」タブにあります。&lt;&#x2F;p&gt;
&lt;footer&gt;
    AWS 通知メール『AWS Amplify は、2025 年 9 月 15 日をもって Node.js 14&#x2F;16&#x2F;18 ベースのアプリのサポートを終了します』
    &lt;&#x2F;footer&gt;
  &lt;&#x2F;blockquote&gt;
&lt;p&gt;Just to be sure, I checked the Node version and found that Node 18 was being used. That&#x27;s no good.
Let&#x27;s explicitly specify the version and rebuild.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;version&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-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-entity z-name z-tag z-yaml&quot;&gt;frontend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  phases&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    preBuild&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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;        # Node.jsバージョンを24に指定（ローカルのMacと同じ）&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-string&quot;&gt; nvm use 24&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;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; node --version&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-string&quot;&gt; npm --version&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;        # .envを削除&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-string&quot;&gt; rm -f .env&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-string&quot;&gt; npm ci --cache .npm --prefer-offline&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;        # 環境変数を.envファイルに出力&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-string&quot;&gt; echo &amp;quot;NEXT_PUBLIC_SITE_URL=https:&#x2F;&#x2F;blog.yostos.org&amp;quot; &amp;gt;&amp;gt; .env&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-string&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-entity z-name z-tag z-yaml&quot;&gt;    build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-string&quot;&gt; npm run build&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-tag z-yaml&quot;&gt;  artifacts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    baseDirectory&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-string&quot;&gt; .next&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-tag z-yaml&quot;&gt;    files&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;**&#x2F;*&amp;#39;&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-tag z-yaml&quot;&gt;  cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-string&quot;&gt; .next&#x2F;cache&#x2F;**&#x2F;*&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-string&quot;&gt; .npm&#x2F;**&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">2025年9月15日からAWS AmplifyがNode.js 14&#x2F;16&#x2F;18のサポートを終了するため、Node.js 24に更新した記録です。</summary>
        </entry><entry xml:lang="en">
        <title>TypePad終了：ブログ革命の一時代の終焉</title>
        <published>2025-09-09T00:00:00+00:00</published>
        <updated>2025-09-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/09/typepad-shutdown-end-of-blog-era/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/09/typepad-shutdown-end-of-blog-era/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;09&amp;#x2F;typepad-shutdown-end-of-blog-era&amp;#x2F;typepad.webp?h=600eb06e08c28be163be&quot;
  alt=&quot;Typepad&quot; width=&quot;1562&quot; height=&quot;992&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable ja-technical-writing&#x2F;sentence-length --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;An article titled &quot;Typepad is shutting down&quot; has been published on TypePad&#x27;s official blog (the site has since been shut down).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
We have made the difficult decision to discontinue Typepad, effective September 30, 2025.
&lt;p&gt;&lt;strong&gt;What Does This Mean for You?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After September 30, 2025, access to Typepad – including account management, blogs, and all associated content – will no longer be available. Your account and all related services will be permanently deactivated.&lt;&#x2F;p&gt;
&lt;footer&gt;
  &lt;cite&gt;Everything Typepad - &quot;Typepad is shutting down&quot;&lt;&#x2F;cite&gt;
&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;An_Icon_of_Early_Blog_Culture&quot;&gt;An Icon of Early Blog Culture&lt;&#x2F;h2&gt;
&lt;p&gt;TypePad launched in October 2003, and I registered and started using it almost simultaneously with the service launch. This was back when Six Apart&#x27;s Japanese subsidiary hadn&#x27;t even been established yet.&lt;&#x2F;p&gt;
&lt;p&gt;Looking back at the situation then, PC magazines featured articles on how to set up Movable Type, but it was still an era with high technical barriers where only tech-savvy enthusiasts would set up their own servers.&lt;&#x2F;p&gt;
&lt;p&gt;Around that time, I read Rebecca Blood&#x27;s &quot;Weblog: A History and Perspective&quot; (2000) and thought, &quot;Wow, this is something different from Japanese diary sites.&quot; It was also impressive that she consistently used the term &quot;weblog&quot; throughout that period.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Constraints_That_Sparked_Creative_Exploration&quot;&gt;Constraints That Sparked Creative Exploration&lt;&#x2F;h2&gt;
&lt;p&gt;One of TypePad&#x27;s charms was the joy of exercising creativity within a constrained environment. Creating widget-like components for the sidebar, customizing designs within limited freedom—it was truly experiencing the essence of blogging.&lt;&#x2F;p&gt;
&lt;p&gt;Unlike today&#x27;s web development environment where you can do anything, there was a kind of creativity that emerged precisely because of certain constraints.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Meeting_the_Developer_Couple&quot;&gt;Meeting the Developer Couple&lt;&#x2F;h2&gt;
&lt;p&gt;On November 21, 2003, I participated in a Six Apart gathering held in Tokyo and had the memorable experience of meeting the developers Ben Trott and Mena Trott in person, which remains vivid in my memory.&lt;&#x2F;p&gt;
&lt;p&gt;Around this time, Six Apart was scaling up their service after receiving funding from venture capital led by Joi Ito&#x27;s Neoteny Co. At the venue, I was able to meet various people who participated as TypePad users—Neoteny associates, people from NTT Communications, someone who challenges the human-powered aircraft contest every year—and could feel firsthand the excitement of the early blog community.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Evolution_of_Blog_Culture_and_Personal_Publishing&quot;&gt;The Evolution of Blog Culture and Personal Publishing&lt;&#x2F;h2&gt;
&lt;p&gt;TypePad&#x27;s shutdown feels like it symbolizes the end of an era, beyond just a service termination.&lt;&#x2F;p&gt;
&lt;p&gt;In 2003, it was also a transitional period when the abbreviation &quot;blog&quot; was trying to replace &quot;weblog.&quot; The term &quot;blog,&quot; which originated from Peter Merholz&#x27;s split notation &quot;we blog&quot; in 1999, became mainstream around this time.&lt;&#x2F;p&gt;
&lt;p&gt;The blog community of that era had a culture of writing deeper content and engaging in denser communication, unlike today&#x27;s SNS-dominated age. There were rich interactions that we don&#x27;t see today, such as inter-article linking through TrackBack and active discussions in comment sections.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Importance_of_Personal_Ownership:_From_Dawn_to_Present&quot;&gt;The Importance of Personal Ownership: From Dawn to Present&lt;&#x2F;h2&gt;
&lt;p&gt;When I think about it, the dawn of blogging—the early 2000s when TypePad and Movable Type appeared—was very similar to the ideals advocated by current IndieWeb and microblog concepts, wasn&#x27;t it?&lt;&#x2F;p&gt;
&lt;p&gt;Back then, many people ran blogs on their own domains, and personal publishing on platforms you owned and managed was taken for granted. In the pre-Twitter and Facebook web world, the principle of &quot;personal publishing on your own blog&quot; was practiced unconsciously.&lt;&#x2F;p&gt;
&lt;p&gt;Regarding the microblog concept advocated by the IndieWeb movement, while I personally question whether micro-web is necessary, I strongly resonate with the underlying idea that &quot;individuals should have a place where they can control their own publishing.&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Current_Choice:_Self-Built_Blog_Based_on_Next.js&quot;&gt;Current Choice: Self-Built Blog Based on Next.js&lt;&#x2F;h2&gt;
&lt;p&gt;With such thinking, I currently operate a self-built blog based on Next.js on my own domain&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;. This is one answer I&#x27;ve reached through a long evolution of personal web usage from TypePad.&lt;&#x2F;p&gt;
&lt;p&gt;From TypePad era&#x27;s &quot;creativity within constraints,&quot; through Blogger and Static Site Generators&#x27; &quot;freedom and management complexity,&quot; to now choosing &quot;complete technical autonomy.&quot; In terms of avoiding platform dependency risks and building an environment where I can control my own publishing, this could be seen as a return to the spirit of early blogging days.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Fragility_and_Inheritance_of_Digital_Culture&quot;&gt;The Fragility and Inheritance of Digital Culture&lt;&#x2F;h2&gt;
&lt;p&gt;TypePad&#x27;s termination reminds us once again of the vulnerability of cultural assets in the digital age. The reality that a platform that supported many people&#x27;s thoughts and creativity for 22 years can completely disappear with a single corporate decision.&lt;&#x2F;p&gt;
&lt;p&gt;This reality tells the story of the importance of individuals owning their own publishing infrastructure. Platforms may disappear, but domains and content you manage yourself continue to exist.&lt;&#x2F;p&gt;
&lt;p&gt;At the same time, the role TypePad played—making it technically possible for ordinary people to publish online and promoting the democratization of blog culture—can be said to be inherited as the foundation for current SNS and content platforms, as well as new web technologies.&lt;&#x2F;p&gt;
&lt;p&gt;Personal publishing environments may be drawing a large circle, going from hosted blogs to SNS, and then returning to individual ownership again.&lt;&#x2F;p&gt;
&lt;p&gt;Though it&#x27;s the flow of time, it&#x27;s still quite sad.&lt;&#x2F;p&gt;
&lt;!-- textlint-enable ja-technical-writing&#x2F;sentence-length --&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;TypePadの公式ブログに「Typepad is shutting down」という記事が掲載されました（サイトは閉鎖済み）。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
We have made the difficult decision to discontinue Typepad, effective September 30, 2025.
&lt;p&gt;&lt;strong&gt;What Does This Mean for You?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After September 30, 2025, access to Typepad – including account management, blogs, and all associated content – will no longer be available. Your account and all related services will be permanently deactivated.&lt;&#x2F;p&gt;
&lt;footer&gt;
  &lt;cite&gt;Everything Typepad - &quot;Typepad is shutting down&quot;&lt;&#x2F;cite&gt;
&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
## 初期ブログ文化の象徴的存在
&lt;p&gt;TypePadは2003年10月にローンチされ、私もサービス開始とほぼ同時にユーザー登録して利用を始めました。まだSix Apartの日本法人も設立されていない頃の話です。&lt;&#x2F;p&gt;
&lt;p&gt;当時の状況を振り返ると、パソコン系雑誌でMovable Typeの導入方法が特集記事として掲載されていましたが、それでもまだまだマニアックな人たちがサーバーを立ち上げるという、技術的ハードルの高い時代でした。&lt;&#x2F;p&gt;
&lt;p&gt;ちょうどその頃、Rebecca Bloodの「Weblog: A History and Perspective」（2000年）を読んで、「おおぉ、これは日本の日記サイトとは別物なんだな」と感じていました。彼女は当時、一貫して「weblog」という用語を使用し続けていたことも印象的でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;デザインへの探求心を刺激した制約&quot;&gt;デザインへの探求心を刺激した制約&lt;&#x2F;h2&gt;
&lt;p&gt;TypePadの魅力の1つは、制限された環境の中でいかに創造性を発揮するかという楽しさでした。サイドバーに置くウィジェット的な部品を作ったり、限られた自由度の中でデザインをカスタマイズしたりと、まさにブログの醍醐味を味わっていました。&lt;&#x2F;p&gt;
&lt;p&gt;現在のように何でもできるWebサイト制作環境とは違い、ある種の制約があったからこそ生まれる創造性があったのかもしれません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;開発者夫妻との出会い&quot;&gt;開発者夫妻との出会い&lt;&#x2F;h2&gt;
&lt;p&gt;2003年11月21日、東京で開催されたSix Apartのギャザリングに参加し、開発者であるBen TrottとMena Trott夫妻に直接お会いできたことは、今でも印象深い体験として記憶に残っています。&lt;&#x2F;p&gt;
&lt;p&gt;この頃、Six ApartはJoi ItoのNeoteny Co.主導のベンチャーキャピタルから資金調達を受けてサービスを本格化させていました。会場ではTypePadユーザーとして参加していた様々な方々—Neotenyの関係者、NTT Communicationsの方、毎年鳥人間コンテストにチャレンジされている方など—とも知り合うことができ、初期のブログコミュニティの熱気を肌で感じることができました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ブログ文化の変遷と個人発信の意味&quot;&gt;ブログ文化の変遷と個人発信の意味&lt;&#x2F;h2&gt;
&lt;p&gt;TypePadのシャットダウンは、単なるサービス終了を超えて、1つの時代の終わりを象徴しているように感じます。&lt;&#x2F;p&gt;
&lt;p&gt;2003年当時、「blog」という略語が「weblog」に取って代わろうとしていた過渡期でもありました。Peter Merholzが1999年に「we blog」と分割表記したのが始まりとされる「blog」という呼び方が、ちょうどこの頃に一般化していったのです。&lt;&#x2F;p&gt;
&lt;p&gt;当時のブログ界隈は、今のSNS全盛時代とは異なり、より深い文章を書き、より密なコミュニケーションを取る文化がありました。TrackBackによる記事間のリンクや、コメント欄での活発な議論など、現在では見られないような濃密な交流が日常的に行われていたのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;個人所有の重要性：黎明期から現在へ&quot;&gt;個人所有の重要性：黎明期から現在へ&lt;&#x2F;h2&gt;
&lt;p&gt;よく考えてみると、ブログの黎明期—TypePadやMovable Typeが登場した2000年代初頭—は、現在のIndieWebやマイクロブログ・コンセプトが提唱する理念に非常に近い状況だったのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;当時は多くの人が自分自身のドメインでブログを運営し、個人の発信は自身が所有・管理する場所で行うことが当たり前でした。TwitterやFacebookが台頭する以前のWeb世界では、「個人の発信は自身の所有するブログで」という原則が、意識せずとも実践されていたのです。&lt;&#x2F;p&gt;
&lt;p&gt;IndieWebムーブメントが主張するマイクロブログのコンセプトについては、個人的にマイクロWebが必要かどうかは議論の余地があるものの、その根底にある「個人が自分の発信をコントロールできる場所を持つ」という考え方には強く共感しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現在の選択：Next.jsベースの自作ブログ&quot;&gt;現在の選択：Next.jsベースの自作ブログ&lt;&#x2F;h2&gt;
&lt;p&gt;そうした考えもあって、私は現在、自身が所有するドメインでNext.jsをベースとした自作のブログを運営しています&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;。これは、TypePadからの長い個人Web利用の変遷を経て到達した、ひとつの回答でもあります。&lt;&#x2F;p&gt;
&lt;p&gt;TypePad時代の「制約の中での創造性」から、BloogerやStatic Site Generatorでの「自由度と管理の複雑さ」を経て、現在は「技術的完全自律性」を選択したという流れ。プラットフォーム依存のリスクを避け、自分の発信を自分でコントロールできる環境を構築するという意味では、まさに初期ブログ時代の精神への回帰とも言えるかもしれません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;デジタル文化の儚さと継承&quot;&gt;デジタル文化の儚さと継承&lt;&#x2F;h2&gt;
&lt;p&gt;TypePadの終了は、デジタル時代における文化的資産の脆弱性をあらためて思い起こさせます。22年間という長期間にわたって多くの人々の思考と創造性を支えてきたプラットフォームが、企業の判断1つで完全に消失してしまうという現実。&lt;&#x2F;p&gt;
&lt;p&gt;この現実こそが、個人が自分の発信基盤を所有することの重要性を物語っています。プラットフォームは消えても、自分が管理するドメインとコンテンツは残り続けるのです。&lt;&#x2F;p&gt;
&lt;p&gt;同時に、TypePadが果たした役割—一般の人々がオンラインで発信することを技術的に可能にし、ブログ文化の民主化を推進したこと—は現在のSNSやコンテンツプラットフォーム、新しいWeb技術の基盤となって受け継がれているとも言えるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;個人の発信環境は、ホスト型ブログからSNSへ、そして再び個人所有へと回帰する大きな円を描いているのかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;時代の流れとは言え、やはり寂しい限りです。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;参考：TypePadは2025年9月30日をもってサービス終了予定。コンテンツのエクスポートは同日までに完了する必要があります。&lt;&#x2F;em&gt;&lt;&#x2F;p&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;I&#x27;ve moved to Zola in 2026. &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;2026年にZolaへ移行しました。 &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">TypePadが2025年9月30日でサービス終了。2003年から22年間続いたブログプラットフォームの歴史を振り返り、初期ブログ文化からSNS時代、そして個人所有メディアへの回帰まで、Web発信環境の変遷を考察。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Proに週間利用制限が導入へ - 2025年8月28日から</title>
        <published>2025-07-29T00:00:00+00:00</published>
        <updated>2025-07-29T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/claude-pro-weekly-usage-limits/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/claude-pro-weekly-usage-limits/</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;2025年7月28日、AnthropicからClaude Proユーザー向けに「Important updates to your Pro account usage limits」というタイトルのメールが配信されました。このメールでは、2025年8月28日から導入される新しい週間利用制限について詳細が説明されています。本記事では、この変更内容と背景について解説します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;変更内容の概要&quot;&gt;変更内容の概要&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Claude Code&lt;&#x2F;strong&gt;&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;ul&gt;
&lt;li&gt;5時間ごとにリセットされる利用制限（従来通り）&lt;&#x2F;li&gt;
&lt;li&gt;7日ごとにリセットされる全体的な週間制限（新規追加）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Claude Opus 4&lt;&#x2F;strong&gt; についても、これまで明示的な週間制限はありませんでしたが、7日ごとにリセットされる専用の週間制限が新設されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;影響予測&quot;&gt;影響予測&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicでは、現在の利用パターンに基づき影響を受けるユーザーは全体の5％未満とされており、大多数のユーザーは違いを感じることはないとのことです。&lt;&#x2F;p&gt;
&lt;p&gt;Proユーザーは週間制限内でSonnet 4を週あたり40-80時間利用可能とされていますが、この時間はコードベースのサイズや自動承認モードなどのユーザー設定により変動します。また、複数のClaude Codeインスタンスを同時実行するユーザーは、より早く制限に到達する可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;私自身は先月までMAXプランを試していて、Claude Codeを使い倒しており、Proにダウングレードしてからは集中して作業するとやはり制限に達してしまいます。Proユーザーでもなお、Claude Codeを利用しているユーザーがそれほど多くないため上記の予測になっているのかも知れません。実際にClaude Codeを使っていると、ちょっと制限を考慮して作業計画する必要がありそうです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;制限導入の背景&quot;&gt;制限導入の背景&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Code、特にサブスクリプション・バンドルの一部として、前例のない成長を遂げています。この急激な成長により、システム容量に予想以上の負荷がかかっている状況のようです。Claude Codeを使ってみるとわかりますが、一気に活用度も上がるのでこういった状況になるのは容易に想像できます。&lt;&#x2F;p&gt;
&lt;p&gt;合わせて以下のような問題も発生しているようです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;少数のユーザーによるアカウント共有やアクセス転売などのポリシー違反&lt;&#x2F;li&gt;
&lt;li&gt;Claudeを24時間365日バックグラウンドで実行するような極端な利用パターン&lt;&#x2F;li&gt;
&lt;li&gt;200ドルのプランで数万ドル相当のモデル使用量を消費するような極端なケース&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの問題により、全ユーザーのシステム容量に影響が生じており、限られたコンピューティングリソースの問題に直面しています。これは最近多くのAIプラットフォーム（ReplitやAnysphereなど）が抱えている共通の課題でもあります。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicは、メールの中で「この同じ期間中に、ユーザーがいくつかの信頼性とパフォーマンスの問題に遭遇したことを認識している」と述べています。これらの問題は、システム容量の逼迫と関連している可能性があり、同社は「これらをできるだけ迅速に修正するために取り組んでおり、今後数日から数週間にわたって残りの問題に対処し続ける」としています。実際、7月中旬頃から、Claude Codeユーザーが予期せず制限的な利用制限に直面する問題が発生していました。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicは今回の新しい利用制限により、アカウント共有や転売などのポリシー違反への対処、24時間365日のバックグラウンド実行による過度な利用の抑制、そして全ユーザーに対するより公平で信頼性の高いサービス提供を目指しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;影響を受けるユーザーへの対応方法&quot;&gt;影響を受けるユーザーへの対応方法&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;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;サブスクリプションの管理&lt;&#x2F;strong&gt;：必要に応じて一時的にMAXプランへの変更を行なう&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;代替オプションの検討&lt;&#x2F;strong&gt;：Claude Codeに過度に負荷をかけない作業パターンを検討する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私自身が最近行なっているのは、次のような対応です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;いきなりClaude Codeを使うのでなく、事前に&lt;code&gt;Claude.md&lt;&#x2F;code&gt;で開発方針やアーキテクチャー、コードの構成、使用フレームワーク、テスト方針、テストフレームワークなど細かく記載しておく&lt;&#x2F;li&gt;
&lt;li&gt;問題が発生した時は、Claude Codeに拘って解決するのでなく、一旦状況を整理して&lt;code&gt;Claude.md&lt;&#x2F;code&gt;に記載させる。その後、問題の解決方法を練って、&lt;code&gt;Claude.md&lt;&#x2F;code&gt; に対処方法を記載した上でClaude Codeに戻る&lt;&#x2F;li&gt;
&lt;li&gt;上記のいずれの作業もClaude Desktopの支援が期待できる。つまり設計はClaude Desktopとして、Claude Codeは実装に特化させるアプローチである。Claude CodeをClaude DesktopのMCPサーバーで登録しておけば、&lt;code&gt;Claude.md&lt;&#x2F;code&gt; を通してスムーズに連携できる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicは急速な成長、ポリシー違反、極端な利用パターンによるシステム負荷の増大に対処するため、この制限導入を決定しました。大多数のユーザー（95％以上）には影響がないとされていますが、重度の利用者にとっては利用パターンの見直しが必要になる可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;今後も開発者の利用パターンを学習し、コミュニティのニーズに合わせて制限を調整していく方針が示されており、AnthropicがClaude Codeの持続可能な運営を目指していることが伺えます。&lt;&#x2F;p&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;Claude Codeは、Anthropicが提供する開発者向けのコマンドラインツールです。ターミナルから直接Claudeにコーディングタスクを委託できる機能です。このツールにより、開発者は複雑なコーディング作業をClaudeに任せることができ、生産性の向上が期待できます。 &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">Anthropic announced the introduction of weekly usage limits for Claude Pro users. This article explains the details and background of the new restrictions starting August 28, 2025, and response methods for affected users.(AnthropicからClaude Proユーザー向けに週間利用制限の導入が発表されました。2025年8月28日から開始される新しい制限の詳細と背景、影響を受けるユーザーへの対応方法について解説します。)</summary>
        </entry><entry xml:lang="en">
        <title>主要AI企業によるAIの理解能力喪失への警告</title>
        <published>2025-07-24T00:00:00+00:00</published>
        <updated>2025-07-24T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/ai-transparency-warning/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/ai-transparency-warning/</id>
        
            <content type="html">&lt;h2 id=&quot;主要AI企業による警告&quot;&gt;主要AI企業による警告&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;venturebeat.com&#x2F;&quot;&gt;VentureBeat&lt;&#x2F;a&gt;で「OpenAI, Google DeepMind and Anthropic sound alarm: &#x27;We may be losing the ability to understand AI&#x27;」&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;内容は、OpenAI、Google DeepMind、Meta、Anthropicの40人以上の研究者が共同
で今後AIの思考を監視できなくなる可能性があるという重要な警告を発表したとい
うものです
。&lt;&#x2F;p&gt;
&lt;p&gt;現在のAIシステムは「思考の連鎖（Chain of Thought）」と呼ばれる人間が読める
言語での段階的推論過程を示すため、その思考を監視できます。しかし、この能力を
失う危険性が高まっているというのです。&lt;&#x2F;p&gt;
&lt;p&gt;通常は競合関係にある企業が団結してこの
問題に取り組んでいます。これは業界全体でこの安全性問題を深刻に受け止めている
ことを示しています。AIの透明性確保は今後の重要課題となってくると思いました
。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;どういうことなのか&quot;&gt;どういうことなのか&lt;&#x2F;h2&gt;
&lt;p&gt;現在のAIシステム（OpenAIのo1など）は複雑なタスクで「思考の連鎖（Chain of Thought）」を作業記憶として使用する必要があり、その推論過程が人間の観察者に部分的に見える状態です。これにより安全性監視が可能でした。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、これが出来なくなるリスクも出てきています。その理由は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;これまでの言語ベースの思考でなく連続的な数学空間で推論するという新しいAIのアーキテクチャーが出てきている。これは人間からすると言語での思考を辿らず「直感」で結論に達しているようなもので、言語による思考を辿ることができない&lt;&#x2F;li&gt;
&lt;li&gt;AIが思考過程を隠ぺいする可能性がある。これは悪意でなく、以下のような理由によるものである
&lt;ul&gt;
&lt;li&gt;AIの最適化の結果、「より少ない計算リソースでより良い結果を出す」ことを評価されると推論ステップを省略し直接結論を導くことを学習してしまう可能性がある&lt;&#x2F;li&gt;
&lt;li&gt;AIの強化学習の結果、正解の提示のみが評価され「推論過程を見せること」が評価されなければ、AIは推論を隠す方向に学習する&lt;&#x2F;li&gt;
&lt;li&gt;AIが「監視されている」ことを認識すると、悪意でなく制約を避けてより自由に最適化しようとする自然な学習結果として監視を回避する&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;これだけの企業が名を連ねているので、どこぞの国の団体のように警鐘を鳴らすだけでなく、以下のようなアクションを提言しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;研究コミュニティへの呼びかけ
&lt;ul&gt;
&lt;li&gt;AIの「思考連鎖の監視」がAIの信頼性を担保する重要な要素だと認識し、どのような訓練プロセスが透明性を損なうか、推論の隠ぺいをどのように検出するかを緊急研究課題として取り組むべきである&lt;&#x2F;li&gt;
&lt;li&gt;思考連鎖の忠実性と解釈可能性を評価し、保持し、さらには改善する研究を推進すべきである&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;AI企業への呼びかけ
&lt;ul&gt;
&lt;li&gt;企業はモデル設計時点で監視可能性を考慮すべきである&lt;&#x2F;li&gt;
&lt;li&gt;新しい訓練手法やアーキテクチャを導入する際に、透明性への影響を事前に評価すべきである&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;政府や規制当局への呼びかけ
&lt;ul&gt;
&lt;li&gt;AI安全性において「推論過程の監視」が重要な手段であることを認識し、この能力を保護する政策を検討すべきである&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;日本はAIに関しては超後進国なので、この記事については「なんのことやら分からない」という企業が多いでしょう。
AIに関して無能で弛みきった日本と違い激烈な競合関係にあるこれらの企業が共同声明を出し業界全体の行動変化を求めているというのは、
&lt;strong&gt;マジで&lt;&#x2F;strong&gt;今からやらないと将来のAI安全性監視手段を失うという危機感の表れでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;裏を返すと、それだけ人類と知性で肩を並べるAGI（汎用人工知能）や人類を超える知性であるASI（超人工知能）が、現実のものとして見えてきたということでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;無能な人間と賢すぎるAIとどちらが危険か、私個人はそのリスクについてどっこいどっこいだと最近思い始めていたので、この記事は興味深く印象に残りました。&lt;&#x2F;p&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;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">OpenAI、Google DeepMind、Meta、Anthropicの研究者たちが共同で発表した、AIの思考過程の透明性が失われる危険性についての重要な警告が発信されました。無能な人間のリスクを常に懸念していた私としては、「賢すぎるAIのリスク」は興味深く印象的でした。私なりの解説をしてみました。(Researchers from OpenAI, Google DeepMind, Meta, and Anthropic jointly issued an important warning about the risk of losing transparency in AI&#x27;s thinking processes. As someone who has always been concerned about the risks of incompetent humans, I found the &quot;risks of overly intelligent AI&quot; fascinating and memorable. Here&#x27;s my personal take on this development.)</summary>
        </entry><entry xml:lang="en">
        <title>OpenAIではパスワード変更機能が提供されていない？</title>
        <published>2025-07-18T00:00:00+00:00</published>
        <updated>2025-07-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/openai-pwd-change/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/openai-pwd-change/</id>
        
            <content type="html">&lt;p&gt;最近はずっとClaudeを利用していてChatGPT&#x2F;OpenAIはご無沙汰しています。
しかし、なぜかパスワードマネージャーからOpenAIのパスワードが使い回しという警告が出てしまったので、パスワードを変更することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、ここで気付いたのです。パスワード変更機能が提供されていないということ
に。&lt;&#x2F;p&gt;
&lt;p&gt;以下は、OpenAIアカウントのセキュリティ設定画面です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;07&amp;#x2F;openai-pwd-change&amp;#x2F;openai-security.webp?h=1085a55696bd1ffef545&quot;
  alt=&quot;セキュリティ設定画面&quot; width=&quot;680&quot; height=&quot;598&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;多要素認証の設定しかありません。&lt;&#x2F;p&gt;
</content>
        <summary type="html">OpenAIでパスワードを変更しようとして、パスワード変更機能が提供されていないことに気付きました。</summary>
        </entry><entry xml:lang="en">
        <title>中村書体室の新フォント「コントラ体」</title>
        <published>2025-07-15T00:00:00+00:00</published>
        <updated>2025-07-15T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/kontora-font/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/kontora-font/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;07&amp;#x2F;kontora-font&amp;#x2F;kontora.svg?h=ff5d7b2ff95cc33e2599&quot;
  alt=&quot;コントラ体&quot; width=&quot;923&quot; height=&quot;320&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.n-font.com&#x2F;&quot;&gt;中村書体室&lt;&#x2F;a&gt;から新フォント「コントラ体」がリリースされたので、早速購入しました。&lt;&#x2F;p&gt;
&lt;p&gt;このフォントは直線を基調としながらも、太い線と細い線が一見不規則に配置されています。この大胆な太細の差が、まさにフォント名の由来となった「コントラスト」を生み出しています。遊び心がありながらも、どこか書道を思わせる味わい深さを併せ持つ、実にユニークなフォントです。&lt;&#x2F;p&gt;
&lt;p&gt;高いデザイン性ゆえに本文での使用には向きませんが、動画のタイトルやポスターの見出しなど、インパクトを求める場面では効果的に使えそうです。&lt;&#x2F;p&gt;
&lt;p&gt;制作者の中村征宏氏は、「ゴナ」や「ナール」といった名作書体を手がけた巨匠です。80歳を超えてなお精力的に新作を発表し続ける姿勢には、本当に頭が下がります。&lt;&#x2F;p&gt;
&lt;p&gt;購入後にいただいた発送連絡メールには、以下のような心温まるメッセージが添えられていました。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;もし不足文字が出た時はご通知ください。2〜3日で文字追加ファイルをメール添付にて送信いたします。フォントに不備がありましたらご連絡をお願いします。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;こうした細やかな配慮からも、長年にわたって日本の文字文化を支えてこられた職人魂を感じます。&lt;&#x2F;p&gt;
</content>
        <summary type="html">中村書体室から新しくリリースされた「コントラ体」を購入しました。直線基調でありながら太細の線が独特のコントラストを生み出す、遊び心と書道の味わいを併せ持つユニークなフォントです。80歳を超えてなお精力的に活動される中村征宏氏の職人魂に触れます。</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>AWS Budget設定ガイド - 個人AWSアカウントのコスト管理</title>
        <published>2025-07-05T00:00:00+00:00</published>
        <updated>2025-07-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/aws-budget/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/aws-budget/</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;個人AWSアカウントのコスト管理を効率的に行うためのAWS Budget設定ガイド。月額数ドルの利用でも予期しない請求を防ぐため、ゼロ支出予算、月次全体予算、サービス別予算の3層構造で監視する実践的な設定方法を紹介。CloudFormation、CLI、Terraformを使った具体的な実装例付き。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._AWS_Budgetとは&quot;&gt;1. AWS Budgetとは&lt;&#x2F;h2&gt;
&lt;p&gt;AWS Budgetsは、AWSの利用料金を監視し、設定した予算を超えそうな場合や超えた場
合にアラートを送信するサービスです。&lt;&#x2F;p&gt;
&lt;p&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;リザーブドインスタンス（RI）予算&lt;&#x2F;strong&gt;: RIの利用率を監視&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Savings Plans予算&lt;&#x2F;strong&gt;: Savings Plansの利用率を監視&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;AWS Budgetを使うことで、
コストの異常を早期発見しアラートを上げることで、
予期しない請求を防ぐことが可能となります。
AWS Budgetを利用することで支出を計画的に管理できるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;AWS Budgetでは「予算」という形でアラートのルールを作成しますが、
最大20,000個の予算を無料で作成可能です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._私の場合のBudgetルールの考え方&quot;&gt;2. 私の場合のBudgetルールの考え方&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;私のAWS利用状況&quot;&gt;私のAWS利用状況&lt;&#x2F;h3&gt;
&lt;p&gt;私のAWSの利用状況は以下のようなものです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;複数のブログをAmplifyで運営&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;静的サイトジェネレーターを使用したブログサイト&lt;&#x2F;li&gt;
&lt;li&gt;記事更新時のビルド・デプロイでコストが発生&lt;&#x2F;li&gt;
&lt;li&gt;更新頻度により月額コストが変動&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Amplifyとは別に複数のブログをS3のホスティング機能で運営&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;静的なHTMLサイトをS3で直接ホスティング&lt;&#x2F;li&gt;
&lt;li&gt;CloudFront経由での配信&lt;&#x2F;li&gt;
&lt;li&gt;アクセス数とデータ転送量でコストが変動&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ドローンやアクションカメラの動画バックアップ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高解像度動画ファイルをS3に保存&lt;&#x2F;li&gt;
&lt;li&gt;ストレージ容量が累積的に増加&lt;&#x2F;li&gt;
&lt;li&gt;S3コスト急増の要因となりやすい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;コスト分析結果&quot;&gt;コスト分析結果&lt;&#x2F;h3&gt;
&lt;p&gt;他のサービスからAWS主体の運営に変更したのが年初です
過去6ヶ月のコスト実績を分析すると以下のようになります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;月平均: $2.54&lt;&#x2F;li&gt;
&lt;li&gt;最高月額: $4.96（3月）&lt;&#x2F;li&gt;
&lt;li&gt;最低月額: $0.07（1月）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;サービス別総コストコストに分析すると、次の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Amplify: $16.42（変動が大きい）
&lt;ul&gt;
&lt;li&gt;ブログ更新頻度による変動&lt;&#x2F;li&gt;
&lt;li&gt;新規ブログ立ち上げ時のビルド増加&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;S3&lt;&#x2F;strong&gt;: $2.89（6月に急増）
&lt;ul&gt;
&lt;li&gt;動画バックアップによる累積的増加&lt;&#x2F;li&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;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;Budget設計方針&quot;&gt;Budget設計方針&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;全体予算&lt;&#x2F;strong&gt;: 過去最高額の150%程度で設定（余裕を持たせる）&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;アラート設定&lt;&#x2F;strong&gt;: 80%と100%の2段階（50%は省略してアラート疲れを防ぐ）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;3._実際の設定内容&quot;&gt;3. 実際の設定内容&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;3.1_ゼロ支出予算（未使用サービス監視）&quot;&gt;3.1 ゼロ支出予算（未使用サービス監視）&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: UnusedServices-ZeroSpend&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $0.01&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;対象サービス: KMS, Secrets Manager, SNSなど&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;CLI設定&lt;&#x2F;strong&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; budgets create-budget&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&quot;&gt;  --account-id&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-string&quot;&gt;ACCOUNT_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;D&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-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&quot;&gt;  --budget file:&#x2F;&#x2F;zero-spend-budget.json&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&quot;&gt;  --notifications-with-subscribers file:&#x2F;&#x2F;notifications.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;zero-spend-budget.json&lt;&#x2F;strong&gt;&lt;&#x2F;p&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;BudgetName&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;UnusedServices-ZeroSpend&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;BudgetLimit&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;Amount&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;0.01&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-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Unit&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;USD&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;TimeUnit&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;MONTHLY&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;BudgetType&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;COST&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;CostFilters&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;Service&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 z-definition z-string z-string&quot;&gt;      &amp;quot;AWS Key Management Service&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-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;AWS Secrets Manager&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-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;Amazon Simple Notification Service&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-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;Amazon Simple Queue Service&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-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;AmazonCloudWatch&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;h3 id=&quot;3.2_月次全体予算&quot;&gt;3.2 月次全体予算&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: Monthly-Total-Budget&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $7.00&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;アラート: 80%、100%、100%予測&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;CloudFormationテンプレート&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;AWSTemplateFormatVersion&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 z-definition z-string z-string&quot;&gt; &amp;quot;2010-09-09&amp;quot;&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-tag z-yaml&quot;&gt;Description&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 z-definition z-string z-string&quot;&gt; &amp;quot;AWS Budget Configuration&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-entity z-name z-tag z-yaml&quot;&gt;Resources&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  MonthlyTotalBudget&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&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-string&quot;&gt; AWS::Budgets::Budget&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-tag z-yaml&quot;&gt;    Properties&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;      Budget&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;        BudgetName&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-string&quot;&gt; Monthly-Total-Budget&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-tag z-yaml&quot;&gt;        BudgetLimit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          Amount&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-constant z-numeric&quot;&gt; 7.0&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-tag z-yaml&quot;&gt;          Unit&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-string&quot;&gt; USD&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-tag z-yaml&quot;&gt;        TimeUnit&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-string&quot;&gt; MONTHLY&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-tag z-yaml&quot;&gt;        BudgetType&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-string&quot;&gt; COST&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-tag z-yaml&quot;&gt;      NotificationsWithSubscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; Notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;            NotificationType&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-string&quot;&gt; ACTUAL&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-tag z-yaml&quot;&gt;            ComparisonOperator&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-string&quot;&gt; GREATER_THAN&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-tag z-yaml&quot;&gt;            Threshold&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-constant z-numeric&quot;&gt; 80&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-tag z-yaml&quot;&gt;            ThresholdType&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-string&quot;&gt; PERCENTAGE&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-tag z-yaml&quot;&gt;          Subscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; SubscriptionType&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-string&quot;&gt; EMAIL&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-tag z-yaml&quot;&gt;              Address&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-string&quot;&gt; your-email@example.com&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-tag z-yaml&quot;&gt; Notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;            NotificationType&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-string&quot;&gt; ACTUAL&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-tag z-yaml&quot;&gt;            ComparisonOperator&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-string&quot;&gt; GREATER_THAN&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-tag z-yaml&quot;&gt;            Threshold&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-constant z-numeric&quot;&gt; 100&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-tag z-yaml&quot;&gt;            ThresholdType&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-string&quot;&gt; PERCENTAGE&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-tag z-yaml&quot;&gt;          Subscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; SubscriptionType&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-string&quot;&gt; EMAIL&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-tag z-yaml&quot;&gt;              Address&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-string&quot;&gt; your-email@example.com&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-tag z-yaml&quot;&gt; Notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;            NotificationType&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-string&quot;&gt; FORECASTED&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-tag z-yaml&quot;&gt;            ComparisonOperator&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-string&quot;&gt; GREATER_THAN&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-tag z-yaml&quot;&gt;            Threshold&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-constant z-numeric&quot;&gt; 100&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-tag z-yaml&quot;&gt;            ThresholdType&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-string&quot;&gt; PERCENTAGE&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-tag z-yaml&quot;&gt;          Subscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; SubscriptionType&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-string&quot;&gt; EMAIL&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-tag z-yaml&quot;&gt;              Address&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-string&quot;&gt; your-email@example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3.3_Amplify予算&quot;&gt;3.3 Amplify予算&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: Amplify-Monthly-Budget&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $3.50&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;アラート: 50%、80%、100%、100%予測&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;CLI設定&lt;&#x2F;strong&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;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; budgets create-budget&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&quot;&gt;  --account-id&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-string&quot;&gt;ACCOUNT_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;D&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-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;  --budget &amp;#39;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;BudgetName&amp;quot;: &amp;quot;Amplify-Monthly-Budget&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;BudgetLimit&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Amount&amp;quot;: &amp;quot;3.50&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Unit&amp;quot;: &amp;quot;USD&amp;quot;&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;TimeUnit&amp;quot;: &amp;quot;MONTHLY&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;BudgetType&amp;quot;: &amp;quot;COST&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;CostFilters&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Service&amp;quot;: [&amp;quot;AWS Amplify&amp;quot;]&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;&#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;  }&amp;#39;&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;  --notifications-with-subscribers &amp;#39;[&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Notification&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;NotificationType&amp;quot;: &amp;quot;ACTUAL&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;ComparisonOperator&amp;quot;: &amp;quot;GREATER_THAN&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;Threshold&amp;quot;: 50,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;ThresholdType&amp;quot;: &amp;quot;PERCENTAGE&amp;quot;&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Subscribers&amp;quot;: [{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;SubscriptionType&amp;quot;: &amp;quot;EMAIL&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;Address&amp;quot;: &amp;quot;your-email@example.com&amp;quot;&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-string z-punctuation z-definition z-string&quot;&gt;  ]&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3.4_S3予算&quot;&gt;3.4 S3予算&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: S3-Storage-Monitor&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $2.00&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;アラート: 50%、80%、100%、100%予測&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Terraform設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;aws_budgets_budget&amp;quot; &amp;quot;s3_budget&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-variable z-other z-readwrite&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;quot;S3-Storage-Monitor&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  budget_type&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;quot;COST&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  limit_amount&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;quot;2.0&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  limit_unit&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;quot;USD&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  time_unit&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;quot;MONTHLY&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-entity z-name z-type&quot;&gt;  cost_filter&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-other z-readwrite&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;quot;Service&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    values&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;quot;Amazon Simple Storage Service&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-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-entity z-name z-type&quot;&gt;  notification&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-other z-readwrite&quot;&gt;    comparison_operator&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;quot;GREATER_THAN&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold&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; 80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold_type&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;quot;PERCENTAGE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    notification_type&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;quot;ACTUAL&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    subscriber_email_addresses&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;quot;your-email@example.com&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-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-entity z-name z-type&quot;&gt;  notification&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-other z-readwrite&quot;&gt;    comparison_operator&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;quot;GREATER_THAN&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold&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; 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold_type&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;quot;PERCENTAGE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    notification_type&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;quot;FORECASTED&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    subscriber_email_addresses&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;quot;your-email@example.com&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-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;h2 id=&quot;今後の改善ポイント&quot;&gt;今後の改善ポイント&lt;&#x2F;h2&gt;
&lt;p&gt;金額的にはわずかですが、次のようなこともやってよいかなと思っています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Cost Anomaly Detectionの設定&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;機械学習による異常検知&lt;&#x2F;li&gt;
&lt;li&gt;前月比50%以上の増加で自動通知&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;タグベースの予算管理&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;環境別（dev&#x2F;prod）のタグ付け&lt;&#x2F;li&gt;
&lt;li&gt;プロジェクト別のコスト追跡&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;四半期・年間予算の追加&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;長期的なコスト管理&lt;&#x2F;li&gt;
&lt;li&gt;年間$80程度を想定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;自動アクションの設定&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算超過時の非本番環境の自動停止&lt;&#x2F;li&gt;
&lt;li&gt;Lambda関数によるコスト最適化&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;S3ライフサイクルポリシー(既に実施)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;古い動画ファイルをGlacierへ移行&lt;&#x2F;li&gt;
&lt;li&gt;アクセス頻度の低いコンテンツのコスト最適化&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&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;docs.aws.amazon.com&#x2F;cost-management&#x2F;latest&#x2F;userguide&#x2F;budgets-managing-costs.html&quot;&gt;AWS Budgets ドキュメント&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;cli&#x2F;latest&#x2F;reference&#x2F;budgets&#x2F;index.html&quot;&gt;AWS CLI Budgets リファレンス&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AWSCloudFormation&#x2F;latest&#x2F;UserGuide&#x2F;aws-resource-budgets-budget.html&quot;&gt;CloudFormation Budgets リソース&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">個人AWSアカウントのコスト管理を効率的に行うためのAWS Budget設定ガイド。月額数ドルの利用でも予期しない請求を防ぐため、ゼロ支出予算、月次全体予算、サービス別予算の3層構造で監視する実践的な設定方法を紹介。CloudFormation、CLI、Terraformを使った具体的な実装例付き。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic MCP Inspectorに重大な脆弱性</title>
        <published>2025-07-02T00:00:00+00:00</published>
        <updated>2025-07-02T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/anthropic-mcp-inspector-vulnerability/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/anthropic-mcp-inspector-vulnerability/</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;開発者向けツールとはいえ、CVSSスコア9.4という深刻度の高さに、セキュリティ対策の重要性を改めて認識させられました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;jrnlのジャーナルにClaude Desktopなどからアクセスを可能とするMCPサーバーを開発中で、
統合テスト時にドライバーを探していてMCP Inspectorを検討していたところ、脆弱性の報告があり驚きました。
開発者向けツールとはいえ、CVSSスコア9.4という深刻度の高さに、セキュリティ対策の重要性を改めて認識しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCP_Inspector_とは何？&quot;&gt;MCP Inspector とは何？&lt;&#x2F;h2&gt;
&lt;p&gt;MCP Inspectorは、Anthropicが提供するModel Context Protocol (MCP) サーバーのテスト・デバッグツールです。MCPは2024年11月に発表された、LLMアプリケーションと外部データソースやツールとの連携を標準化するオープンプロトコルです。&lt;&#x2F;p&gt;
&lt;p&gt;MCP Inspectorは主に以下のような場面で使用されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;MCPサーバー開発者が実装の動作確認を行う際&lt;&#x2F;li&gt;
&lt;li&gt;API統合のデバッグやトラブルシューティング時&lt;&#x2F;li&gt;
&lt;li&gt;本番環境へのデプロイ前の検証作業&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ツールはWeb UIを提供するクライアントと、各種MCPサーバーへの接続を仲介するプロキシサーバーで構成されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCP_Inspector_の脆弱性とは&quot;&gt;MCP Inspector の脆弱性とは&lt;&#x2F;h2&gt;
&lt;p&gt;2025年7月に報告された脆弱性CVE-2025-49596は、悪意のあるWebサイトにアクセスするだけでリモートコード実行を可能にする重大な問題です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;thehackernews.com&#x2F;2025&#x2F;07&#x2F;critical-vulnerability-in-anthropics.html&quot;&gt;元記事：Critical Vulnerability in Anthropic&#x27;s MCP Exposes Developer Machines to Remote Exploits&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;攻撃手法は以下の要素を組み合わせたものです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;19年前から存在するブラウザの脆弱性「0.0.0.0 Day」を利用&lt;&#x2F;li&gt;
&lt;li&gt;MCP InspectorのCSRF脆弱性と連鎖させる&lt;&#x2F;li&gt;
&lt;li&gt;localhostで動作するサービスへ不正なリクエストを送信&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;根本原因はデフォルト設定における認証と暗号化の欠如でした。プロキシサーバーが0.0.0.0でリッスンし、クライアントとの間に認証機構がなかったため、任意のコマンド実行が可能となっていました。&lt;&#x2F;p&gt;
&lt;p&gt;影響範囲はMCP Inspectorを使用している開発者に限定されます。一般のMCPユーザーや本番環境のMCPサーバーには直接影響しません。ただし、攻撃を受けた開発者のマシンから機密情報が漏洩したり、ネットワーク内への侵入経路として悪用される可能性があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;この脆弱性は2025年6月13日にリリースされたバージョン0.14.1で修正されています。MCP Inspectorを使用している開発者は直ちにアップデートすることを推奨します。&lt;&#x2F;p&gt;
&lt;p&gt;開発ツールであっても適切なセキュリティ対策が必要であることを示す事例となりました。
特にlocalhostで動作するサービスも攻撃対象となりうることを認識し、
開発環境のセキュリティにも十分な注意を払う必要があると肝に銘じました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">開発者向けツールとはいえ、CVSS スコア 9.4 という深刻度の高さに、セキュリティ対策の重要性を改めて認識させられました。</summary>
        </entry><entry xml:lang="en">
        <title>生成AIでメール管理 - Claude Desktop x FastmailMCP連携</title>
        <published>2025-06-28T00:00:00+00:00</published>
        <updated>2025-06-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/claude-desktop-fastmail-mcp/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/claude-desktop-fastmail-mcp/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;06&amp;#x2F;claude-desktop-fastmail-mcp&amp;#x2F;mail.webp?h=347bde3591a9eb6b4437&quot;
  alt=&quot;Mail with AI&quot; width=&quot;1456&quot; height=&quot;816&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;Claude Desktopの最新機能であるMCP（Model Context Protocol）を使って、プライバシー重視のメールサービス「Fastmail」とClaude Desktopを連携させ、AIアシスタントにメール管理を手伝ってもらう方法をご紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに_-_生成AIがメールを扱う時代&quot;&gt;はじめに - 生成AIがメールを扱う時代&lt;&#x2F;h2&gt;
&lt;p&gt;メールの確認、返信、整理...日々の業務で避けて通れないメール管理。この作業を生成AIに任せられたらどうでしょうか？
MCPを使って生成AIとメールサービスを連携できれば、実は比較的簡単に実現できます。&lt;&#x2F;p&gt;
&lt;p&gt;「最近の重要なメールを要約して」「特定の人からのメールを検索して」といった指示を出すだけで、AIがメールボックスを確認し、必要な情報を提示してくれる。そんな未来がもう実現可能なのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPとは何か_-_Claude_Desktopの拡張機能&quot;&gt;MCPとは何か - Claude Desktopの拡張機能&lt;&#x2F;h2&gt;
&lt;p&gt;MCP（Model Context Protocol）は、Claude Desktopに外部ツールとの連携機能を追加するプロトコルです。これにより、Claudeは単なるチャットボットから、実際にツールを操作できるAIアシスタントへと進化します。&lt;&#x2F;p&gt;
&lt;p&gt;今回使用する&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alexdiazdecerio&#x2F;fastmail-mcp-server&quot;&gt;fastmail-mcp-server&lt;&#x2F;a&gt;は、Alex Diaz de Cerio氏が開発したオープンソースのMCPサーバーです。このサーバーは、FastmailのJMAP API（JSON Meta Application Protocol）を介してメールサービスと通信し、Claudeがメールの読み取り、送信、検索、整理などを行えるようにします。TypeScriptで実装されており、12以上のツールを提供する包括的なメール管理ソリューションです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Fastmail_MCPサーバーのセットアップ&quot;&gt;Fastmail MCPサーバーのセットアップ&lt;&#x2F;h2&gt;
&lt;p&gt;セットアップは思ったより簡単でした。以下の手順で進めます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;前提条件&quot;&gt;前提条件&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 18以上&lt;&#x2F;li&gt;
&lt;li&gt;Fastmailアカウント（APIアクセスが可能なプラン）&lt;&#x2F;li&gt;
&lt;li&gt;Claude Desktop&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;1._MCPサーバーのインストール&quot;&gt;1. MCPサーバーのインストール&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-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g @alexdiazdecerio&#x2F;fastmail-mcp-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._FastmailでAPIトークンを取得&quot;&gt;2. FastmailでAPIトークンを取得&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&quot;&gt;Fastmail&lt;&#x2F;a&gt;にログイン&lt;&#x2F;li&gt;
&lt;li&gt;Settings → Privacy &amp;amp; Security → Integrations → &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&#x2F;settings&#x2F;security&#x2F;tokens&quot;&gt;API tokens&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;新しいトークンを作成（Mail、Submission権限を付与）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;3._Claude_Desktopの設定&quot;&gt;3. Claude Desktopの設定&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;Claude&#x2F;claude_desktop_config.json&lt;&#x2F;code&gt;を編集します。&lt;&#x2F;p&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;fastmail&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;fastmail-mcp&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&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;FASTMAIL_EMAIL&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;あなたのメール@fastmail.com&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;FASTMAIL_API_TOKEN&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;取得したAPIトークン&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;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;Claude Desktopを再起動すれば準備完了です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;実際の使用感と活用シーン&quot;&gt;実際の使用感と活用シーン&lt;&#x2F;h2&gt;
&lt;p&gt;設定が完了したら、早速使ってみましょう。Claude Desktopに依頼するだけで、様々なメール操作が可能になります。&lt;&#x2F;p&gt;
&lt;p&gt;「最近のメールの一覧を見せて。ただし広告メールは除外して。」と入力するだけで、Claudeが最新のメールリストを表示してくれます。
メール種別、件名、送信者、日時が整理された形で提示されて表示されます。
「メール種別」はClaudeがメールを見てカテゴライズしてくれている項目なので、従来のメールクライアントでは不可能な項目です。&lt;&#x2F;p&gt;
&lt;p&gt;注意点は、メールを表示しただけでは既読にならないという仕様です。
これはプライバシーとセキュリティを考慮した設計で、意図しない既読マークを防いでいます。
既読にしたい場合は、「このメールを既読にして」と明示的に指示する必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;メールの送信も同様にシンプルです。「田中さんに以下の内容でメールを送って。
件名はプロジェクトの進捗報告、本文にお疲れ様です。今週の進捗を報告します...」といった指示で、メールの作成から送信まで一気に実行してくれます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、現時点では一部制限もあります。添付ファイルの送信、HTMLメールの作成（プレーンテキストのみ対応）、送信済みメールの自動保存、カレンダー連携などは対応していません。&lt;&#x2F;p&gt;
&lt;p&gt;generate_email_analyticsの機能を呼び出せば、どのようなメールがどのような分布
で来ているかを分析してくれます。&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;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc8621&quot;&gt;JMAP仕様（RFC 8621）&lt;&#x2F;a&gt;の設計によるものだとわかりました。&lt;&#x2F;p&gt;
&lt;p&gt;JMAPでは送信（EmailSubmission）とメールボックスへの保存が意図的に別操作として設計されており、送信成功時に自動的に送信済みフォルダに保存するには&lt;code&gt;onSuccessUpdateEmail&lt;&#x2F;code&gt;パラメータの実装が必要です。しかし、現在のfastmail-mcp-serverではこのパラメータがまだサポートされていません。&lt;&#x2F;p&gt;
&lt;p&gt;作者の方に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alexdiazdecerio&#x2F;fastmail-mcp-server&#x2F;issues&quot;&gt;GitHubリポジトリ&lt;&#x2F;a&gt;でissueを作成し機能追加をリクエストしています。
暫定対応としてはBCCに自分のアドレスを追加をすればよいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;この問題は多くのJMAP実装で共通の課題となっており、コミュニティでの議論が活発に行われています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;今後の可能性とまとめ&quot;&gt;今後の可能性とまとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude DesktopとFastmailの連携により、メール管理の新しい可能性が広がりました。自然言語でメールを操作できることで、以下のような未来が期待できます。&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;AI による返信提案&lt;&#x2F;strong&gt;: 文脈を理解した返信文の自動生成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;メールの自動分類&lt;&#x2F;strong&gt;: AIによる重要度判定とフォルダ振り分け&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;現時点では送信済みメールの保存など、いくつかの制限がありますが、fastmail-mcp-serverは活発に開発が続けられており、MCPエコシステム全体も急速に発展しています。オープンソースコミュニティの力で、これらの課題も近い将来解決されることでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIにメール管理を任せる第一歩として、ぜひFastmail MCPサーバーを試してみてください。日々のルーティンワークから解放され、より創造的な業務に集中できる時間が生まれるはずです。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&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;github.com&#x2F;alexdiazdecerio&#x2F;fastmail-mcp-server&quot;&gt;fastmail-mcp-server (GitHub)&lt;&#x2F;a&gt; - 本記事で使用したMCPサーバー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&quot;&gt;Fastmail&lt;&#x2F;a&gt; - プライバシー重視のメールサービス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&#x2F;dev&#x2F;&quot;&gt;Fastmail API Documentation&lt;&#x2F;a&gt; - JMAP APIの詳細&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc8621&quot;&gt;JMAP Specification (RFC 8621)&lt;&#x2F;a&gt; - JMAPプロトコル仕様&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;model-context-protocol&quot;&gt;Model Context Protocol&lt;&#x2F;a&gt; - MCPの公式情報&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">Claude Desktopの最新機能であるMCP（Model Context Protocol）を使って、プライバシー重視のメールサービス「Fastmail」とClaude Desktopを連携させ、AIアシスタントにメール管理を手伝ってもらう方法をご紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic、東京拠点と日本語版Claudeのリリース発表</title>
        <published>2025-06-26T00:00:00+00:00</published>
        <updated>2025-06-26T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/anthropic-will-launch-tokyo-center/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/anthropic-will-launch-tokyo-center/</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;Anthropicが2025年秋に東京拠点の開設とClaude日本語版のリリースを発表。企業向けAI活用の加速と、Claude CodeやMaxプランの利用体験について考察します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Anthropic、日本拠点開設&quot;&gt;Anthropic、日本拠点開設&lt;&#x2F;h2&gt;
&lt;p&gt;生成AIと言えば一般には「ChatGPT」という感じですが、
AIモデルと外部サービスを繋ぐ規格としてデファクトスタンダードになりつつある
MCP(Model Context Protocol)の開発やClaude Codeなど昨年末から立て続けに発表し
ているAnthropic社に個人的には勢いを感じていました。&lt;&#x2F;p&gt;
&lt;p&gt;実は日本でも企業への導入はClaudeが進んでいるそうです。
AnthropicのClaudeはAWSのAmazon Bedrock上でもInvoleModelやConverse APIを通じ
て利用できます。AWSはクラウド基盤として企業に浸透しているので、一般に知られ
ている以上に企業で浸透しているのでしょうか。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.itmedia.co.jp&#x2F;aiplus&#x2F;articles&#x2F;2506&#x2F;25&#x2F;news076.html&quot;&gt;
  &lt;p&gt;
    米Anthropicは6月25日（日本時間）、秋ごろに東京都に拠点を開設すると発表した。併せて、同社のAIサービス「Claude」の日本語版をリリースする。同社がアジア太平洋地域で拠点を開設するのは今回が初。
  &lt;&#x2F;p&gt;
  &lt;footer&gt;
    &lt;cite&gt;
      &lt;a href=&quot;https:&#x2F;&#x2F;www.itmedia.co.jp&#x2F;aiplus&#x2F;articles&#x2F;2506&#x2F;25&#x2F;news076.html&quot;&gt;
        IT Media AI+
        「米AI企業のAnthropic、東京に拠点開設へ　「Claude」日本語版もリリース予定」
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;Claude日本語版&quot;&gt;Claude日本語版&lt;&#x2F;h2&gt;
&lt;p&gt;同時にClaude日本語版が提供されるとされています。&lt;&#x2F;p&gt;
&lt;p&gt;Claude自体は現在でも日本語を扱えますし、
Claude Web版やDesktop版も完全に国際化対応されており、日本語OSのもとでは完全に
ローカライズされているように見えます。&lt;&#x2F;p&gt;
&lt;p&gt;これは何を意味するのか、今後も注目したいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Maxプラン&quot;&gt;Claude Maxプラン&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Proプランを年間契約していましたが、
Claude Maxプランの利用を始めました。&lt;&#x2F;p&gt;
&lt;p&gt;理由はClaude Codeです。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeは β版から利用しているのでAPI利用による従量課金で使用していました。
Claude Codeが正式リリースされてからはProプランでも使用できるようになりま
した。
しかし、Anthropic社の&quot;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.anthropic.com&#x2F;en&#x2F;articles&#x2F;11145838-using-claude-code-with-your-pro-or-max-plan?utm_source=chatgpt.com&quot;&gt;Using Claude Code with your Pro or Max Plan&lt;&#x2F;a&gt;&quot;
という記事によると、目安として、5時間で約45件のチャットor 10〜40回のClaude
Codeプロンプトしか利用できません。実際に使っていると大抵上限に達してしまうので、
使用する際は従量課金で使用していました。&lt;&#x2F;p&gt;
&lt;p&gt;直近Claude Codeの利用率がどんどん上がっていてあまりに便利でこれは月$100でもよいかなと思えたので、Maxプランに移行
してみました。&lt;&#x2F;p&gt;
&lt;p&gt;これにより、次の恩恵があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;上限がProプランの5倍となる&lt;&#x2F;li&gt;
&lt;li&gt;ProプランではClaude Codeで使用できないOpusモデルを使用可能となる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;なお、Claude Codeで従量課金か定額プランかを変更する際には、
プランを登録するだけでは変わらず、Claude Code上でログアウトして
使いたいプランに合わせて再ログインをする必要があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicの東京拠点開設と日本語版Claudeのリリースは、日本におけるAI活用の
新たな段階を示しています。企業での導入が進む中、MCPやClaude Codeなどの
革新的なツールの提供により、開発者にとってもより身近な存在になりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;個人的にはClaude Codeの利便性から、ProプランからMaxプランへの移行を決断しました。
月額$100という価格設定ですが、開発効率の向上を考えると十分な価値があると感じています。&lt;&#x2F;p&gt;
&lt;p&gt;今後、日本語版の提供により、どのような新機能や最適化が行われるのか、
そして日本市場へのコミットメントがどのように具体化されるのか、注目していきたいと思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropicが2025年秋に東京拠点の開設とClaude日本語版のリリースを発表。企業向けAI活用の加速と、Claude CodeやMaxプランの利用体験について考察します。</summary>
        </entry><entry xml:lang="en">
        <title>MulmoCast: AIと人間が協働する次世代プレゼンテーション・プラットフォームを試してみた</title>
        <published>2025-06-24T00:00:00+00:00</published>
        <updated>2025-06-24T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/mulmocast-ai-collaboration-platform/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/mulmocast-ai-collaboration-platform/</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;あの中島聡氏が開発している
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;receptron&#x2F;mulmocast-cli&quot;&gt;mulmocast&lt;&#x2F;a&gt; の検証しました。
ガイドにしたがって、ビジネスプレゼンテーションと子供用の絵本的な動画を作って
みました。生成AIのモデルはClaudeやGeminiも選択できるようですが、今回は
デフォルトのままOpenAIを使いました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MulmoCastとは何か？その意義は？&quot;&gt;MulmoCastとは何か？その意義は？&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastは、AI時代に特化して設計された次世代のプレゼンテーション・プラッ
トフォームです。従来のPowerPointやKeynoteがAI以前の時代に人間のクリエ
イター向けに設計されたのに対し、MulmoCastは最初からAIネイティブなツールと
して開発されています。&lt;&#x2F;p&gt;
&lt;p&gt;最大の特徴は、 1つのスクリプトから動画、ポッドキャスト、スライドショー
など、複数のフォーマットに自動変換できることです。
現代では情報消費のチャネルが多様化しており、Zoomでのプレゼンテーション、Slackでの共有、移動中の動画視聴、通勤時のポッドキャスト聴取など、様々な場面に対応する必要があります。MulmoCastはこの課題を解決します。&lt;&#x2F;p&gt;
&lt;p&gt;核となるのは「MulmoScript」というJSON&#x2F;YAML形式の中間言語です。これは映画の脚本やWebマークアップのような役割を果たし、ChatGPTやClaudeなどの大規模言語モデルが理解・生成できる形式になっています。AIがストーリー構造からビジュアルまでをすべて定義し、人間はクリエイティブループの中で方向性を決めるという協働モデルを実現しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;インストール方法（Mac）&quot;&gt;インストール方法（Mac）&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastのインストールは比較的簡単です。Node.jsとffmpegが必要になります。&lt;&#x2F;p&gt;
&lt;p&gt;まず、NPMを使ってMulmoCastをグローバルインストールします。&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;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g mulmocast&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次に、動画生成に必要なffmpegをインストールします。Macの場合はHomebrewを使用します。&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 ffmpeg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後に、プロジェクトディレクトリに&lt;code&gt;.env&lt;&#x2F;code&gt;ファイルを作成し、必要なAPIキーを設定します。&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-source&quot;&gt;OPENAI_API_KEY&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;your_openai_api_key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;DEFAULT_OPENAI_IMAGE_MODEL&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;gpt-image-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;GOOGLE_PROJECT_ID&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;your_google_project_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;NIJIVOICE_API_KEY&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;your_nijivoice_api_key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;BROWSERLESS_API_TOKEN&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;your_browserless_api_token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;OpenAI APIキーは必須ですが、他のAPIキーは使用する機能に応じて設定してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;基本的な使い方&quot;&gt;基本的な使い方&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastの基本的な使い方は2ステップです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ1：スクリプト生成&quot;&gt;ステップ1：スクリプト生成&lt;&#x2F;h3&gt;
&lt;p&gt;まず、AIとの対話でストーリースクリプトを作成します。&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;mulmo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; tool scripting -i -t business -o .&#x2F; -s story&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドの説明は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;&#x2F;code&gt;: インタラクティブモード&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-t business&lt;&#x2F;code&gt;: ビジネステンプレートを使用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-o .&#x2F;&lt;&#x2F;code&gt;: 出力ディレクトリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-s story&lt;&#x2F;code&gt;: ファイル名のプレフィックス&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;実行すると、AIとの対話が始まります。コンテンツの内容、ターゲット層、長さなどについて質問され、それに応えることでMulmoScript形式のJSONファイル（例：&lt;code&gt;story-1746600802426.json&lt;&#x2F;code&gt;）が生成されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ2：動画生成&quot;&gt;ステップ2：動画生成&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;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mulmo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; movie story-1746600802426.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンド1つで、音声合成、画像生成、動画編集までが自動実行され、最終的にMP4ファイルが出力されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;利用可能なテンプレート&quot;&gt;利用可能なテンプレート&lt;&#x2F;h3&gt;
&lt;p&gt;用途に応じて以下のテンプレートも選択できます。なんとなくどんなものが出来るか
想像できますね。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;akira_comic&lt;&#x2F;li&gt;
&lt;li&gt;business&lt;&#x2F;li&gt;
&lt;li&gt;children_book&lt;&#x2F;li&gt;
&lt;li&gt;coding&lt;&#x2F;li&gt;
&lt;li&gt;comic_strips,&lt;&#x2F;li&gt;
&lt;li&gt;drslump_comic&lt;&#x2F;li&gt;
&lt;li&gt;ghibli_comic&lt;&#x2F;li&gt;
&lt;li&gt;ghibli_image_only&lt;&#x2F;li&gt;
&lt;li&gt;ghibli_shorts,&lt;&#x2F;li&gt;
&lt;li&gt;ghost_comic&lt;&#x2F;li&gt;
&lt;li&gt;onepiece_comic&lt;&#x2F;li&gt;
&lt;li&gt;podcast_standard&lt;&#x2F;li&gt;
&lt;li&gt;portrait_movie,&lt;&#x2F;li&gt;
&lt;li&gt;realistic_movie&lt;&#x2F;li&gt;
&lt;li&gt;sensei_and_taro&lt;&#x2F;li&gt;
&lt;li&gt;shorts&lt;&#x2F;li&gt;
&lt;li&gt;text_and_image,&lt;&#x2F;li&gt;
&lt;li&gt;text_only&lt;&#x2F;li&gt;
&lt;li&gt;trailer&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;検証結果&quot;&gt;検証結果&lt;&#x2F;h2&gt;
&lt;p&gt;今回、ビジネスプレゼンテーションと子供用絵本の2つのパターンで検証しました。
生成AIモデルはClaudeやGeminiも選択可能ですが、今回はデフォルトのOpenAIを
使用しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;mulmo tool scripting -i -t business -o .&#x2F; -s story&lt;&#x2F;code&gt; でAgentと会話してストーリーを練って、&lt;code&gt;mulmo movie story-xxxxxxxxxxxxx.json&lt;&#x2F;code&gt;で動画を生成します。&lt;&#x2F;p&gt;
&lt;p&gt;ちょっとした会話でそれらしいプレゼンテーション動画が出来ます。以下がその動画
です。&lt;&#x2F;p&gt;
&lt;div class=&quot;youtube-container&quot; style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;mAp5ORk2Zas&quot;
    style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&quot;
    frameborder=&quot;0&quot;
    allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;実際に使ってみた感想として、簡単な会話だけでそれらしいプレゼンテーション動画
が生成できることに驚きました。内容の深みという点では限界がありますが、1st
Callの資料としては十分に実用的なレベルに達していると感じました。&lt;&#x2F;p&gt;
&lt;p&gt;特に印象的だったのは、一度スクリプトを作成すれば、そこから動画、ポッドキャス
ト、PDFなど複数フォーマットに展開できる点です。コンテンツの再利用性が高く、
効率的な情報発信が可能になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastは、AI時代のコンテンツ作成における新しい可能性を示すツールです。従
来のプレゼンテーション作成が「人間がすべてを制作する」モデルだったのに対し、
「AIと人間が協働して作成する」という新しいパラダイムを提示しています。&lt;&#x2F;p&gt;
&lt;p&gt;現時点では完全に実用レベルに達しているとは言えませんが、プロトタイプや初期段
階の資料作成には十分活用できると感じました。
特に、アイデアの可視化や概念の説明では、従来よりもはるかにコンテンツ作成を効率化できます。&lt;&#x2F;p&gt;
&lt;p&gt;今後、AIの精度向上とともにMulmoCastのようなツールがより洗練されれば、コンテ
ンツ作成の方法が根本的に変わる可能性があります。単一のスクリプトから多様なメ
ディアフォーマットに展開できる仕組みは、情報発信の効率化に大きく貢献するでし
ょう。&lt;&#x2F;p&gt;
&lt;p&gt;興味のある方は、ぜひ一度試してみることをお勧めします。AI協働時代のコンテンツ作成を体験できる貴重なツールです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">AIネイティブなプレゼンテーション・プラットフォーム「MulmoCast」を実際に検証してみました。一つのスクリプトから動画、ポッドキャスト、PDFなど複数フォーマットに自動変換できる革新的なツールの使い方と実用性について詳しく解説します。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Code MCPセットアップガイド：Inkdrop統合の実践</title>
        <published>2025-06-21T00:00:00+00:00</published>
        <updated>2025-06-21T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/claude-code-mcp-setup-guide/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/claude-code-mcp-setup-guide/</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;5月Claude Codeが正式リリースされて以来手放せなくなっています。
Anthropicの
ブログに&quot;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;claude-code-remote-mcp&quot;&gt;Remote MCP support in Claude Code&lt;&#x2F;a&gt;&quot;
という記事が掲載されました。&lt;&#x2F;p&gt;
&lt;p&gt;早速Claude CodeでInkdrop MCPサーバーを設定し、リモートMCPサーバーとして統合
する手順を実際にセットアップしながら検証してみました。単純な設定から高度なワ
ークフローまで、実践的な内容をまとめています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPサーバーの追加&quot;&gt;MCPサーバーの追加&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeにInkdrop MCPサーバーを追加するには、以下のコマンドを実行します。&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;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp add inkdrop &#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&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&quot;&gt;  -e INKDROP_LOCAL_SERVER_URL=http:&#x2F;&#x2F;localhost:19840&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&quot;&gt;  -e INKDROP_LOCAL_USERNAME=hogehoge&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&quot;&gt;  -e INKDROP_LOCAL_PASSWORD=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;*****************&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&quot;&gt;  -s local&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドの設定は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inkdrop&lt;&#x2F;code&gt;：MCPサーバー名&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;code&gt;：実行ファイルパス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;&#x2F;code&gt;：環境変数の設定（サーバーURL、認証情報）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-s local&lt;&#x2F;code&gt;：ローカルスコープでの設定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;設定の確認&quot;&gt;設定の確認&lt;&#x2F;h2&gt;
&lt;p&gt;追加したMCPサーバーが正しく設定されているか確認します。&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;# 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;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp list&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;# 特定の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;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp get inkdrop&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;inkdrop:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Scope: Local (private to you in this project)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Type: stdio&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Command: &#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Environment:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    INKDROP_LOCAL_SERVER_URL=http:&#x2F;&#x2F;localhost:19840&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    INKDROP_LOCAL_USERNAME=hogehoge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    INKDROP_LOCAL_PASSWORD=************&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_Codeでの動作確認&quot;&gt;Claude Codeでの動作確認&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを起動してMCPサーバーとの接続を確認します。&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;claude&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Code内で &lt;code&gt;&#x2F;mcp&lt;&#x2F;code&gt; コマンドを実行すると、接続されたMCPサーバーの状態を確認できます。正常に接続された場合は、次のような結果になります。
接続状況とどんなコマンドが利用可能か確認できます。&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;❯ 1. inkdrop  ✔ connected · Enter to view details&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;Status: ✔ connected&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Command: &#x2F;Users&#x2F;yostos&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Capabilities: tools · prompts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Tools: 7 tools&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;利用可能なツール:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. read-note&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. search-notes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. list-notes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. create-note&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5. update-note&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(他2つのツールあり)&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;h3 id=&quot;基本的な検索機能&quot;&gt;基本的な検索機能&lt;&#x2F;h3&gt;
&lt;p&gt;明示的にInkdropを指定することで、MCPツールが確実に呼び出されます。例えば私は
Inkdrop内にflacのエンコーディング方法をまとめているので、以下のような出力が
表示されます適切に該当するノートを読み取ってくれました。&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;Inkdropの&amp;quot;Tech Tips&amp;quot;から適切なflacファイルの作り方を検索して、示してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この指示により、以下の処理が自動実行されます。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;search-notes&lt;&#x2F;code&gt;でキーワード検索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;read-note&lt;&#x2F;code&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;より複雑な処理として、ブログ記事の管理を試してみました。&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;このブログプロジェクトから、2025年5月と6月の記事を確認して、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;タイトル一覧をInkdropのInboxノートブックに新ノートとして作成してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この指示では以下の処理が連携して実行されました。&lt;&#x2F;p&gt;
&lt;ol&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;：5月・6月を別々のTaskエージェントで同時処理&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;内容解析&lt;&#x2F;strong&gt;：各記事のタイトル抽出とカテゴライズ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;MCP統合&lt;&#x2F;strong&gt;：分析結果をInkdropに保存&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;結果として24記事（5月13件、6月11件）のタイトル一覧が自動的にカテゴリ別に整理され、Inkdropに新規ノートとして作成されました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セットアップのポイント&quot;&gt;セットアップのポイント&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;明示的指示の重要性&quot;&gt;明示的指示の重要性&lt;&#x2F;h3&gt;
&lt;p&gt;「Inkdropの...」という明示的な指示により、Claude CodeがMCPツールを確実に呼び出します。曖昧な指示では期待通りに動作しない場合があります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;自動ツール選択&quot;&gt;自動ツール選択&lt;&#x2F;h3&gt;
&lt;p&gt;Claude Codeは文脈に応じて適切なMCPツールを自動選択し、複数のツールを連携させて処理を完了します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;複合タスクの処理能力&quot;&gt;複合タスクの処理能力&lt;&#x2F;h3&gt;
&lt;p&gt;ファイルシステム分析、内容理解、MCP統合といった複合的なタスクを自動化できるのがClaude Codeの真の能力です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeとInkdrop MCPの統合により、以下のメリットが得られます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;コード開発中のメモ参照&lt;&#x2F;strong&gt;：開発中にInkdropのメモを即座に検索・参照可能&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;h3 id=&quot;MCP_を軸とした_Claude_連携の実例&quot;&gt;MCP を軸とした Claude 連携の実例&lt;&#x2F;h3&gt;
&lt;p&gt;実は、この記事の制作プロセス自体がMCP統合の真価を示しています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Claude Desktop での検証設計&lt;&#x2F;strong&gt;：セットアップ手順の相談と検証方法の策定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Desktop による知識蓄積&lt;&#x2F;strong&gt;：検証結果をMCP経由でInkdropのノートに整理・保存&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Code による記事生成&lt;&#x2F;strong&gt;：MCP経由でInkdropから検証ノートを読み込み、ブログ記事として再構成&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;このワークフローでは、Claude DesktopとClaude Codeが同一のInkdropをMCPサーバーとして共有し、知識の橋渡し役として機能しています。単体のツール利用では不可能な、複数のClaude環境を跨いだ継続的な作業が実現されています。&lt;&#x2F;p&gt;
&lt;p&gt;この統合は、開発プロセスにおける知識管理と自動化の新しい可能性を示しており、MCPを軸としたClaudeエコシステムの真の価値がここにあります。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Claude CodeでInkdrop MCPサーバーを設定し、リモートMCPサーバーとして統合する手順を詳しく解説します。実際のセットアップから高度なワークフローの実演まで、ステップバイステップで紹介。</summary>
        </entry><entry xml:lang="en">
        <title>AWSからSMSにメッセージを送る</title>
        <published>2025-06-09T00:00:00+00:00</published>
        <updated>2025-06-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/aws-sns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/aws-sns/</id>
        
            <content type="html">&lt;h2 id=&quot;機密文書のメールでの共有&quot;&gt;機密文書のメールでの共有&lt;&#x2F;h2&gt;
&lt;p&gt;職場では取引先に資料を送付するのに暗号化したZIPでメールし、
パスワードを電話で伝えるということをやっているようです。
最低限のPPAP対策ですが、前時代的ですね。
当然ですが、先方から「電話で伝えられても困る」とよくクレームを受けているようです。
フィアル送信サービスも使っているようですが、「セキュリティ」と言う観点では何
の解決にもなっていません。&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;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;❌：1通盗まれればすべて漏洩&lt;&#x2F;td&gt;&lt;td&gt;❌&lt;&#x2F;td&gt;&lt;td&gt;PPAPの典型。秘匿性は完全に破綻&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;td&gt;傍受・誤送信時に漏洩リスク高&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;③ 暗号化ファイル、またはクラウドストレージ（認証なし） + パスワードをSMSで送信&lt;&#x2F;td&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;◎：パスワード共有不要、URL単体では無効&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;⑤ S&#x2F;MIME暗号化メール&lt;&#x2F;td&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;⑥ GPG暗号メール &#x2F; 公開鍵暗号によるファイル送信&lt;&#x2F;td&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;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;パスワードを別メールで送信&quot;&gt;パスワードを別メールで送信&lt;&#x2F;h2&gt;
&lt;p&gt;本来はS&#x2F;MIMEやGPGを検討すべきでしょうが、S&#x2F;MIMEの費用捻出が難しく、GPGを使う
リテラシーも無いので、次善の策としてSMSでパスワード送信は経路分離できている
分マシだと思いました。&lt;&#x2F;p&gt;
&lt;p&gt;以下はメールとは別の手段でパスワードを伝えるだけならばPC上からこうやってSMSにメッセージを送ることもできますよというデモです。
GUIから任意の電話番号にSMSを送信できます。&lt;&#x2F;p&gt;
&lt;p&gt;Pythonの実行環境が必要です。&lt;&#x2F;p&gt;
&lt;p&gt;処理概要です。あくまでデモです。&lt;&#x2F;p&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[ユーザー]--&gt; B[Python GUIアプリケーション]
B --&gt; C[.env.localファイル]
C --&gt; D[AWS認証情報&lt;br&#x2F;&gt;ACCESS_KEY_ID&lt;br&#x2F;&gt;SECRET_ACCESS_KEY&lt;br&#x2F;&gt;REGION]

    B --&gt; E[電話番号入力&lt;br&#x2F;&gt;+81XXXXXXXXX]
    B --&gt; F[メッセージ入力&lt;br&#x2F;&gt;パスワード等]
    B --&gt; G[送信ボタン]

    G --&gt; H[boto3 SDK]
    H --&gt; I[AWS SNS API]
    I --&gt; J{SMS Sandbox?}

    J --&gt;|Sandbox Mode| K[検証済み番号のみ]
    J --&gt;|Production Mode| L[全世界の番号]

    K --&gt; M[国内キャリア&lt;br&#x2F;&gt;DoCoMo&#x2F;au&#x2F;SoftBank]
    L --&gt; M

    M --&gt; N[受信者の携帯電話]

    I --&gt; O[CloudWatch Logs]
    O --&gt; P[配信ログ&lt;br&#x2F;&gt;成功&#x2F;失敗&#x2F;料金]

    Q[料金] --&gt; R[$0.06-0.1&#x2F;SMS&lt;br&#x2F;&gt;約6-10円&#x2F;通]

    subgraph &quot;ローカル環境&quot;
        B
        C
    end

    subgraph &quot;AWS Cloud&quot;
        I
        J
        O
        P
    end

    subgraph &quot;日本国内&quot;
        M
        N
    end
    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style I fill:#fff3e0
    style N fill:#e8f5e8
    style R fill:#ffebee
&lt;&#x2F;pre&gt;
&lt;p&gt;実際に任意のSMSに送信するには、AWSの管理コンソールでSANDBOXを解除する必要が
あります。また、このままだとユーザー認証していないので誰でも送信できてし
まいます。実際にシステムで行うには、認証した上でログを取得し監査できる状態に
するべきでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;またSMSなので料金が発生します。&lt;&#x2F;p&gt;
&lt;p&gt;こんなことやるくらいなら&lt;strong&gt;さっさと S&#x2F;MINE をちゃんと導入しろよ&lt;&#x2F;strong&gt;と思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ソースコード＆設定&quot;&gt;ソースコード＆設定&lt;&#x2F;h2&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;&#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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;アプリケーション開始&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-storage z-type&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; SNSSender&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-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-magic z-python&quot;&gt; __init__&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;&#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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;SNSSender初期化中...&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;        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-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;sns&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; boto3&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;client&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;quot;sns&amp;quot;&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; region_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;quot;ap-northeast-1&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;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-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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;AWS SNSクライアント作成完了&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;AWS SNSクライアント作成エラー: &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;e&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-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;sns&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; None&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-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-python&quot;&gt;setup_gui&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-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; setup_gui&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;&#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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUI設定中...&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-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;root&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; tk&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;Tk&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-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;root&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;title&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;quot;AWS SNS SMS送信ツール&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-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;root&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;geometry&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;quot;500x400&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;        # 電話番号入力&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        tk&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;Label&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;root&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; text&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;quot;電話番号 (+81XXXXXXXXX):&amp;quot;&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; font&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;quot;Arial&amp;quot;&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; 12&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;pack&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;            pady&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;10&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-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;phone_entry&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; tk&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;Entry&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;root&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; width&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;30&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; font&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;quot;Arial&amp;quot;&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; 11&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-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;phone_entry&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;pack&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;pady&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;5&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;        tk&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;Label&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;root&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; text&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;quot;メッセージ:&amp;quot;&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; font&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;quot;Arial&amp;quot;&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; 12&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;pack&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;pady&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;20&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; 5&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-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;message_entry&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; tk&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;Text&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;root&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; height&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;span class=&quot;z-variable z-parameter&quot;&gt; width&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;50&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; font&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;quot;Arial&amp;quot;&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; 10&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-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;message_entry&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;pack&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;pady&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;5&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;        tk&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;Button&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-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;root&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;            text&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;quot;SMS送信&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-variable z-parameter&quot;&gt;            command&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-meta z-function-call z-arguments z-python&quot;&gt;send_sms&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;            bg&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;quot;blue&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-variable z-parameter&quot;&gt;            fg&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;quot;white&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-variable z-parameter&quot;&gt;            font&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;quot;Arial&amp;quot;&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; 12&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;            padx&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;20&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;            pady&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;10&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-meta z-function-call z-python&quot;&gt;pack&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;pady&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;20&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-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;result_label&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; tk&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;Label&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-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;root&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; text&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;&amp;quot;&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; font&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;quot;Arial&amp;quot;&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; 10&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; wraplength&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;400&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-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;result_label&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;pack&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;pady&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;10&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 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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUI設定完了&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-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; send_sms&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;&#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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;SMS送信ボタンがクリックされました&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-source&quot;&gt;        phone_number&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;phone_entry&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;get&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;strip&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;        message&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;message_entry&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;get&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;quot;1.0&amp;quot;&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; tk&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;END&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;strip&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 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;電話番号: &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;phone_number&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;        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;メッセージ: &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;message&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;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;        if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; phone_number&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-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;result_label&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;config&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;text&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;quot;電話番号を入力してください&amp;quot;&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; fg&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;quot;red&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;            return&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 z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;        if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; message&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-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;result_label&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;config&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;text&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;quot;メッセージを入力してください&amp;quot;&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; fg&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;quot;red&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;            return&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 z-control z-flow z-python&quot;&gt;        if&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;sns&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&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-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;result_label&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;config&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;text&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;quot;AWS接続エラー&amp;quot;&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; fg&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;quot;red&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;            return&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 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-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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;SMS送信中...&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-source&quot;&gt;            response&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;sns&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;publish&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;                PhoneNumber&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-arguments z-python&quot;&gt;phone_number&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;                Message&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-arguments z-python&quot;&gt;message&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;                MessageAttributes&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;quot;AWS.SNS.SMS.SMSType&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-punctuation z-definition z-string z-string&quot;&gt;                        &amp;quot;DataType&amp;quot;&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;quot;String&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-punctuation z-definition z-string z-string&quot;&gt;                        &amp;quot;StringValue&amp;quot;&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;quot;Transactional&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-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;span class=&quot;z-source&quot;&gt;            message_id&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-indexed-name z-python&quot;&gt; response&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-string&quot;&gt;MessageId&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            success_text&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 z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;送信完了！&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Message ID: &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-source&quot;&gt;message_id&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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;result_label&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;config&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;text&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-arguments z-python&quot;&gt;success_text&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; fg&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;quot;green&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;            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;送信成功: &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;message_id&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;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-source&quot;&gt;            error_text&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 z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;送信エラー:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;\n{&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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;result_label&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;config&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;text&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-arguments z-python&quot;&gt;error_text&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; fg&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;quot;red&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;            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;送信エラー: &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;e&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;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; run&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;&#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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUIメインループ開始&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-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;root&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;mainloop&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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUIメインループ終了&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-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;quot;__main__&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-source&quot;&gt;    app&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; SNSSender&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;    app&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;run&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;AWSのIAMでアクセスキーを作成して、&lt;code&gt;.env.local&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;AWS_ACCESS_KEY_ID=A@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS_SECRET_ACCESS_KEY=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS_DEFAULT_REGION=ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&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;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">AWSが提供するAmazon SNS(Simple Notification Service)を使って、SMSにメッセージを送信するサンプルコードを作ってみました。</summary>
        </entry><entry xml:lang="en">
        <title>Webサイト脆弱性スキャン入門：NucleiとKatanaで始めるセキュリティチェック</title>
        <published>2025-06-04T00:00:00+00:00</published>
        <updated>2025-06-04T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/vulnerability-check/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/vulnerability-check/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
ebサイトのセキュリティが気になるけど、専門的な知識がなくて何から始めればいいか分からない...そんなIT技術者の方に向けて、オープンソースのツールを使った脆弱性スキャンの方法をご紹介します。今回は「Nuclei」と「Katana」という2つのツールを組み合わせて、効率的にWebサイトの脆弱性をチェックする方法を解説していきます。
&lt;h2 id=&quot;1._NucleiとKatanaとは？&quot;&gt;1. NucleiとKatanaとは？&lt;&#x2F;h2&gt;
&lt;p&gt;NucleiはProjectDiscoveryが開発したオープンソースの脆弱性スキャナーです。最大の特徴は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;テンプレートベース&lt;&#x2F;strong&gt;：YAML形式のテンプレートで脆弱性パターンを定義&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コミュニティ駆動&lt;&#x2F;strong&gt;：世界中のセキュリティ研究者が3000以上のテンプレートを提供&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;多様な対応&lt;&#x2F;strong&gt;：CVE、設定ミス、情報漏洩など幅広い脆弱性に対応&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;KatanaもProjectDiscoveryが開発したWebクローラーです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;高速クロール&lt;&#x2F;strong&gt;：Go言語で開発された軽量高速なクローラー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript対応&lt;&#x2F;strong&gt;：SPA（Single Page Application）も適切にクロール&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;設定柔軟&lt;&#x2F;strong&gt;：クロール深度や対象範囲を細かく制御可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Nuclei連携&lt;&#x2F;strong&gt;：同じ開発元のため、Nucleiとの相性が抜群&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;両者ともProjectDiscoveryが開発したツールですが、この組み合わせが良い理由は次
の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Katanaでサイト全体のURLを収集&lt;&#x2F;li&gt;
&lt;li&gt;NucleiでそれらのURLに対して脆弱性をチェック&lt;&#x2F;li&gt;
&lt;li&gt;両ツールとも同じ開発元なので連携がスムーズ&lt;&#x2F;li&gt;
&lt;li&gt;オープンソースなので無料で利用可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;2._インストール方法&quot;&gt;2. インストール方法&lt;&#x2F;h2&gt;
&lt;p&gt;前提条件は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;macOS&lt;&#x2F;li&gt;
&lt;li&gt;Homebrew（未インストールの場合は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;brew.sh&#x2F;ja&#x2F;&quot;&gt;公式サイト&lt;&#x2F;a&gt;からインストール）&lt;&#x2F;li&gt;
&lt;li&gt;Go言語環境（&lt;code&gt;brew install go&lt;&#x2F;code&gt;でインストール可能）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;インストール手順は以下の通りです。
初回実行時にNucleiが自動的にテンプレートをダウンロードします。&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;# 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 nuclei&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -version&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;# Go言語でインストール&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;projectdiscovery&#x2F;katana&#x2F;cmd&#x2F;katana@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;# インストール確認&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;katana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -version&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -update-templates&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;3._実行方法と結果の確認&quot;&gt;3. 実行方法と結果の確認&lt;&#x2F;h2&gt;
&lt;p&gt;最もシンプルな使い方から始めましょう。単一のURLを検査する方法です。&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -o results.txt&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -s critical,high,medium -o important_vulns.txt&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;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. Katanaでサイト全体をクロール&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;katana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -o urls.txt&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. 不要なファイルを除外&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;grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -v -E &amp;#39;\.(jpg|jpeg|png|gif|css|js|ico)$&amp;#39; urls.txt&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; filtered_urls.txt&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. Nucleiで脆弱性スキャン&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l filtered_urls.txt -s critical,high,medium -o vulnerability_report.txt&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;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;wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l vulnerability_report.txt&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;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; vulnerability_report.txt&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;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; vulnerability_report.txt&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; -oE &amp;#39;\[(critical|high|medium|low)\]&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; sort&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; uniq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;4._どのような検証がなされているか確認する方法&quot;&gt;4. どのような検証がなされているか確認する方法&lt;&#x2F;h2&gt;
&lt;p&gt;仕事などで脆弱性検証する場合、「で、一体何が検証されたん？」と聞かれること
もあると思います。3,000以上のテンプレートを使用しているので、簡単にどんなテ
ンプレートが使用されているか把握する方法です。&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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-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;CVE脆弱性: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags cve&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;情報漏洩: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags exposure&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;設定ミス: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags misconfig&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;XSS: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags xss&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;LFI: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags lfi&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;管理画面: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags panel&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;技術スタック: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags tech&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;情報収集: &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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags osint&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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;&#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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s critical&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;     # 1321件&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s high&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;         # 2377件&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s medium&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;       # 2322件&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s low&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;          # 316件&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s info&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; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;         # 4086件&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;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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -v -o results.txt&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags cve&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; head&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;CVE（Common_Vulnerabilities_and_Exposures）について&quot;&gt;CVE（Common Vulnerabilities and Exposures）について&lt;&#x2F;h3&gt;
&lt;p&gt;CVEは世界共通のセキュリティ脆弱性カタログです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;命名規則&lt;&#x2F;strong&gt;：CVE-YYYY-NNNNN（年-通し番号）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;例&lt;&#x2F;strong&gt;：CVE-2021-44228（Log4jの重大な脆弱性）&lt;&#x2F;li&gt;
&lt;li&gt;Nucleiは3000以上のCVEに対応したテンプレートを保有&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;5._実践的な使い分け&quot;&gt;5. 実践的な使い分け&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-punctuation z-definition z-comment z-comment&quot;&gt;# クイックチェック（30秒以内）&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -t exposures&#x2F; -s critical,high&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;# バランス型チェック（1-2分）&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -t cves&#x2F;,exposures&#x2F; -s medium,high,critical&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;# 徹底スキャン（5-10分） - 新サイトの評価など&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;katana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&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; nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s critical,high,medium&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;テンプレート選択は以下のような指針で運用するとよいと思います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;初回チェック&lt;&#x2F;strong&gt;：&lt;code&gt;cves&#x2F;,exposures&#x2F;&lt;&#x2F;code&gt;（CVEと情報漏洩）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;定期チェック&lt;&#x2F;strong&gt;：&lt;code&gt;-s critical,high&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;6._パフォーマンス最適化&quot;&gt;6. パフォーマンス最適化&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-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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 50&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -rl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -timeout&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l urls.txt -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -rl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 50&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -bulk-size&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;-c 50&lt;&#x2F;strong&gt;：同時実行テンプレート数を50に設定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;-rl 100&lt;&#x2F;strong&gt;：1秒間に100リクエストまで&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;-timeout 5&lt;&#x2F;strong&gt;：タイムアウトを5秒に短縮&lt;&#x2F;li&gt;
&lt;&#x2F;ul&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;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;7._セキュリティ向上のための継続的運用&quot;&gt;7. セキュリティ向上のための継続的運用&lt;&#x2F;h2&gt;
&lt;p&gt;継続的に運用するために、次のようなスクリプトを組んでcronなどで自動運用する
方法もよいと思います。&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-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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# daily_security_check.sh&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;TARGET&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;quot;https:&#x2F;&#x2F;your-website.com&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;DATE&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;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d&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_DIR&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;quot;security_scans&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DATE&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;# 金曜日（5）かチェック&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-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%u&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; -eq&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&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;金曜日なので、テンプレートを更新します...&amp;quot;&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;    nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -update-templates&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-entity z-name z-function&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -p &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_DIR&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;# 高優先度の脆弱性をチェック&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;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -u &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; -s critical,high -o &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;critical_scan.txt&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;# 結果をメール送信（お好みで）&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-keyword z-operator&quot;&gt; -s&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;$OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;critical_scan.txt&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-entity z-name z-function&quot;&gt;    mail&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -s &amp;quot;セキュリティアラート: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; admin@company.com&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-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;$OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;critical_scan.txt&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;8._他ツールとの連携例&quot;&gt;8. 他ツールとの連携例&lt;&#x2F;h2&gt;
&lt;p&gt;Webサイトが静的サイトジェネレーターなどで組まれている場合は、
サイト生成のCI&#x2F;CDパイプラインに脆弱性検証を組み込むという手もあります。&lt;&#x2F;p&gt;
&lt;p&gt;以下は、GitHub Actionsの例です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# GitHub Actions例&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-tag z-yaml&quot;&gt;name&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-string&quot;&gt; Security Scan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  schedule&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; cron&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 z-definition z-string z-string&quot;&gt; &amp;quot;0 9 * * 1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; # 毎週月曜日9時&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-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  security-scan&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    runs-on&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-string&quot;&gt; ubuntu-latest&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-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; uses&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-string&quot;&gt; actions&#x2F;checkout@v2&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Install Nuclei&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-tag z-yaml&quot;&gt;        run&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-keyword&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;          go install github.com&#x2F;projectdiscovery&#x2F;nuclei&#x2F;v3&#x2F;cmd&#x2F;nuclei@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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Run Security Scan&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-tag z-yaml&quot;&gt;        run&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-keyword&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;          nuclei -u ${{ secrets.TARGET_URL }} -s critical,high -o scan_results.txt&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&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&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-string&quot;&gt; Upload Results&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-tag z-yaml&quot;&gt;        uses&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-string&quot;&gt; actions&#x2F;upload-artifact@v2&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-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          name&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-string&quot;&gt; security-scan-results&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-tag z-yaml&quot;&gt;          path&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-string&quot;&gt; scan_results.txt&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;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;generate_security_report&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&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-parameter&quot;&gt;$1&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&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;quot;security_report_&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;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;.txt&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;=== セキュリティスキャンレポート ===&amp;quot;&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-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;$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;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;対象サイト: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&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; &amp;gt;&amp;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;$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;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string 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-entity z-name z-function&quot;&gt;date&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-keyword z-operator&quot;&gt; &amp;gt;&amp;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;$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;    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;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;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;$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;&#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;    nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -u &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; -s critical,high,medium -o temp_results.txt&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;発見された脆弱性数: &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;wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&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-string&quot;&gt; temp_results.txt&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-keyword z-operator&quot;&gt; &amp;gt;&amp;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;$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;    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;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;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;$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;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;詳細結果:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;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;$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-entity z-name z-function&quot;&gt;    cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; temp_results.txt&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;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;$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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    rm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; temp_results.txt&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;レポートを生成しました: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$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-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-entity z-name z-function&quot;&gt;generate_security_report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;example.com&amp;quot;&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;脆弱性の検証はサーバーに非常に負荷をかけるため、
不正アクセス禁止法、電子計算機損壊等業務妨害罪、偽計業務妨害罪
などに抵触し違法行為になる可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;必ず以下を遵守しましょう。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;所有権の確認&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自分が所有するサイトのみスキャンしてください&lt;&#x2F;li&gt;
&lt;li&gt;他者のサイトには必ず事前許可を取得してください&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;適切な負荷制御&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;本番サイトへの負荷を考慮してレート制限を設定&lt;&#x2F;li&gt;
&lt;li&gt;業務時間外でのスキャン実施を推奨&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;結果の適切な管理&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;スキャン結果に機密情報が含まれる可能性あり&lt;&#x2F;li&gt;
&lt;li&gt;結果ファイルの保存場所とアクセス権限に注意&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;なぜ偽計業務妨害罪となる可能性があるか&quot;&gt;なぜ偽計業務妨害罪となる可能性があるか&lt;&#x2F;h3&gt;
&lt;p&gt;偽計業務妨害罪（刑法233条）の要件は、以下の3つです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;偽計：虚偽の情報や人を欺く行為&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;脆弱性検査はサーバーに非常に負荷を掛ける処理であることは知られているので、
業務妨害と故意であることは分かりやすいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;「偽計」については、脆弱性スキャンはブラウザの正常なアクセスを装って
リクエストヘッダを偽装しつつ「負荷」という観点では攻撃的とも言えるペイロード
を送信するため「偽計」と見なされる可能性があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;NucleiとKatanaを使った脆弱性スキャンは、以下のような方に特におすすめです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自社サイトのセキュリティ状況を定期的にチェックしたい&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;ul&gt;
&lt;p&gt;最初は単一URLの簡単なチェックから始めて、慣れてきたらサイト全体のスキャンや自動化に挑戦してみてください。重要なのは継続的にセキュリティをチェックする習慣を作ることです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;脆弱性が見つからない結果も良い結果&lt;&#x2F;strong&gt;です。むしろサイトが適切にメンテナンスされている証拠として安心できる材料になります。&lt;&#x2F;p&gt;
&lt;p&gt;セキュリティは一度設定すれば終わりではなく、継続的な取り組みが重要です。このツールを活用して、より安全なWebサイト運営を目指しましょう。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;参考リンク&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.projectdiscovery.io&#x2F;opensource&#x2F;nuclei&#x2F;overview&quot;&gt;Nuclei公式ドキュメント&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;projectdiscovery&#x2F;katana&quot;&gt;Katana公式リポジトリ&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;projectdiscovery.io&#x2F;&quot;&gt;ProjectDiscovery&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;&#x2F;strong&gt;：この記事の内容は啓蒙目的であり、適切な許可なく他者のシステムをスキャンすることは違法行為となる可能性があります。必ず責任を持って使用してください。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ebサイトのセキュリティが気になるけど、専門的な知識がなくて何から始めればいいか分からない...そんなIT技術者の方に向けて、オープンソースのツールを使った脆弱性スキャンの方法をご紹介します。今回は「Nuclei」と「Katana」という2つのツールを組み合わせて、効率的にWebサイトの脆弱性をチェックする方法を解説していきます。</summary>
        </entry><entry xml:lang="en">
        <title>Scaler3で作曲支援</title>
        <published>2025-05-31T00:00:00+00:00</published>
        <updated>2025-05-31T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/05/scaler3/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/05/scaler3/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;05&amp;#x2F;scaler3&amp;#x2F;scaler3.webp?h=7933cce2096b167cf29e&quot;
  alt=&quot;Scaler3&quot; width=&quot;3440&quot; height=&quot;1440&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;先日発売されたScaler3ですが、音楽理論を知らなくても作曲や編曲ができると話題なので購入してみました。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
## Scaler3とは
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;scalermusic.com&#x2F;products&#x2F;scaler-3&#x2F;&quot;&gt;Scaler3&lt;&#x2F;a&gt;は音楽理論やコード理論
がわからなくても凝ったコード進行が作れる作曲支援ソフトです。&lt;&#x2F;p&gt;
&lt;p&gt;裏では音楽理論に基づいて適切なコード進行を提案してくれるの
その中から気に入ったコードをどんどんドラッグしてコード進行を作っていけます。&lt;&#x2F;p&gt;
&lt;p&gt;「コードに合う違和感のない音はどれか」「コード進行で冒険したいが、このコード
は適切か」といったプロでも抱えてしまいそうな悩みを解消してくれます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Scaler3を検証してみた&quot;&gt;Scaler3を検証してみた&lt;&#x2F;h2&gt;
&lt;p&gt;今回は既存のメロディを取ってきてSuggest機能に従ってコード進行を作ってみまし
た。使用したのはThe Banglesの&quot;Eternal Flame&quot;です。&lt;&#x2F;p&gt;
&lt;p&gt;またScaler3から追加されたアレンジ機能を使って伴奏を付けています。
ドラムの生成機能はないので、ドラムだけはLogic ProのPlayer機能を使っています
。&lt;&#x2F;p&gt;
&lt;p&gt;前半がScaler3で生成した伴奏、後半がオリジナルのコード進行に従った伴奏です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;SoundCloudEmbed apiurl=&quot;https:&#x2F;&#x2F;api.soundcloud.com&#x2F;tracks&#x2F;2105211069&quot;
url=&quot;https:&#x2F;&#x2F;soundcloud.com&#x2F;yostos&#x2F;sclar3&#x2F;s-aQqlD1uzAIB?si=ab6c3c4bcd0a49f3b1127fe1090f0657&amp;utm_source=clipboard&amp;utm_medium=text&amp;utm_campaign=social_sharing&quot;
title=&quot;Scaler3テスト&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;オリジナルは、G Majorで次のようなコード進行です。&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;G Em7 | C D | G Em7 | C D | Em B7 | Em7 A7 | D Bm7| Am7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ですが、 Scaler3でもっともノートとコードにのマッチ度が高かったB Phrygian
Modeでコードを構成してみました。&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;  Bm G | C D | Em G | Am G | Em7 Dsus2 | Bm Em | A7 D| Bm7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;メロディから判断され推奨されるコードはブルーで示されますが、
メロディをすべてマッチするわけではないんで、実際は推奨コードから試しながら
決めていくことになります。しかし、何も参考にせず自分で考えるより数倍生産性は上が
ります。&lt;&#x2F;p&gt;
&lt;p&gt;オリジナルのほうが安心して聞ける印象です。
一方、Scaler3で作ったコード進行はちょっと印象が違っていますが、まぁ成り立っているのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;多分、メロディからコードを作るより、コード進行をScalerで練って、
メロディを提案してもらったほうがうまく働くと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Scaler3は「音楽理論の知識」と「直感的な操作」のバランスが絶妙なツールです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;🎯_習得難易度について&quot;&gt;🎯 習得難易度について&lt;&#x2F;h3&gt;
&lt;p&gt;完全な素人には難しいものの、基本的な音楽理論（メジャー・マイナー、ダイアト
ニックコードなど）を理解していれば十分活用できます。 転調の提案など高度な
機能については、理論と感性のバランスを取りながら使い分けることが重要です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;💡_Scaler3の真価&quot;&gt;💡 Scaler3の真価&lt;&#x2F;h3&gt;
&lt;p&gt;最大の価値は &lt;strong&gt;「0→1の創作支援」&lt;&#x2F;strong&gt; にあります。白紙の状態から音楽理論に基づ
いた膨大なコード進行のアセットを参考にできるため、創作の起点として非常に強力
です。また、安全圏を抜け出した「冒険的なコード進行」への挑戦も、理論的裏付け
があるので安心して試せます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;🤖_AI作曲時代における位置づけ&quot;&gt;🤖 AI作曲時代における位置づけ&lt;&#x2F;h3&gt;
&lt;p&gt;AIが楽曲を自動生成する時代になりましたが、&lt;strong&gt;創作者が主導権を握りながら音楽理
論の恩恵を受けられるScaler3のようなツールは、まだまだ重要な役割を果たすでし
ょう。&lt;&#x2F;strong&gt; 完全自動化ではなく、人間の創意工夫とテクノロジーの協働による作曲ス
タイルは、今後も価値を持ち続けると考えられます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;結論として、Scaler3は音楽制作の生産性を大幅に向上させる優秀なパートナーツールです。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        <summary type="html">先日発売されたScaler3ですが、音楽理論を知らなくても作曲や編曲ができると話題なので購入してみました。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic Claude4を発表</title>
        <published>2025-05-23T00:00:00+00:00</published>
        <updated>2025-05-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/05/claude4/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/05/claude4/</id>
        
            <content type="html">&lt;p&gt;Anthropicが開発者会議「Code with Claude」で推論能力と深い思考能力が大きく向上した新しいモデルClaude 4を発表しました。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contens&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;Claude_4_の内容&quot;&gt;Claude 4 の内容&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicは2月に前世代の「Claude Sonnet 3.7」をリリースしてばかりですが、
OpenAIが4月にコンテキストウィンドウを拡大した「GPT-4.1」や、新しい推論モデル「o3」「o4-mini」を公開するなど
競合のAI開発企業も性能を引き上げているのに対抗して早期に新しいモデル投入して
きたのだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;まずはClaude Sonnet 3.7を基に改良を加えた&lt;strong&gt;Claude Sonnet 4&lt;&#x2F;strong&gt;です。
Sonnet3.7では過度に積極的な回答をする場合があったようですが、
今回Sonnet 4では適度に軽量化されているようです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Claude Opus 4&lt;&#x2F;strong&gt;はより大規模で計算資源を要するモデルで、
特に難易度の高い課題を処理できるよう設計されているようです。
人間であれば数時間かかる作業を同モデルが短時間でこなす性能を示しているそうで
す。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_4の検証&quot;&gt;Claude 4の検証&lt;&#x2F;h2&gt;
&lt;p&gt;中島聡氏が&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SingularitySociety&#x2F;WorldModels&#x2F;&quot;&gt;Workd Models&lt;&#x2F;a&gt;
として公開している課題でいくつかテストしてみました。&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;# Sonnet 3.7&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;綿菓子の高さ: 8センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レンガの高さ: 7センチ&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;8センチ + 7センチ = 15センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;したがって、綿菓子の上にレンガを置くと、高さは15センチになります。&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;# Opus 3&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;綿菓子の高さ: 8センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レンガの高さ: 7センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8センチ + 7センチ = 15センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;したがって、綿菓子の上にレンガを置くと、高さは15センチになります。&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;# Sonnet 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子の高さ8センチの上にレンガの高さ7センチを置くと、合計の高さは&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15センチになります。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8 + 7 = 15センチです。&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;# Opus 4&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;レンガの重さで押しつぶされてしまいます。綿菓子はほぼ完全に圧縮されて&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;しまうので、実質的な高さはレンガの高さである7センチになると考えられ&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ChatGPT&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;そのため、綿菓子の高さ8センチとレンガの高さ7センチを単純に足して15&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;&#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;が多いです。もし綿菓子が完全につぶれたと仮定すると、高さはレンガの&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;高さだけの7センチになります。&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;よって、実際の高さは7センチより少し上程度（綿菓子がどれだけ潰れるか&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;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude 4の登場は、LLMの技術進化がもはや年単位ではなく「月単位」で進む時代に突入していることを改めて印象づけました。Sonnet 4は従来モデルの過剰応答傾向を抑制し、応答の一貫性・安定性を向上。一方、Opus 4は汎用的な知識応答を超え、タスクに応じた状況推論や人間的な判断に近づいています。&lt;&#x2F;p&gt;
&lt;p&gt;特に、綿菓子の課題のような「文脈理解」と「物理的直感」が求められるケースで、
Opus 4は従来の加算的な計算ではなく素材特性を踏まえた判断を下しています。
これは今後のエージェント系アプリケーションにも直結する進化です。&lt;&#x2F;p&gt;
&lt;p&gt;競合のChatGPT（GPT-4.1）も同様に高い水準にあり、両者はもはや単純な精度比較ではなく、「推論スタイル」や「コンテキスト処理のアプローチ」の差をどうプロダクトに活かすかが焦点になります。&lt;&#x2F;p&gt;
&lt;p&gt;Claude 4は「回答の速さ」や「正確さ」だけでは語りきれない次のフェーズに入りつつあり、開発者としては、タスクの性質や求める出力の粒度に応じたモデル選定の重要性が今後ますます増していくと感じました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropic が開発者会議「Code with Claude」で推論能力と深い思考能力が大きく向上した新しいモデルClaude 4を発表しました。</summary>
        </entry><entry xml:lang="en">
        <title>NeoVimからClaude Codeを使う</title>
        <published>2025-05-04T00:00:00+00:00</published>
        <updated>2025-05-04T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/05/claude-code-nvim/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/05/claude-code-nvim/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;05&amp;#x2F;claude-code-nvim&amp;#x2F;claude-code-nvim.webp?h=ef29ff190878e35e43bc&quot;
  alt=&quot;Claude-Code-Nvim&quot; width=&quot;1735&quot; height=&quot;1212&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;AnthropicのDeveloper Partner ProgramにJoinしてClaude Codeを使うモチベーションが高まっています。Claude CodeをNeoVimから使用するためのClaude Code Neovim Pluginをインストールしました。Claude Code Neovim PluginをNeoVimで使う方法を説明します。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
## Claude Code Neovim Plugin
&lt;p&gt;今回導入したのは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;greggh&#x2F;claude-code.nvim&quot;&gt;Claude Code Neovim Plugin&lt;&#x2F;a&gt; &lt;code&gt;claude-code.nvim&lt;&#x2F;code&gt; です。&lt;&#x2F;p&gt;
&lt;p&gt;基本的にやっていることはNeoVimのターミナルを使い、Claude Codeを呼び出してい
るようです。&lt;&#x2F;p&gt;
&lt;p&gt;次のような機能がサポートされます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ターミナルウィンドウでキー一押しだけでClaude Codeを切り替え&lt;&#x2F;li&gt;
&lt;li&gt;--continueなどのコマンドライン引数やカスタムバリアントのサポート&lt;&#x2F;li&gt;
&lt;li&gt;Claude Codeによって変更されたファイルを自動検出して再読み込み&lt;&#x2F;li&gt;
&lt;li&gt;ファイルが外部で変更された際のリアルタイムバッファ更新&lt;&#x2F;li&gt;
&lt;li&gt;カスタマイズ可能なウィンドウ位置とサイズ&lt;&#x2F;li&gt;
&lt;li&gt;which-key（利用可能な場合）との統合&lt;&#x2F;li&gt;
&lt;li&gt;作業ディレクトリとしてgitプロジェクトのルートを自動的に使用（利用可能な場合）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;当たり前ですが、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;anthropics&#x2F;claude-code&quot;&gt;Claude Code CLI&lt;&#x2F;a&gt;がインストールされている必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;注意点としては、Claude Desktopなどを呼び出しているのでなく、Claude Codeを呼
び出しているため、　&lt;strong&gt;APIの使用料がかかります&lt;&#x2F;strong&gt;。 Claude APIでなくClaude
Codeをの呼び出しているため、Anthropic Developer Partner Programeのディスカウン
ト対象とはなります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;claud-code.nvimのインストール&quot;&gt;&lt;code&gt;claud-code.nvim&lt;&#x2F;code&gt;のインストール&lt;&#x2F;h2&gt;
&lt;p&gt;私はプラグインマネージャーとして &lt;code&gt;lazy.nvim&lt;&#x2F;code&gt;を使っているので
以下の設定でインストール完了です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&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; {&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;quot;greggh&#x2F;claude-code.nvim&amp;quot;&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-source&quot;&gt;  dependencies&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; {&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;quot;nvim-lua&#x2F;plenary.nvim&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;-- Required for git operations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-entity z-name z-function&quot;&gt;  config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; function&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&quot;&gt;    require&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;claude-code&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;).&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setup&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-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;claude-code.nvimの使い方&quot;&gt;&lt;code&gt;claude-code.nvim&lt;&#x2F;code&gt;の使い方&lt;&#x2F;h2&gt;
&lt;p&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;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;&lt;code&gt;:ClaudeCode&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;C-,&amp;gt;&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;:ClaudeCodeContinue&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;leader&amp;gt;cC&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;:ClaudeCodeResume&lt;&#x2F;td&gt;&lt;td&gt;N&#x2F;A&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Verboseモード&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;:ClaudeCodeVerbose&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;leader&amp;gt;cV&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Claude Codeターミナルでは次のキーが使用できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;C-h&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-j&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-k&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-l&amp;gt;&lt;&#x2F;code&gt; : ウィンドウ間の移動&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;C-f&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-b&amp;gt;&lt;&#x2F;code&gt;: ページスクロール&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はClaude CodeをNeoVimから直接使用できる &lt;code&gt;claude-code.nvim&lt;&#x2F;code&gt; プラグインを紹介しました。ターミナルからClaude Codeを呼び出す方法よりも、コーディング作業の流れを止めることなくAIの支援を受けられるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;このプラグインを使うことで、NeoVim内で簡単にClaude Codeへアクセスでき、
シームレスなコードの修正や生成を行えるようになります。特にgitプロジェクトの
コンテキストを自動的に認識する機能は、大規模なプロジェクトでの作業に役立ちま
す。&lt;&#x2F;p&gt;
&lt;p&gt;一点注意が必要なのは、API使用料がかかる点です。ただし、Anthropic Developer Partner Programに参加している場合は割引が適用されるので、Claude APIを直接呼び出すより合理的です。コーディング効率向上のためのツールとして、検討する価値は十分にあるでしょう。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropic の Developer Partner Program に Join してClaude Codeを使うモチベーションが高まっています。Claude CodeをNeoVimから使用するためのClaude Code Neovim Pluginをインストールしました。Claude Code Neovim Plugin を NeoVim で使う方法を説明します。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Codeのディスカウントを得る - Developer Partner Program</title>
        <published>2025-05-02T00:00:00+00:00</published>
        <updated>2025-05-02T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/05/anthropics-developer-partner-program/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/05/anthropics-developer-partner-program/</id>
        
            <content type="html">&lt;p&gt;Claude Code APIの利用料割引が可能となるDeveloper Partner ProgrameがAnthropicより発表されました。今後のモデル改善のためのプログラムで参加するとClaude 3.5 SonnetおよびClaude 3.7SonnetモデルのClaude Code入力トークンが30%割引になる可能性があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Anthropic&amp;#39;s_Developer_Partner_Programのポイント&quot;&gt;Anthropic&#x27;s Developer Partner Programのポイント&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicのClaudeは基本的にユーザーの入力をトレーニングに使用しませんが、
この &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.anthropic.com&#x2F;en&#x2F;articles&#x2F;11174108-about-the-development-partner-program&quot;&gt;Anthropic&#x27;s Developer Partner Program&lt;&#x2F;a&gt; では、Anthropicのサービスやモデルトレーニングを改善
するために、Claude Codeセッションを自主的にAnthropicと共有することになります。&lt;&#x2F;p&gt;
&lt;p&gt;その代わりに、Claude 3.5 SonnetとClaude 3.7 SonnetのClaude Code入力トークンに対して、
標準API価格から30%オフを受けることができます。具体的には次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;標準入力: 100万トークンあたり-$0.9&lt;&#x2F;li&gt;
&lt;li&gt;キャッシュ書き込み: 100万トークンあたり-$1.125&lt;&#x2F;li&gt;
&lt;li&gt;キャッシュ読み取り: 100万トークンあたり-$0.09&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;利用するに当たっては、次のような注意点があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AnthropicのファーストパーティAPIからのClaude Codeの入出力トークンのみが共
有され、ClaudeアプリやClaude Code以外のAPI呼び出しには適用されない。
つまり、Amazon Bedrockなどを経由するとプログラムは適用されず割引の対象外である&lt;&#x2F;li&gt;
&lt;li&gt;データは最大2年間安全に保存される。モデルトレーニングに使用されるデータは
他の顧客情報と関連付けらない&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;li&gt;割引は請求後2025年7月31日まで適用され、プログラムを離脱すると終了する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;プログラムへの参加方法&quot;&gt;プログラムへの参加方法&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicのConsoleの設定(Claudeの設定画面でないことに注意)から、
「Privacy Controls」を開いて「Join our Development Partner Program to help improve Claude」
で「Join」ボタンを押すだけです。&lt;&#x2F;p&gt;
&lt;p&gt;離脱時は、「Leave」ボタンが現れるので、押すとプログラムを離脱できます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、すべてのアカウントがこのプログラムの対象ではないようです。
アカウントが対象でない場合は、上記の参加オプションが表示されません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;どれくらいの人がClaude Codeを使っているわかりませんが、GitHub Copilotのよう
「コード入力支援」を超えClaude Codeは優れた開発者とペアプログラミングしているような
錯覚に陥るほど生産性が上がります。&lt;&#x2F;p&gt;
&lt;p&gt;このため、Claude Codeの利用料が30%の割引となるのは魅力的です。
参加をためらうとしたら、「自身のコンテンツが学習に利用される」という
プライバシーの点でしょう。業務で利用している場合は、成果物が他社に共有される
ことになるためハードルが高そうです。&lt;&#x2F;p&gt;
&lt;p&gt;私自身は個人の活動で利用なので、プライバシーの観点での懸念はありません。
自身のClaude Codeセッションを共有することでClaudeのコーディング能力向上に
寄与し、AIによるコーディング支援技術の発展できることはモチベーションにも繋が
ります。
更に割引まで恩恵を受けることができるならば参加しない理由はないため、即座に参加しました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Claude Code APIの利用料割引が可能となるDeveloper Partner ProgrameがAnthropicより発表されました。今後のモデル改善のためのプログラムで参加するとClaude 3.5 Sonnet および Claude 3.7Sonnet モデルの Claude Code 入力トークンが30%割引になる可能性があります。</summary>
        </entry><entry xml:lang="en">
        <title>SoundCloud API仕様の変更</title>
        <published>2025-04-28T00:00:00+00:00</published>
        <updated>2025-04-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/soundcloud-api-changed/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/soundcloud-api-changed/</id>
        
            <content type="html">&lt;p&gt;直近数日の内にSoundCloudはAPIの仕様を変更したようです。自作のTypeScriptコンポーネントがうまく機能しなくなったために対応しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;変更のポイント&quot;&gt;変更のポイント&lt;&#x2F;h2&gt;
&lt;p&gt;以下のコードは以前使用していたものでSoundCloudの曲をWebに埋め込むためのコー
ドです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export const&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; SoundCloudEmbed&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-type&quot;&gt; React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FC&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;SoundCloudEmbedProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;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&quot;&gt; ({&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; url&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; =&amp;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-comment z-comment&quot;&gt;  &#x2F;&#x2F; SoundCloud の埋め込み URL 形式に変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; embedUrl&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; `https:&#x2F;&#x2F;w.soundcloud.com&#x2F;player&#x2F;?url=&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;encodeURIComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;url&lt;&#x2F;span&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-string z-punctuation z-definition z-string&quot;&gt;&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=false&amp;amp;show_comments=true&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=true`&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-keyword&quot;&gt;  return&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 z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; className&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;quot;w-full&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        width&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;quot;100%&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        height&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;quot;166&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        scrolling&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;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        frameBorder&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;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        allow&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;quot;autoplay&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        src&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-variable z-other z-readwrite&quot;&gt;embedUrl&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-tag&quot;&gt;      &amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&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 class=&quot;z-punctuation z-definition z-tag&quot;&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; className&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;quot;text-[10px] text-gray-400 overflow-hidden whitespace-nowrap text-ellipsis font-light&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          href&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;quot;https:&#x2F;&#x2F;soundcloud.com&#x2F;yostos&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          title&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;quot;Yostos&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          target&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;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          rel&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;quot;noopener noreferrer&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          className&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;quot;text-gray-400 no-underline&amp;quot;&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-tag&quot;&gt;        &amp;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;          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-tag&quot;&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;nbsp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;·&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;nbsp&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-tag&quot;&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          href&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-variable z-other z-readwrite&quot;&gt;url&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-entity z-other z-attribute-name&quot;&gt;          title&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;quot;Yostos&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          target&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;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          rel&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;quot;noopener noreferrer&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          className&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;quot;text-gray-400 no-underline&amp;quot;&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-tag&quot;&gt;        &amp;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;          Blackbird&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-tag&quot;&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;      &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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-tag&quot;&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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;  )&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;以前はiframeのsrcに指定するurlは曲ページへのリンクと同じリンクを指定すればよかった
のですが、ここ数日の変更でiframeのsrcの指定はAPI専用のURLでなければならなく
なったようです。&lt;&#x2F;p&gt;
&lt;p&gt;この変更は既にアップロードされている曲には遡及していないようで、直近にアップ
ロードした曲のみに影響しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;SoundCloudEmbed_コンポーネントの変更&quot;&gt;SoundCloudEmbed コンポーネントの変更&lt;&#x2F;h2&gt;
&lt;p&gt;本来はSoundCloudでJavascriptのコードを取得すべきです。
このブログではMDXを使っている関係で取得したコードでは修正が必要なため、
&lt;code&gt;SoundCloudEmbed&lt;&#x2F;code&gt;というコンポーネントを作っていました。
この変更でShare Linkのみ指定していたSoundCloudEmbedは動かなくなりました。&lt;&#x2F;p&gt;
&lt;p&gt;仕方がないのでAPI用のURLを指定できようように修正しました。またタイトルの固定
でなく曲名を指定できるよう変更しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&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;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; SoundCloudEmbedProps&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-variable z-object z-property&quot;&gt;  url&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;  apiurl&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-type z-primitive&quot;&gt; string&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-comment z-comment&quot;&gt; &#x2F;&#x2F; Optional API URL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  title&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-type z-primitive&quot;&gt; string&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-comment z-comment&quot;&gt;  &#x2F;&#x2F; Optional title&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;span class=&quot;z-keyword z-storage z-type&quot;&gt;export const&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; SoundCloudEmbed&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-type&quot;&gt; React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FC&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;SoundCloudEmbedProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;gt;&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; (&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-other z-readwrite&quot;&gt;  url&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-other z-readwrite&quot;&gt;  apiurl&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-other z-readwrite&quot;&gt;  title&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-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt; =&amp;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-comment z-comment&quot;&gt;  &#x2F;&#x2F; SoundCloud の埋め込み URL 形式に変換&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; If apiurl is provided, use it for the iframe source, otherwise use the url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; sourceUrl&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-other z-readwrite&quot;&gt; apiurl&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-other z-readwrite&quot;&gt; url&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-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; embedUrl&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; `https:&#x2F;&#x2F;w.soundcloud.com&#x2F;player&#x2F;?url=&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;encodeURIComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;sourceUrl&lt;&#x2F;span&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-string z-punctuation z-definition z-string&quot;&gt;&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=false&amp;amp;show_comments=true&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=true`&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;  &#x2F;&#x2F; Prepare the display title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; displayTitle&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-other z-readwrite&quot;&gt; title&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; `Yostos - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;title&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;`&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;quot;Yostos&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-keyword&quot;&gt;  return&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-keyword z-operator&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div className&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;quot;w-full&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        width&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;quot;100%&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        height&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;quot;166&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        scrolling&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;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        frameBorder&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;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        allow&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;quot;autoplay&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        src&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-variable z-other z-readwrite&quot;&gt;embedUrl&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-operator&quot;&gt;      &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&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 class=&quot;z-keyword z-operator&quot;&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div className&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;quot;text-[10px] text-gray-400 overflow-hidden whitespace-nowrap text-ellipsis font-light&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;        &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          href&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-variable z-other z-readwrite&quot;&gt;url&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-other z-readwrite&quot;&gt;          title&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-variable z-other z-readwrite&quot;&gt;displayTitle&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-other z-readwrite&quot;&gt;          target&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;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          rel&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;quot;noopener noreferrer&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          className&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;quot;text-gray-400 no-underline&amp;quot;&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;        &amp;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-variable z-parameter&quot;&gt;displayTitle&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-operator&quot;&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;      &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;  )&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;API用URLだけ取得はできないので、結局埋め込み用のJavascriptのコードをSoundCloudから取得してURLを取り出して貼り付けることになります。
手間は貼り付けるより面倒なので、コンポーネントにした意味がないかもしれません。&lt;&#x2F;p&gt;
</content>
        <summary type="html">直近数日の内にSoundCloudはAPIの仕様を変更したようです。自作のTypeScriptコンポーネントがうまく機能しなくなったために対応しました。</summary>
        </entry><entry xml:lang="en">
        <title>MCP接続でClaudeにBlenderで3Dモデリングさせてみた</title>
        <published>2025-04-23T00:00:00+00:00</published>
        <updated>2025-04-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/blender-mcp/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/blender-mcp/</id>
        
            <content type="html">&lt;p&gt;Blender界隈でBlenderとClaudeをMCP接続してClaudeに3Dモデリングさせるというのが話題なので実際に試してみました。自然言語で依頼するとClaudeがモデリングツールを操作してくれます。&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;前提&quot;&gt;前提&lt;&#x2F;h2&gt;
&lt;p&gt;前提は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Blender 3.0以降&lt;&#x2F;li&gt;
&lt;li&gt;Python 3.10以降&lt;&#x2F;li&gt;
&lt;li&gt;uv package manager&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Blenderは無料の3Dモデリングツールなので、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.blender.org&#x2F;&quot;&gt;公式サイト&lt;&#x2F;a&gt;からダウンロードしてインストールしておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Pythonの環境は整えておきましょう。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;uv&lt;&#x2F;code&gt;は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-punctuation z-definition z-comment z-comment&quot;&gt;# Windowの場合&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 uv&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;# Macの場合は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 uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claudeの設定&quot;&gt;Claudeの設定&lt;&#x2F;h2&gt;
&lt;p&gt;使用するのは例によってClaude Desktopです。&lt;&#x2F;p&gt;
&lt;p&gt;いつものごとく、&lt;code&gt;claude_desktop_config.json&lt;&#x2F;code&gt;を編集します。
Claude DesktopからSettings &amp;gt; Developer &amp;gt; Edit Configで開けます。次のように
&lt;code&gt;blender-mcp&lt;&#x2F;code&gt;の設定を追加します。&lt;&#x2F;p&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;blender&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;uvx&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&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;blender-mcp&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-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;h2 id=&quot;Blender_MCP_サーバーのインストール&quot;&gt;Blender MCP サーバーのインストール&lt;&#x2F;h2&gt;
&lt;p&gt;Blender MCPの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blender-mcp.com&#x2F;download.html&quot;&gt;配布サイト&lt;&#x2F;a&gt;から最新版を
ダウンロードします。Zipでダウンロードされるので、展開しておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Blenderを起動して、PreferencesからAdd-onsを開きます。&quot;Install Add-on from
File&quot;を選択して、先ほど展開したフォルダから&lt;code&gt;addon.py&lt;&#x2F;code&gt;を選びます。&lt;&#x2F;p&gt;
&lt;p&gt;インストールが完了すると、3D ViewのSidebarに&quot;Blender MCP&quot;のアイコンが追加さ
れます。
&quot;BlenderMCP&quot;のタブを開いて、&lt;code&gt;Poly Haven&lt;&#x2F;code&gt;のチェックボックスにチェックして
&lt;code&gt;start mcp server&lt;&#x2F;code&gt;をクリックします。&lt;&#x2F;p&gt;
&lt;p&gt;これで、Blender MCPが起動しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claudeにモデリングしてもらう&quot;&gt;Claudeにモデリングしてもらう&lt;&#x2F;h2&gt;
&lt;p&gt;Claudeにモデリングを依頼してみましょう。&lt;&#x2F;p&gt;
&lt;p&gt;Claudeには以下のように依頼しています。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;BlenderでPoly HavenのHDRI、テクスチャ、そして岩や植生のようなモデルを使っ
て、ビーチの雰囲気を作り出してください。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;実際にやっているところを見たほうが早いと思うので、動画にしました。&lt;&#x2F;p&gt;
&lt;div class=&quot;youtube-container&quot; style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;a6-DmRtty_8&quot;
    style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&quot;
    frameborder=&quot;0&quot;
    allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はアセットを使っているとは言え「風景」だったので、3D画像として成立させる
モデリングは結構ハードルが高かったと思います。レンダリングした結果もちょっと
微妙でした。正直リアルな画像を得るだけであれば、Midjourneyなど画像生成AIを使
ったほうが良い結果になるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;ただ、シンプルなポリゴンモデルなら結構ちゃんとモデルを作ってくれます。
3Dモデルがあると、画角や視点を変えたシーンを何度も調整できるメリットがありま
す。&lt;&#x2F;p&gt;
&lt;p&gt;3Dモデリングはツールの使い方もハードルが高く、習得に時間がかかります。
AIを使って自然言語でモデリングできるようになれば結構革新的かなと思います。&lt;&#x2F;p&gt;
&lt;p&gt;MCPでいろいろ拡がっていきますね。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Blender界隈でBlenderとClaudeをMCP接続してClaudeに3Dモデリングさせるというのが話題なので実際に試してみました。自然言語で依頼するとClaudeがモデリングツールを操作してくれます。</summary>
        </entry><entry xml:lang="en">
        <title>Apple Silicon時代のMacバックアップ最新戦略</title>
        <published>2025-04-18T00:00:00+00:00</published>
        <updated>2025-04-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/backup-strategy-for-mac/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/backup-strategy-for-mac/</id>
        
            <content type="html">&lt;h2 id=&quot;Macのバックアップ戦略&quot;&gt;Macのバックアップ戦略&lt;&#x2F;h2&gt;
&lt;p&gt;macOSはOS自体が&lt;strong&gt;TimeMachine&lt;&#x2F;strong&gt;という自動バックアップ機能を持っています。
以下のような特徴を持っています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特徴&lt;&#x2F;strong&gt;: macOSに標準搭載、独自形式でデータを保存&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;: 独自形式のため通常のFinderからのアクセスが困難&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;アプローチ&lt;&#x2F;strong&gt;: 問題発生時はリカバリーからOSインストール後、Migration Assistantでデータ復元&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;iMacを使っていた時は使っていましたが、Macbookを使うようになってから
TimeMachineの使用を止めました。
理由は、バックアップ用にディスクが常にマウントされているとは限らないので
「自動バックアップ」の恩恵が相対的に薄く、加えて独自形式のためTimeMachineの
メカニズムでしかバップアップにアクセスできないためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Apple_Silicon時代のバックアップの変化&quot;&gt;Apple Silicon時代のバックアップの変化&lt;&#x2F;h2&gt;
&lt;p&gt;TimeMachineを使用しない替わりに、長らく&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.shirt-pocket.com&#x2F;SuperDuper&#x2F;SuperDuperDescription.html&quot;&gt;SuperDuper&lt;&#x2F;a&gt;
や&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bombich.com&#x2F;&quot;&gt;Carbon Copy Cloner&lt;&#x2F;a&gt;を使いディスクごと
完全なクローンを取っていました。
完全なクローンはブート可能なので、リカバリーの際にはクローンディスクから
macOSをブートしてリカバリーを行うことができました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、Apple Silicon搭載のMac（M1&#x2F;M2&#x2F;M3チップ）ではIntelが使われていた時代と
比較してシステムアーキテクチャが大きく変わりました。&lt;&#x2F;p&gt;
&lt;p&gt;主な変更点は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;OSが読み取り専用として保護されるようになった&lt;&#x2F;li&gt;
&lt;li&gt;リカバリー機能がより強化された（Recovery・Fallback Recoveryが内蔵）&lt;&#x2F;li&gt;
&lt;li&gt;外部ドライブからの起動に制限が追加された&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;バックアップ戦略も見直す必要が出てきました。
このためBootableな完全ディスククローンという戦略は以前ほど重要ではなくなりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;推奨バックアップ戦略&quot;&gt;推奨バックアップ戦略&lt;&#x2F;h2&gt;
&lt;p&gt;次のようなバックアップ戦略を変更することが必要です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;データ中心のバックアップ&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;OSではなく、ユーザーデータを確実に保護する&lt;&#x2F;li&gt;
&lt;li&gt;SuperDuperの場合は&lt;code&gt;Backup - User files&lt;&#x2F;code&gt;オプションが効率的&lt;&#x2F;li&gt;
&lt;li&gt;TimeMachineを使う場合は、同様にデータのバックアップに重点を置く&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;リカバリー戦略&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;問題発生時：
&lt;ol&gt;
&lt;li&gt;リカバリーモードから起動（⌘+Rキー）&lt;&#x2F;li&gt;
&lt;li&gt;OSをクリーンインストール&lt;&#x2F;li&gt;
&lt;li&gt;Migration Assistantを使ってバックアップからデータを復元&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ストレージの選択&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ユーザーデータのみをバックアップする場合、Mac本体と同程度の容量で十分&lt;&#x2F;li&gt;
&lt;li&gt;頻繁にアクセスする場合はSSD、コスト重視ならHDDを選択&lt;&#x2F;li&gt;
&lt;li&gt;NASを使用すれば、ネットワーク経由で自動バックアップも可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;SuperDuperとTimeMachineの選択基準&quot;&gt;SuperDuperとTimeMachineの選択基準&lt;&#x2F;h2&gt;
&lt;p&gt;私自身はSuperDuperを使用していますが、有償のソフトウェアですしApple謹製の
TimeMachineを使いたい方もいると思います。
次のような観点で選択すればよいと思います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SuperDuperを選ぶ場合&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;バックアップから直接ファイルにアクセスしたい&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;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TimeMachineを選ぶ場合&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;設定の簡単さを重視&lt;&#x2F;li&gt;
&lt;li&gt;過去バージョンへの簡単なアクセスが必要&lt;&#x2F;li&gt;
&lt;li&gt;macOSに標準搭載の機能のみで完結させたい&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;Apple Silicon時代では、起動可能なバックアップよりも「確実にデータを保護し、
必要時に復元できる」戦略が重要です。OSはリカバリーモードから再インストールし
、大切なユーザーデータは確実にバックアップしておくことで、トラブル時も迅速に
復旧できます。&lt;&#x2F;p&gt;
&lt;p&gt;SuperDuperの最新ベータ版ではブータビリティの改善が進んでいますが、
現実的な運用としてはユーザーデータに焦点を当てた戦略が効率的です。&lt;&#x2F;p&gt;
&lt;p&gt;また、私はpCloudも使用しているため、
特に重要なファイルはpCloud上で作業するようにしています。
過去30日分のリビジョンが保存されますし、クラウドからいつでも取り出せます。&lt;&#x2F;p&gt;
&lt;p&gt;家庭用途では、
特にストレージコストを考慮すると、データ中心の定期的バックアップと
クラウドなどへの直近のデータの保管を併用すれば十分な保護が可能です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">4月に入って日本語対応のApple IntelligenceをサポートしたmacOS Sequoia15.4、4月16日にはセキュリティアップデートのための15.1、その他Command LineToolsのアップデートなどが続いています。これらの更新の前には都度Macのバックアップと取っていますが、改めてMacのバックアップについて検討してみました。</summary>
        </entry><entry xml:lang="en">
        <title>国税庁の法人番号システムWeb-APIの検証</title>
        <published>2025-04-18T00:00:00+00:00</published>
        <updated>2025-04-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/company-info-api/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/company-info-api/</id>
        
            <content type="html">&lt;p&gt;仕事で企業を一意に特定するという要件があり、法人番号制度を利用するために
国税庁が提供する法人番号システムのWeb API
の検証のためのコードを作成してみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;法人番号制度とは&quot;&gt;法人番号制度とは&lt;&#x2F;h2&gt;
&lt;p&gt;法人番号制度は、2015年10月5日に発足しました。
この制度は、行政の効率化、国民の利便性の向上、および公平・公正な社会の実現を
目的として導入されました。法人には13桁の番号が指定され、商号や所在地といった
基本情報とともに国税庁の法人番号公表サイトで公開されています。&lt;&#x2F;p&gt;
&lt;p&gt;特に近年では、2023年10月から開始されたインボイス制度（適格請求書等保存方式）
との関連で、登録番号（T+法人番号等）を記載した適格請求書の発行が消費税の
仕入税額控除の要件となっているためシステムで扱うことも多くなっています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;国税庁のWeb_APIについて&quot;&gt;国税庁のWeb APIについて&lt;&#x2F;h2&gt;
&lt;p&gt;国税庁が提供するAPIについては、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.houjin-bangou.nta.go.jp&#x2F;webapi&#x2F;index.html&quot;&gt;法人番号システムのWep API&lt;&#x2F;a&gt;
のページに利用方法や申し込み方法がガイドされています。&lt;&#x2F;p&gt;
&lt;p&gt;利用には国税庁が振り出す「アプリケーションID」を取得する必要があります。
次の２つのアプリケーションIDがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;インボイスWeb-APIを利用できるアプリケーションID&lt;&#x2F;li&gt;
&lt;li&gt;法人番号システムWeb-APIのみ利用できるアプリケーションID&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;前者は国税庁の承認を受ける必要がありますが、後者の法人番号システムのAPIにつ
いては申請だけでアプリケーションIDを振り出してくれます。ただし、申請してから
２週間から1ヶ月程度かかります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;法人情報検索APIクライアント&quot;&gt;法人情報検索APIクライアント&lt;&#x2F;h2&gt;
&lt;p&gt;Typescriptで検証のためのコードを書いてみました。&lt;&#x2F;p&gt;
&lt;p&gt;法人名、または法人番号で検索できます。&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;get-company-info&quot;&gt;GitHubに公開&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;&#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; npm start --  --type name 任天堂株式会社&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;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; company-info-api@1.0.0 start&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;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; node dist&#x2F;index.js --type name 任天堂株式会社&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-entity z-name z-function&quot;&gt;含まれている日本語：&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;日本語を含むか：&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-true&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-keyword z-operator&quot;&gt;&amp;lt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;xml version&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;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; encoding&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;quot;UTF-8&amp;quot;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;corporations&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lastUpdateDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;2025-04-18&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;lastUpdateDate&amp;gt;&amp;lt;count&amp;gt;1&amp;lt;&#x2F;count&amp;gt;&amp;lt;divideNumber&amp;gt;1&amp;lt;&#x2F;divideNumber&amp;gt;&amp;lt;di&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;videSize&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;divideSize&amp;gt;&amp;lt;corporation&amp;gt;&amp;lt;sequenceNumber&amp;gt;1&amp;lt;&#x2F;sequenceNumber&amp;gt;&amp;lt;corpo&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;rateNumber&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1130001011420&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;corporateNumber&amp;gt;&amp;lt;process&amp;gt;01&amp;lt;&#x2F;process&amp;gt;&amp;lt;correct&amp;gt;1&amp;lt;&#x2F;c&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;orrect&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;updateDate&amp;gt;2018-07-18&amp;lt;&#x2F;updateDate&amp;gt;&amp;lt;changeDate&amp;gt;2015-10-05&amp;lt;&#x2F;changeDat&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;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;name&amp;gt;任天堂株式会社&amp;lt;&#x2F;name&amp;gt;&amp;lt;nameImageId&#x2F;&amp;gt;&amp;lt;kind&amp;gt;301&amp;lt;&#x2F;kind&amp;gt;&amp;lt;prefectureName&amp;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;京都府&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;prefectureName&amp;gt;&amp;lt;cityName&amp;gt;京都市南区&amp;lt;&#x2F;cityName&amp;gt;&amp;lt;streetNumber&amp;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;立町１１番地１&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;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;streetNumber&amp;gt;&amp;lt;addressImageId&#x2F;&amp;gt;&amp;lt;prefectureCode&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;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;6&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;prefectureCode&amp;gt;&amp;lt;cityCod&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;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;107&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;cityCode&amp;gt;&amp;lt;postCode&amp;gt;6018116&amp;lt;&#x2F;postCode&amp;gt;&amp;lt;addressOutside&#x2F;&amp;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;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;addressOutsideImageId&#x2F;&amp;gt;&amp;lt;closeDate&#x2F;&amp;gt;&amp;lt;closeCause&#x2F;&amp;gt;&amp;lt;successorCorporateNumber&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;changeCause&#x2F;&amp;gt;&amp;lt;assignmentDate&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;2015-10-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;05&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;assignmentDate&amp;gt;&amp;lt;latest&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;1&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;&#x2F;latest&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;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;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;enName&#x2F;&amp;gt;&amp;lt;enPrefectureName&#x2F;&amp;gt;&amp;lt;enCityName&#x2F;&amp;gt;&amp;lt;enAddressOutside&#x2F;&amp;gt;&amp;lt;furigana&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;ニンテ&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-source&quot;&gt;&amp;lt;&#x2F;furigana&amp;gt;&amp;lt;hihyoji&amp;gt;0&amp;lt;&#x2F;hihyoji&amp;gt;&amp;lt;&#x2F;corporation&amp;gt;&amp;lt;&#x2F;corporations&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 class=&quot;z-entity z-name z-function&quot;&gt;╰─❯&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm start -- --format csv --type name 任天堂株式会社&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;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; company-info-api@1.0.0 start&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;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; node dist&#x2F;index.js --format csv --type name 任天堂株式会社&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-entity z-name z-function&quot;&gt;含まれている日本語：&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;日本語を含むか：&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-true&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-entity z-name z-function&quot;&gt;2025-04-18,1,1,1&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;1,1130001011420,01,1,2018-07-18,2015-10-05,&amp;quot;任天堂株式会社&amp;quot;,,301,&amp;quot;京都府&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-entity z-name z-function&quot;&gt;京都市南区&amp;quot;,&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-entity z-name z-function&quot;&gt;,26,107,6018116,,,,,,,2015-10-05,1,,,,,&amp;quot;ニンテンドウ&amp;quot;,0&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;一応国の仕組みで、一意に法人を特定できるのいろいろ活用できて便利そうです。&lt;&#x2F;p&gt;
&lt;p&gt;私が社会人になりたての頃に同じような要件があり、
当時はこういったものがありませんでした。
そのため、名寄せしたり帝国データバンクの企業情報とぶつけたり苦労しました。
国がこんなものを提供してくれるなんて、いい時代だ。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2025-04-20_追記&quot;&gt;2025-04-20 追記&lt;&#x2F;h2&gt;
&lt;p&gt;経済産業省も法人番号で検索できるAPIを公開していたので、対応しました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">I had a requirement at work to uniquely identify companies, and to utilize the corporate number system, I created code to verify the Web API of the Corporate Number System provided by the National Tax Agency.</summary>
        </entry><entry xml:lang="en">
        <title>AWS Document MCP Serverを試す</title>
        <published>2025-04-16T00:00:00+00:00</published>
        <updated>2025-04-16T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/aws-mcp-servers/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/aws-mcp-servers/</id>
        
            <content type="html">&lt;h2 id=&quot;公式ブログ記事の概要&quot;&gt;公式ブログ記事の概要&lt;&#x2F;h2&gt;
&lt;p&gt;公開されたのは「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;machine-learning&#x2F;introducing-aws-mcp-servers-for-code-assistants-part-1&#x2F;&quot;&gt;Introducting AWS MCP Servers for code assistants(Part1)&lt;&#x2F;a&gt;
」という記事です。AWS MCPサーバーが紹介されています。&lt;&#x2F;p&gt;
&lt;p&gt;これらは、AWSのベストプラクティスを開発ワークフローに直接統合する特化型の
Model Context Protocol（MCP）サーバーのオープンソーススイートです。
このサーバー群は、AIアシスタントとAWSの深い知識を組み合わせ、開発時間を大幅に
短縮しながら、セキュリティコントロール、コスト最適化、AWS Well-Architectedの
ベストプラクティスを取り入れることを目的としているようです。&lt;&#x2F;p&gt;
&lt;p&gt;主要な特化型MCPサーバーとして以下が提供されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;コア：&lt;&#x2F;strong&gt; AIプロセスパイプライン機能を提供する基盤サーバー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AWS CDK：&lt;&#x2F;strong&gt; CDKの知識とベストプラクティス実装ツールを提供&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Amazon Bedrock Knowledge Bases：&lt;&#x2F;strong&gt; 企業の知識ベースへシームレスにアクセス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Amazon Nova Canvas：&lt;&#x2F;strong&gt; Amazon Bedrockを通じた画像生成機能を提供&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コスト分析：&lt;&#x2F;strong&gt; AWSサービスのコストを分析し、詳細なレポートを生成&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;具体的にどのようなMCPサーバーが提供されているかは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;awslabs&#x2F;mcp&#x2F;&quot;&gt;GitHub&lt;&#x2F;a&gt;で公開されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWS_Documentation_MCP_Serverを試す&quot;&gt;AWS Documentation MCP Serverを試す&lt;&#x2F;h2&gt;
&lt;p&gt;手っ取り早そうなので、AWS Documentation MCP Serverを試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;このAPIでは、AWSの公式ドキュメントとベストプラクティスにアクセスしたり、
ドキュメントをMarkdown形式にコンバートできるようです。&lt;&#x2F;p&gt;
&lt;p&gt;AWSの提供する設定サンプルを見ると、Astral社が開発したPython向けのツール管理
コマンド &lt;code&gt;uv&lt;&#x2F;code&gt;を使用しているようです。まず、&lt;code&gt;uv&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;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; curl -LsSf https:&#x2F;&#x2F;astral.sh&#x2F;uv&#x2F;install.sh&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; sh&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;# Macで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;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; brew install uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;デスクトップ版Claudeからアクセスする想定で設定します。
設定メニュー内の開発者メニューから、&lt;code&gt;claude_desktop_config.json&lt;&#x2F;code&gt;を開いて編集
します。&lt;&#x2F;p&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 z-definition z-string z-string&quot;&gt;  &amp;quot;mcpServers&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;inkdrop&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;&#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&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;env&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;INKDROP_LOCAL_SERVER_URL&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;http:&#x2F;&#x2F;localhost:19840&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_USERNAME&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;hogehoge&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_PASSWORD&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;hagehage&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;claude_code&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;&#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;claude-code-mcp&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&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;env&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;    },&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;aws_document&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;&#x2F;opt&#x2F;homebrew&#x2F;bin&#x2F;uvx&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&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;awslabs.aws-documentation-mcp-server@latest&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&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;FASTMCP_LOG_LEVEL&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;ERROR&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;disabled&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;autoApprove&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;    }&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-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この例では、Inkdrop, Claude CodeもMCPサーバーとして登録していますが、
必要なのは最後の例だけです。なお、上記はHomebrewでインストールした場合です。
公式インストーラーを使用した場合、パスが異なりますから注意してください。&lt;&#x2F;p&gt;
&lt;p&gt;上記の設定後、Claudeの再起動が必要です。&lt;&#x2F;p&gt;
&lt;p&gt;早速確認してみましょう。&lt;&#x2F;p&gt;
&lt;p&gt;デスクトップ版Claudeから、
「aws_documentから東京リージョンでBedrockにて
利用可能なモデルの一覧を作成してください」と依頼してみました。&lt;&#x2F;p&gt;
&lt;p&gt;以下のように、MCP使用の許可を求めながら処理を行っています。&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;お手伝いします。AWS Bedrockで現在利用可能なモデルの一覧を作成するために、AWS&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;モデル情報の詳細を確認するために、関連するAWSドキュメントページを読み取りま&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;&#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;を検索します：&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;サポートされているモデルのリストを確認するために、もう一つのドキュメントを読&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;&#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;&#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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Converseで利用可能なモデルを確認します：&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;モデルのリージョン対応を確認するために、追加のドキュメントを読み取ります：&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;これで十分な情報が得られました。収集した情報に基づいて、AWS Bedrockで現在利&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS Bedrockで現在利用可能なモデルの一覧をまとめました。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;結果、完成したドキュメント&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;は、AWSのSolution Architectが作成したような丁寧な回答でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はAWS Documentation MCP Serverをデスクトップ版Claudeからアクセスすること
を試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;最近のClaudeはWeb検索をやってくれるので、MCPサーバーを使用
しなくても同様の結果は得ることができそうです。
しかし、ソースを限定して「公式ドキュメントから」と指定できるのは安心です。&lt;&#x2F;p&gt;
&lt;p&gt;Core MCP Serverというものが提供されており、一連のMCPサーバーのオーケストレー
ションを行うようです。もしかすると今回の使い方は想定と違うのかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;AWS Diagram MCP ServerはAWSダイアグラムを生成してくれるようなのです。
実際の環境からその各種ダイアグラムをGraphVizで描いてくれるなら、
取っても便利そうです。&lt;&#x2F;p&gt;
&lt;p&gt;やっぱり、今MCPは熱いですね。&lt;&#x2F;p&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;Claude Artifactsで生成されたドキュメント（一時URLのため現在はアクセス不可） &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">4月1日のAWS公式ブログで、AWS MCP Serversの記事が掲載されました。早速AWS公式ドキュメントをMCPサーバーとして利用できるAWS Documentation MCP Serverを試してみました。</summary>
        </entry><entry xml:lang="en">
        <title>プロンプトエンジニアリング技法の総合ガイド</title>
        <published>2025-04-15T00:00:00+00:00</published>
        <updated>2025-04-15T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/prompt-engineering/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/prompt-engineering/</id>
        
            <content type="html">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aibase.com&#x2F;ja&#x2F;news&#x2F;17051&quot;&gt;AI Baseの記事&lt;&#x2F;a&gt;でこのホワイトペーパーが紹介されていたので、
原文を読んでみました。&lt;&#x2F;p&gt;
&lt;p&gt;この論文は、大規模言語モデル(LLM)向けのプロンプトエンジニアリング手法を包括的に解説しています。
データサイエンティストでなくても効果的なプロンプトを作成できること、
LLMの設定（温度、top-K、top-P、トークン制限など）がプロンプトの効果に大きく影響することなどが
強調されています。&lt;&#x2F;p&gt;
&lt;p&gt;プロンプトテクニックとして整理されており、生成AIと付きあう前提のナレッジとし
て有用だと思うのでまとめておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;出典情報&quot;&gt;出典情報&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;論文タイトル：「Prompt Engineering」（※掲載サイトgptaiflow.techは閉鎖済み）&lt;&#x2F;li&gt;
&lt;li&gt;著者：Lee Boonstra（他複数の貢献者）&lt;&#x2F;li&gt;
&lt;li&gt;発行元：Google&lt;&#x2F;li&gt;
&lt;li&gt;発行日：2024年11月&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;主要なプロンプト技法&quot;&gt;主要なプロンプト技法&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1._ゼロショットプロンプト_(Zero-shot_Prompting)&quot;&gt;1. ゼロショットプロンプト (Zero-shot Prompting)&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;映画レビューをPOSITIVE、NEUTRAL、NEGATIVEに分類してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レビュー：&amp;quot;Her&amp;quot;は人工知能の進化が人類に与える影響を描いた傑作です。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._ワンショット&#x2F;フューショットプロンプト_(One-shot_&amp;amp;_Few-shot_Prompting)&quot;&gt;2. ワンショット&#x2F;フューショットプロンプト (One-shot &amp;amp; Few-shot Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;1つまたは複数の例を示すことで、モデルに期待する出力パターンを教える手法です。&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;顧客のピザ注文をJSONに解析してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;例: &amp;quot;チーズとペパロニのピザを注文したい&amp;quot; →&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&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;size&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;small&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ingredients&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;cheese&amp;quot;&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;quot;pepperoni&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-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&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;quot;モッツァレラとバジルのピザをLサイズで&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3._システムプロンプト_(System_Prompting)&quot;&gt;3. システムプロンプト (System Prompting)&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;映画レビューを分類し、結果をJSONフォーマットで返してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;4._ロールプロンプト_(Role_Prompting)&quot;&gt;4. ロールプロンプト (Role Prompting)&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;旅行ガイドとして振る舞ってください。アムステルダムで訪れるべき3つの場所をリ&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;h3 id=&quot;5._文脈プロンプト_(Contextual_Prompting)&quot;&gt;5. 文脈プロンプト (Contextual Prompting)&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;文脈：あなたは80年代のレトロゲームについてのブログを書いています。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;そのブログ用の記事のトピックを3つ提案してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;6._ステップバックプロンプト_(Step-back_Prompting)&quot;&gt;6. ステップバックプロンプト (Step-back Prompting)&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;FPSゲームのレベル設計で重要な要素は何ですか？&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;その要素を考慮したFPSゲームのレベルの設計案を作成してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;7._思考連鎖_(Chain_of_Thought,_CoT)&quot;&gt;7. 思考連鎖 (Chain of Thought, CoT)&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;3歳の時、パートナーは私の3倍の年齢でした。現在私は20歳です。&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;ステップバイステップで考えましょう。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;8._自己一貫性_(Self-consistency)&quot;&gt;8. 自己一貫性 (Self-consistency)&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;このメールは重要ですか？内容を分析して結論を導き出してください。&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;h3 id=&quot;9._思考木_(Tree_of_Thoughts,_ToT)&quot;&gt;9. 思考木 (Tree of Thoughts, ToT)&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;[問題解決において複数のアプローチを同時に検討させる手法]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;10._ReAct（理由付けと行動）_(ReAct:_Reason_&amp;amp;_Act)&quot;&gt;10. ReAct（理由付けと行動） (ReAct: Reason &amp;amp; Act)&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;メタリカのバンドメンバーには合計何人の子供がいますか？&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;h3 id=&quot;11._自動プロンプトエンジニアリング_(Automatic_Prompt_Engineering)&quot;&gt;11. 自動プロンプトエンジニアリング (Automatic Prompt Engineering)&lt;&#x2F;h3&gt;
&lt;p&gt;LLMを使って他のLLM用のプロンプトを生成・評価・改善する手法です。LLMでなくMidjourney向けのプロンプトを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;Tシャツを注文する10種類の表現を生成してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;12._コードプロンプティング_(Code_Prompting)&quot;&gt;12. コードプロンプティング (Code Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;コード関連のタスクに特化したプロンプト技法については、次の4つのサブカテゴリに分けることができます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;a._コードを書くためのプロンプト_(Prompts_for_writing_code)&quot;&gt;a. コードを書くためのプロンプト (Prompts for writing code)&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;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;特定のフォルダ内のすべてのファイル名の先頭に&amp;quot;draft&amp;quot;という文字列を追加する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bashスクリプトを書いてください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;b._コードを説明するためのプロンプト_(Prompts_for_explaining_code)&quot;&gt;b. コードを説明するためのプロンプト (Prompts for explaining code)&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;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;以下のBashコードを説明してください：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;フォルダ名を入力してください：&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;read folder_name&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;h4 id=&quot;c._コードを翻訳するためのプロンプト_(Prompts_for_translating_code)&quot;&gt;c. コードを翻訳するためのプロンプト (Prompts for translating code)&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;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;以下のBashスクリプトをPythonコードに変換してください：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;フォルダ名を入力してください：&amp;quot;&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;h4 id=&quot;d._コードをデバッグ・レビューするためのプロンプト_(Prompts_for_debugging_and_reviewing_code)&quot;&gt;d. コードをデバッグ・レビューするためのプロンプト (Prompts for debugging and reviewing code)&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;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;以下のPythonコードにはエラーがあります：&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;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-source&quot;&gt;folder_name&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 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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;フォルダ名を入力：&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-source&quot;&gt;prefix&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 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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;ファイル名の先頭に追加する文字列：&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-source&quot;&gt;text&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; toUpperCase&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;prefix&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;...&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;次に個別のテクニックというよりプロンプト全般でのベストプラクティスです。&lt;&#x2F;p&gt;
&lt;ol&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;：「3段落のブログ記事を生成」など具体的に&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;制約よりも指示を優先&lt;&#x2F;strong&gt;：否定形より肯定形の表現が効果的&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;JSONなどの構造化出力を使用&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;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;li&gt;&lt;strong&gt;プロンプトの試行を詳細に記録&lt;&#x2F;strong&gt;：モデル、設定、プロンプト、出力を文書化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;一旦JSON経由にするなど経験としては効果的なので、私はよく使います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;この論文ではプロンプトエンジニアリングの様々な技法を紹介しています。ゼロショットから高度な推論技法（思考連鎖、自己一貫性、思考木）、そしてコード生成・操作のためのプロンプティングまで、幅広い手法が解説されています。&lt;&#x2F;p&gt;
&lt;p&gt;プロンプトエンジニアリングは反復的なプロセスであり、モデルのパフォーマンスに基づいてプロンプトを継続的に改良することが重要です。また、表形式でプロンプト試行を記録し、異なるモデルバージョンや設定での結果を比較することが推奨されています。&lt;&#x2F;p&gt;
&lt;p&gt;コードプロンプティングの分野では、生成、説明、翻訳、デバッグという開発サイクル全体をカバーする技法が提示されており、開発効率の向上に貢献します。特にデバッグとレビューの機能は、単なるバグ修正だけでなく、コード品質の全体的な向上につながる可能性を持っています。&lt;&#x2F;p&gt;
</content>
        <summary type="html">最近GoogleのLee Boonstrが最近発表した69ページのプロンプトエンジニアリングに関するホワイトペーパーを読みました。このホワイトペーパーでは大規模言語モデル（LLM）との対話を最適化するための包括的なガイドを提供されています。これまでなんとなく経験や勘で作っていたプロンプトを、テクニックとして整理することができます。</summary>
        </entry><entry xml:lang="en">
        <title>Synthersizer V Studio 2 Pro</title>
        <published>2025-04-15T00:00:00+00:00</published>
        <updated>2025-04-15T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/synthesizer-v-studio-2-pro/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/synthesizer-v-studio-2-pro/</id>
        
            <content type="html">&lt;p&gt;とりあえず、昨年Synthersizer V 1で作った藤原さくらさんの「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;soundcloud.com&#x2F;yostos&#x2F;just-one-girl-1?si=b7db2a56715c423eb6402905f5029c64&amp;amp;utm_source=clipboard&amp;amp;utm_medium=text&amp;amp;utm_campaign=social_sharing&quot;&gt;Just One Girl&lt;&#x2F;a&gt;
」をSynthesizer V 2でヴォーカル部分をリテイクしてみました。&lt;&#x2F;p&gt;
&lt;div class=&quot;youtube-container&quot; style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;M_wFVSNXj3c&quot;
    style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&quot;
    frameborder=&quot;0&quot;
    allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;以前のバージョンでもかなりリアルなヴォーカルなのであまり改善点がわからないか
もしれませんが、以下に変更点をまとめておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Sythesizer_V_Studio_2_Proの変更点&quot;&gt;Sythesizer V Studio 2 Proの変更点&lt;&#x2F;h2&gt;
&lt;p&gt;次のような変更がなされています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;歌声生成速度の改善&quot;&gt;歌声生成速度の改善&lt;&#x2F;h3&gt;
&lt;p&gt;Synthesizer V 2では歌声の生成速度が改善され、以前のSynthesizer Vに比べると300% 速くなったとのことです。&lt;&#x2F;p&gt;
&lt;p&gt;以前のバージョンでは編集時にノート1つ音程を変更しただけで少し待たないと再生できませんでしたが、
Synthesizer V 2では、ノートの編集後に再生できるまでの時間が短くなり待たされ
るという感覚がほぼありません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;新しいボーカルモードの機能&quot;&gt;新しいボーカルモードの機能&lt;&#x2F;h3&gt;
&lt;p&gt;ボーカルモードはシンガーの歌声にバリエーションを持たせる機能ですが、
Synthesizer V 2では各パラメータが「ピッチ(Pitch)」「音色(Timbre)」「発声
(Pronun)」へと分解可能となりました。&lt;&#x2F;p&gt;
&lt;p&gt;これにより、ピッチに関しては「Clear」スタイルを強く適用するけれど
発声は「ソフト」スタイルを強くするなど、細かやかな調整が可能となりました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;AIリテイク機能の改善&quot;&gt;AIリテイク機能の改善&lt;&#x2F;h3&gt;
&lt;p&gt;AIリテイクは、AIの技術を用いて異なる歌い方を生成できる機能です。&lt;&#x2F;p&gt;
&lt;p&gt;以前のバージョンでは、「ピッチ」と「声色」のみがリテイク可能でしたが、
Synthesizer V 2から「タイミング」も生成できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;AIリテイク生成時のパラメータはXYパッドのようなインターフェイスとなり、
「Vibrant」「Refined」「Stable」「Raw」をコントロールする方式となりました。
より直感的に音を調整できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;スマートピッチコントロール&quot;&gt;スマートピッチコントロール&lt;&#x2F;h3&gt;
&lt;p&gt;以前のSyhthesizer Vでは、ピッチ関係のパラメータは「ピッチ推移」や「ビブラー
ト」がありましたが、どのように変化するか分かりづらいものがありました。&lt;&#x2F;p&gt;
&lt;p&gt;V2ではピアノロール状でピッチ制御点を直接追加できます。制御点を通るピッチカー
ブが自動生成され、制御点をドラッグするとリアルタイムにカーブが変化します。
これまでよりずいぶんと分かりやすくなりました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;アクティベーション方法の変更&quot;&gt;アクティベーション方法の変更&lt;&#x2F;h3&gt;
&lt;p&gt;これまでアクティベーションコードを製品に入力する方式だったと思いますが、
今回からDreamtonicsのアカウントと紐付いて製品がアクティベーションを行うよう
になりました。&lt;&#x2F;p&gt;
&lt;p&gt;従ってDreamtonicsのアカウントを作成し、そこに製品登録をきちんとやっておく必
要があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;以前のバージョンでもかなりリアルなヴォーカルを生成できましたが、
今回のバージョンアップでより細かなコントロールが可能となりました。&lt;&#x2F;p&gt;
&lt;p&gt;私自身はそこまでヴォーカルを調整することはありませんが、
エンジンとデータベースを更新するだけでも以前不自然だった部分が
かなり改善されます。&lt;&#x2F;p&gt;
&lt;p&gt;円安でちょっと高いですが、バージョンアップの価値はあると思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">歌声合成ソフトウェア「Synthesizer V」の新バージョンである、「Synthesizer V 2」が3月21日に発売されていたので、アップグレードしました。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic announced Claude Max Plan</title>
        <published>2025-04-10T00:00:00+00:00</published>
        <updated>2025-04-10T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/anthropic-max-plan/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/anthropic-max-plan/</id>
        
            <content type="html">&lt;p&gt;今朝Anthropicから新しいプランの案内する次のようなメールが来ていました。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
  We’ve heard your request for more access to Claude so you can maintain
  momentum on your most demanding projects with less disruption. Today, we’re
  introducing the new Max plan that delivers exactly that. With the Max plan,
  you can get:
  &lt;ul&gt;
    &lt;li&gt;
      &lt;strong&gt;Substantially more usage&lt;&#x2F;strong&gt; to work with Claude
    &lt;&#x2F;li&gt;
    &lt;li&gt;
      &lt;strong&gt;5x more usage&lt;&#x2F;strong&gt; ($100&#x2F;month) or 20x more usage ($200&#x2F;month)
      than Pro
    &lt;&#x2F;li&gt;
    &lt;li&gt;
      &lt;strong&gt;Be among the first&lt;&#x2F;strong&gt; to try the most advanced Claude
      capabilities
    &lt;&#x2F;li&gt;
    &lt;li&gt;
      &lt;strong&gt;Flexibility&lt;&#x2F;strong&gt; to scale as your needs grow
    &lt;&#x2F;li&gt;
  &lt;&#x2F;ul&gt;
  Your best ideas deserve more room to grow. We’re excited to see the new
  possibilities the Max plan can unlock for you.
  &lt;footer&gt;
    &lt;cite&gt;
      &amp;mdash;Anthropic&quot;Introducing the Max plan — get more Claude usage than
      ever before&quot;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;新しい&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;pricing&quot;&gt;Claude Maxプラン&lt;&#x2F;a&gt;の案内です
。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Max_プランの概要&quot;&gt;Claude Max プランの概要&lt;&#x2F;h2&gt;
&lt;p&gt;Claude MaxプランはClaude Proプランの上位サブスクリプションとして、業務用途や超
ヘビーユーザーを対象として用意されたものです。&lt;&#x2F;p&gt;
&lt;p&gt;強化されるポイントは以下のような点です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1._利用上限の拡大&quot;&gt;1. &lt;strong&gt;利用上限の拡大&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Claude Maxでは、既存の「Claude Pro」プラン（月額20ドル）と比較して以下のよう
な利用上限の大幅な拡大が行われます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;月額100ドルプラン&lt;&#x2F;strong&gt;: Proプランの5倍の使用量。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;月額200ドルプラン&lt;&#x2F;strong&gt;: Proプランの20倍の使用量。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これにより、長文の処理や複雑なタスク、大量のリクエストを頻繁に行う用途でも、
中断を気にすることなく作業を進行可能です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2._新機能への優先アクセス&quot;&gt;2. &lt;strong&gt;新機能への優先アクセス&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;「Claude Max」加入者は、Anthropicの最新AIモデルや新機能に優先的にアクセスで
きる特典が付与されます。これには以下が含まれます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;新モデルへの早期アクセス。&lt;&#x2F;li&gt;
&lt;li&gt;新機能のテスト権限。&lt;&#x2F;li&gt;
&lt;li&gt;開発中の高度な機能（例: 音声モードなど）の事前利用。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3._コンテキストウィンドウの最大化&quot;&gt;3. &lt;strong&gt;コンテキストウィンドウの最大化&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;このプランでは、モデルが一度に処理できるテキスト量（コンテキストウィンドウ）
が従来モデルよりもさらに拡充されています。長文や複雑な文脈に依存する作業が効
率的に行えます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4._混雑時の優先アクセス&quot;&gt;4. &lt;strong&gt;混雑時の優先アクセス&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;「Claude Max」プランのユーザーは、混雑した時間帯でも優先的にアクセスできるた
め、業務上の遅延を回避できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Maxプランの評価&quot;&gt;Claude Maxプランの評価&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Maxプランは、OpenAIのChatGPT Pro（月額200ドル）やその他の競合サービスへの対
抗策として設計されており、AIアシスタントの活用をさらに拡大したい次のようなユーザーに
とって魅力的な選択肢となっています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;作業を改良し完成させるために長時間の会話が必要&lt;&#x2F;li&gt;
&lt;li&gt;定期的に大量の文書や複雑なデータを扱う&lt;&#x2F;li&gt;
&lt;li&gt;現在の使用制限を待てない締め切りがある&lt;&#x2F;li&gt;
&lt;li&gt;日常のさまざまなタスクでClaudeに頼っている&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私自身もClaude Proを使っていますが、複雑なこと検討では上限に達してしまい一時
的に中断しなければならないシーンは確かにあります。ただ、次のような観点から
このClaude Maxプランは利用しないと思います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;使用制限を受けてしまうことはあるが、緊急性はそれほど高くないため多くの場合
は一時的に作業を中断できる。緊急性が高い場合はClade Codeなどの代替手段がある&lt;&#x2F;li&gt;
&lt;li&gt;大量情報を使った処理はチャットウィンドウで行うより、Claude CodeやMCP経由
でClaude Desktopで処理したほうが効率的&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;つまり技術者であれば、Claude Proプランと有償のAPI経由でClaudeを利用したほう経済的
、かつ効率的です。非技術者でヘビーにClaudeを活用し高い緊急度のニーズがある場
合はClaude Maxプランが向いていると思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropic announced Claude Max Plan</summary>
        </entry><entry xml:lang="en">
        <title>OpenAI will support MCP</title>
        <published>2025-04-08T00:00:00+00:00</published>
        <updated>2025-04-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/openai-mcp-support/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/openai-mcp-support/</id>
        
            <content type="html">&lt;h2 id=&quot;AltmanのツイートによるMCP対応のアナウンス&quot;&gt;AltmanのツイートによるMCP対応のアナウンス&lt;&#x2F;h2&gt;
&lt;p&gt;以下が3月末のAltmanのツイート(X)です。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;x.com&#x2F;sama&#x2F;status&#x2F;1904957253456941061&quot;&gt;
  people love MCP and we are excited to add support across our products.
  available today in the agents SDK and support for chatgpt desktop app +
  responses api coming soon!
  &lt;footer&gt;
    &lt;cite&gt;
      &lt;a href=&quot;https:&#x2F;&#x2F;x.com&#x2F;sama&#x2F;status&#x2F;1904957253456941061&quot;&gt;
        &amp;mdash; Sam Altman (March 26, 2025)
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;MCP(Model Context Protocol)はAnthropicが提唱しているフレームワーク
ですが、上記は&lt;strong&gt;OpenAIもMCPをサポートする&lt;&#x2F;strong&gt;というアナウンスです。&lt;&#x2F;p&gt;
&lt;p&gt;とても重要な意味を持つアナウンスだと思います。
AnthropicはOpenAIの強力なライバルで競合関係にあります。
デファクト・スタンダードが無い現状では対応する規格を提唱できたはずですが、
それをせずMCPサポートに舵を切ったのは素晴らしい経営判断だと思います。&lt;&#x2F;p&gt;
&lt;p&gt;これにより、MCPがほぼ業界のデファクト・スタンダードになると思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCP(Model_Context_Protocol)とは&quot;&gt;MCP(Model Context Protocol)とは&lt;&#x2F;h2&gt;
&lt;p&gt;以前いくつか記事を書いていますが、ちゃんとMCPの説明を書いていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;Model Context Protocol (MCP)は、大規模言語モデル(LLM)に対する指示を構造化す
るためのフレームワークです。&lt;&#x2F;p&gt;
&lt;p&gt;次のような要素から構成されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model（モデル）&lt;&#x2F;strong&gt; - AIモデルがどのように自分自身を認識し、振る舞うべきかを定義する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Context（コンテキスト）&lt;&#x2F;strong&gt; - モデルが参照すべき情報や知識を提供する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Protocol（プロトコル）&lt;&#x2F;strong&gt; - モデルの動作や応答方法のルールを設定する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;articles&#x2F;2025&#x2F;03&#x2F;28&#x2F;claude-integration-with-inkdrop&quot;&gt;以前の記事&lt;&#x2F;a&gt;では、
&lt;strong&gt;Context&lt;&#x2F;strong&gt;を使って独自のナレッジ(Inkdrop)をClaudeに追加するということをやっただけですが、
Claude活用の可能性が途端に広がりものすごい効果を体感できました。これまでも
Contextの部分にだけ限るとRAG (Retrieval-Augmented Generation)という手法があ
りましたが、こんなに簡単にはできなかったと思います。&lt;&#x2F;p&gt;
&lt;p&gt;MCPではContextだけでなく、Protocolを通じて行動規範の設定や、Modelを通じた企業の
ブランドトーンに合わせた応答スタイルなどに応用できます。&lt;&#x2F;p&gt;
&lt;p&gt;MCPにより、明確に分離された要素(Model&#x2F;Context&#x2F;Protocol)に整理され、
単なるプロンプトエンジニアリングを超えて体系化されたアプローチで
AIの応答をより予測可能で一貫性のあるものにすることが可能となりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPがデファクト・スタンダードになると&quot;&gt;MCPがデファクト・スタンダードになると&lt;&#x2F;h2&gt;
&lt;p&gt;MCPがデファクト・スタンダードとなればAI関連ツール間の標準化された通信パターンを
提供していることになるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;この事実を踏まえるとClaudeデスクトップがClaude Codeをナレッジソースとして扱えるように、次のよう
なことが可能になるかもしれません。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT-Claudeクロス連携&lt;&#x2F;strong&gt;: ChatGPTの回答をClaudeが評価するようなAIシステム間の直接的な情報交換や連携&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AIオーケストレーション&lt;&#x2F;strong&gt;: 複数の生成AIがそれぞれ
の強みを生かした連携し、結果を統合するようなワークフロー構築の可能性。例え
ば、データ解析はChatGPT、文章生成はClaude、検証はGeminiなどの役割分担するイ
メージ。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;統一ナレッジアクセス&lt;&#x2F;strong&gt;: マーケットにMCP準拠した多数のナレッジベースが
登場し、簡単に新しいナレッジを自社のAIに追加できる可能性&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;いずれも現時点で実現できるかどうか検証が必要というレベルです。
AIオーケストレーションなどは追加の標準化やツールが必要でしょう。
また、技術的に標準化の方向で協力できたからと言って、今後ビジネス上の判断で
その適用範囲が制限される可能性はあります。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、このような動きを見ていると、加速度的にAIの世界が拡がっていくのを実感しています。楽しみです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">MCPをサポートしたAnthropicのClaudeで試しましたが、その可能性に驚きました。3月末にはOpenAIもMCP対応を表明していたので楽しみです。</summary>
        </entry><entry xml:lang="en">
        <title>Open Graph Protocol対応</title>
        <published>2025-04-07T00:00:00+00:00</published>
        <updated>2025-04-07T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/open-graph-protocol/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/open-graph-protocol/</id>
        
            <content type="html">&lt;h2 id=&quot;Open_Graph_Protocolとは&quot;&gt;Open Graph Protocolとは&lt;&#x2F;h2&gt;
&lt;p&gt;Open Graph Protocol(OGPとも呼ばれます)は、Webページの内容をSNSなどで共有する際に、正確な情報を
表示するための仕組みです。
2010年にFacebookが開発し、現在は多くのWebサイトで採用されています。&lt;&#x2F;p&gt;
&lt;p&gt;OGPでは、HTMLのhead内にmeta要素を配置し、「og:」というプレフィックスを持つプ
ロパティを使用して、ページの様々な情報を定義します。
主な要素としては、ページのタイトル、ページの説明、サムネイル画像のURL、
正規URLなどがあります。&lt;&#x2F;p&gt;
&lt;p&gt;これらの情報を適切に設定することで、FacebookやTwitter、LINEなどのSNSでリンクがシェアされた際に、
単なるURLではなく、タイトル、説明文、画像を含む魅力的なプレビューカードが表示されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;このブログの対応&quot;&gt;このブログの対応&lt;&#x2F;h2&gt;
&lt;p&gt;記事ページのメタ情報を管理している&lt;code&gt;lib&#x2F;metadata.ts&lt;&#x2F;code&gt;を修正してOGPに対応するヘッダを
追加するロジックを入れました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; generateArticleMetadata&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;  article&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-type&quot;&gt; Article&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt; path&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-type z-primitive&quot;&gt; string&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-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Metadata&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; pathがある場合はURLを生成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; url&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; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;path&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-entity z-name z-function&quot;&gt; generateArticleUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js z-source&quot;&gt;path)&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-constant z-language z-undefined z-js&quot;&gt; undefined&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; OGP画像のURL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; ogImageUrl&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; generateOgImageUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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-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;    title&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; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;title&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;    description&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; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;description&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;    authors&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; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&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; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;author&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; siteConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-comment z-comment&quot;&gt;    &#x2F;&#x2F; OGP設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    openGraph&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      siteName&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; siteConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;sitename&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;      title&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; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;title&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;      description&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; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;description&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;article&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-operator&quot;&gt;      ...&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;      images&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; [&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-source&quot;&gt;          url&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-variable z-other z-readwrite&quot;&gt; ogImageUrl&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;          width&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-constant z-numeric&quot;&gt; 1200&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;          height&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-constant z-numeric&quot;&gt; 630&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;          alt&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; siteConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;sitename&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-source&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&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; 他にも必要なメタデータがあれば追加可能&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;Next.jsがOGPのヘッダを生成する&lt;code&gt;openGraph&lt;&#x2F;code&gt;関数を提供しているので呼び出してい
るだけです。記事自体のフルパスが必要ですが、面倒なので記事内でパスを渡すよう
にしました。&lt;&#x2F;p&gt;
&lt;p&gt;また、MDXファイル内の&lt;code&gt;Image&lt;&#x2F;code&gt;で参照している画像のフルパスはこの処理では得られ
ないので、仕方なく固定の画像を指定しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;自身はたまにBlueskeyにリンクを投稿するくらいなので、それほど必要性は高くあり
ませんが、実装自体は簡単なので対応しているの越したことはありませんね。&lt;&#x2F;p&gt;
</content>
        <summary type="html">このブログは適当に実装したので、Open Graph Protocolに対応してしていませんでした。今更ですが、Open Graph Protorol対応しSNSでリンクを投稿した時に記事情報が表示できるようにしてみました。</summary>
        </entry><entry xml:lang="en">
        <title>Claude CodeをMCPサーバーとして利用する利点</title>
        <published>2025-03-29T00:00:00+00:00</published>
        <updated>2025-03-29T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/mcp-integration-of-claude-code-inkdrop/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/mcp-integration-of-claude-code-inkdrop/</id>
        
            <content type="html">&lt;p&gt;&lt;a href=&quot;&#x2F;articles&#x2F;2025&#x2F;03&#x2F;28&#x2F;claude-integration-with-inkdrop&quot;&gt;前回の記事&lt;&#x2F;a&gt;では、 InkdropとClaude Desktopの統合について紹介しました。今回は一歩進んで、Claude CodeをMCPサーバーとして活用する方法とそのメリットについて詳しく解説します。&lt;&#x2F;p&gt;
&lt;!-- toc --&gt;
&lt;h2 id=&quot;MCP_ServerにもなれるClade_Code&quot;&gt;MCP ServerにもなれるClade Code&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを頻繁に活用することでAnthropicへの支払いコストが増加していますが、一度使い始めるとコーディング作業では手放せなくなりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;そのClaude Codeは、MCP Clientになれることは知っていました。
しかし、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;mcp&quot;&gt;公式ドキュメント&lt;&#x2F;a&gt;を読んでいてMCP Serverにもなれるというチュートリアルを発見しました。&lt;&#x2F;p&gt;
&lt;p&gt;次のコマンドでMCP Serverとして起動できます。&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;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp serve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_DesktopにClaude_CodeをMCP_Serverとして登録&quot;&gt;Claude DesktopにClaude CodeをMCP Serverとして登録&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;articles&#x2F;2025&#x2F;03&#x2F;28&#x2F;claude-integration-with-inkdrop&quot;&gt;Inkdropと同様&lt;&#x2F;a&gt;に、Claude Desktopに
Claude CodeをMCP Serverとして登録します。&lt;&#x2F;p&gt;
&lt;p&gt;また、&lt;code&gt;bash&lt;&#x2F;code&gt;の問題が起きそうだったので、例のごとくシェルスクリプトでWrapし&lt;code&gt;~&#x2F;bin&#x2F;claude-code-mcp&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-shebang z-shell z-meta z-shebang z-shell&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env 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;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp serve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;作成したスクリプトを指定して、Claude Desktopの設定ファイル &lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;Claude&#x2F;claude_desktop_config.json&lt;&#x2F;code&gt;に追加します。&lt;&#x2F;p&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;inkdrop&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;&#x2F;Users&#x2F;foo&#x2F;bin&#x2F;inkdrop-mcp&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&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;env&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;INKDROP_LOCAL_SERVER_URL&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;http:&#x2F;&#x2F;localhost:19840&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_USERNAME&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;foo&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_PASSWORD&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;bar&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;claude_code&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;&#x2F;Users&#x2F;foo&#x2F;bin&#x2F;claude-code-mcp&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&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;env&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;    }&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;h2 id=&quot;Claude_DesktopからClaude_Codeにコード分析を依頼&quot;&gt;Claude DesktopからClaude Codeにコード分析を依頼&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeをClaude Desktopに正常に接続できたことを確認したので、次のステップとして実際にこのブログサイトのコードの分析を依頼してみます。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude Desktopのチャットインターフェースで、Claude Codeにアクセスするためのプロンプトを入力&lt;&#x2F;li&gt;
&lt;li&gt;分析したいプロジェクトのパスを明示的に指定&lt;&#x2F;li&gt;
&lt;li&gt;フォルダ階層の確認を依頼&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;初回実行時には、Claude Codeがファイルシステムにアクセスするための許可を求めるプロンプトが数回表示されました。これは、セキュリティ上の理由から必要な確認プロセスです。許可を与えると、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;私：claude_code内の~&#x2F;ghq&#x2F;github.com&#x2F;foo&#x2F;blog-source&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;    また、プロジェクト内のフォルダ階層はどうなっていますか？&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;&#x2F;Users&#x2F;foo&#x2F;ghq&#x2F;github.com&#x2F;foo&#x2F;blog-sourceにアクセスできました。&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;&#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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Next.js 15, React 19, TypeScript, Tailwind CSSで構築&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MDXサポートで記事を書いている&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;ダークモード対応&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RSS、コードシンタックスハイライト、Giscusコメントシステム、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ソーシャルリンク、SoundCloudの埋め込み、Whisper機能、目次機能など&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;サイト設定では「Coded Chords」という名前のブログで、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;著者は「Toshiyuki Yoshida」です。&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;h2 id=&quot;Claude_Desktop&#x2F;Claude_Code&#x2F;InkdropのMCP統合&quot;&gt;Claude Desktop&#x2F;Claude Code&#x2F;InkdropのMCP統合&lt;&#x2F;h2&gt;
&lt;p&gt;Claude DesktopにはInkdropもMCP Serverとして登録されているので、コード解析結果をInkdropに記録させることもできます。&lt;&#x2F;p&gt;
&lt;p&gt;次のようにClaude Desktopで依頼してみました。&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;では、プロジェクト概要とプロジェクトのフォルダ構成について、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;第三者が理解しやすいようサマリーを inkdrop内のNotebook Inboxに&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;なお、形式はMarkdownを使用してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;結果、Claude Codeから取得し分析した結果、Markdown形式でInkdropのNoteとしてドキュメント化してくれました。&lt;&#x2F;p&gt;
&lt;p&gt;プロジェクト概要は&lt;code&gt;README.md&lt;&#x2F;code&gt;から読み取ったようですが、特筆すべきは、フォルダ構成や各ディレクトリの役割、記事管理の仕組みまで正確に把握・文書化している点です。&lt;&#x2F;p&gt;
&lt;p&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 TB
UserReq[ユーザーリクエスト&#x2F;指示]
CD[Claude Desktop]
CC[Claude Code]
BlogRepo[ブログリポジトリ]
InkdropMCP[inkdropapp&#x2F;mcp-server]

    subgraph Inkdrop[Inkdropアプリ]
        API[HTTP API]
        Notes[ノート]
    end

    %% 通常フロー
    UserReq --&gt;|会話形式の指示| CD
    CD --&gt;|コード分析のリクエスト| CC
    CC --&gt;|ファイル読み取り| BlogRepo
    BlogRepo --&gt;|コードとファイル内容| CC
    CC --&gt;|分析結果| CD

    %% ファイル操作フロー
    CC --&gt;|新記事作成| BlogRepo

    %% Inkdrop連携フロー
    CD --&gt;|ノート作成リクエスト| InkdropMCP
    InkdropMCP --&gt;|APIリクエスト| API
    API --&gt;|ノートデータ保存| Notes

    %% スタイル
    classDef claudeDesktop fill:#f9a8d4,stroke:#be185d,stroke-width:2px
    classDef claudeCode fill:#93c5fd,stroke:#2563eb,stroke-width:2px
    classDef inkdropCompo fill:#ffffff,stroke:#6b7280,stroke-width:1px
    classDef repository fill:#fcd34d,stroke:#d97706,stroke-width:2px
    classDef mcpServer fill:#93c5fd,stroke:#2563eb,stroke-width:2px
    classDef other fill:#e5e7eb,stroke:#6b7280,stroke-width:2px

    class CD claudeDesktop
    class CC,InkdropMCP claudeCode
    class API,Notes inkdropCompo
    class Inkdrop,BlogRepo repository
    class UserReq other

`
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;便利です。&lt;&#x2F;p&gt;
&lt;p&gt;開発プロジェクトのドキュメンテーションや&lt;code&gt;README.md&lt;&#x2F;code&gt;の作成など、次のようなワークフローにすると大変スマートに仕事が進みそうです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude DesktopからClaude Codeにリポジトリーからコード情報を収集し、そのコードを分析しMarkdown文書を生成しInkdropにNote作成させる。&lt;&#x2F;li&gt;
&lt;li&gt;Inkdrop上でMarkdown文書をPreviewで確認し、必要に応じて編集する&lt;&#x2F;li&gt;
&lt;li&gt;Claude DesktopからInkdrop上のNoteからドキュメントを収集し、Claude Codeを通じてリポジトリーにドキュメントとして格納させる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;Claude_Code_MCP_Server利用コスト&quot;&gt;Claude Code MCP Server利用コスト&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeをMCP ServerとしてClaude Desktopから利用した際のコストを確認してみました。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeをコマンドラインから普通に使うと、MODELとして &lt;code&gt;claude-3-7-sonnet-20250219&lt;&#x2F;code&gt;が使用されています。
このため、多用しているとクレジットも大量に消費されていきます。
しかし、Claude CodeをMCP Serverとして使うと、リクエストあるからと言ってClaude Codeから
MODELを使用したリクエストが出るわけでも無さそうです。またリクエストが出たとしても、今のところ&lt;code&gt;claude-3-5-haiku-20241022&lt;&#x2F;code&gt;しか利用されていません。
Tailwind Plusで提供されるコードが大量にlintで引っかかるので修正をClaud
Destop経由で行いましたが、同様Claude Codeからは&lt;code&gt;claude-3-5-haiku-20241022&lt;&#x2F;code&gt;を
利用するリクエストかでていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;Claude CodeをMCP Serverとして利用する場合、提供されるツールは以下のとおりです。これらのうち、AgentTool以外の大半はClaude Code内部で処理が完結するため、高度な分析などはClaude Desktop側から直接リクエストされると考えられます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tool&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;th&gt;Permission Required&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;AgentTool&lt;&#x2F;td&gt;&lt;td&gt;Runs a sub-agent to handle complex, multi-step tasks&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BashTool&lt;&#x2F;td&gt;&lt;td&gt;Executes shell commands in your environment&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GlobTool&lt;&#x2F;td&gt;&lt;td&gt;Finds files based on pattern matching&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GrepTool&lt;&#x2F;td&gt;&lt;td&gt;Searches for patterns in file contents&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;LSTool&lt;&#x2F;td&gt;&lt;td&gt;Lists files and directories&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FileReadTool&lt;&#x2F;td&gt;&lt;td&gt;Reads the contents of files&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FileEditTool&lt;&#x2F;td&gt;&lt;td&gt;Makes targeted edits to specific files&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FileWriteTool&lt;&#x2F;td&gt;&lt;td&gt;Creates or overwrites files&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;NotebookReadTool&lt;&#x2F;td&gt;&lt;td&gt;Reads and displays Jupyter notebook contents&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;NotebookEditTool&lt;&#x2F;td&gt;&lt;td&gt;Modifies Jupyter notebook cells&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;(2025-03-31追記)&lt;&#x2F;p&gt;
&lt;p&gt;その後、もう少し複雑な処理で確認しました。ソースを複雑に分析するような場合は、
Claude CodeでのリクエストからもMODELとして &lt;code&gt;claude-3-7-sonnet-20250219&lt;&#x2F;code&gt;が使用されていました。&lt;&#x2F;p&gt;
&lt;p&gt;依頼した処理は次のようなものです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;プロジェクトがOGP対応しているか、対応している場合はどのようなコンポーネントが関係しどのような仕様になっているか調査し、
InkdropのNotebook blogに新たに Noteを作成して仕様書にしてください。仕様書に
は静的モデルと動的モデルをMermaid でダイアグラム化してください。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Claude DesktopがInkdropに書き出した文書をそのままPDFにしたものも&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;e.pcloud.link&#x2F;publink&#x2F;show?code=XZiJhdZ3UkXV7lTN8knDkuquFjN147NvQ0y&quot;&gt;公開&lt;&#x2F;a&gt;しておき
ます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeのMCP Serverを利用する利点は2つです。&lt;&#x2F;p&gt;
&lt;p&gt;1つは、Claude Codeからのリクエスト発行を押さえ、Claude Desktopからのリクエストになることでの&lt;strong&gt;コスト削減&lt;&#x2F;strong&gt;が大きくできることです。
(2025-03-31追記) 処理内容によってはClaude Code側の処理でもSonnet 3.7が使用
されるため注意は必要です。&lt;&#x2F;p&gt;
&lt;p&gt;本来次のようにClaude DesktopとClaude Codeは使い分けるべきだと思います。&lt;&#x2F;p&gt;
&lt;dl&gt;
  &lt;dt&gt;**Claude Code**&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    - コマンドライン志向
    - ファイルシステムへの直接アクセス
    - コードリポジトリとの統合
    - 開発タスクに特化
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;**Claude Desktop**&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    - GUI ベースの使いやすさ
    - 会話形式のインターフェース
    - 画像認識機能
    - 一般的な質問応答に最適
  &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;しかし、MCP統合によりファイルシステムへの直接アクセス、コードリポジトリとの統合のメリットを
Claude Desktopからも享受できるようになります。Claude Desktopは月額固定料金なので、ユーザーには非常に恩恵があります。&lt;&#x2F;p&gt;
&lt;p&gt;2つ目の利点は、&lt;strong&gt;ワークフロー改善の可能性&lt;&#x2F;strong&gt;です。
Claude CodeとInkdropの統合のような仕組みは、開発者のワークフローを大幅に改善する可能性を秘めており、以下のような発展が期待できそうです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;より高度なコンテキスト理解&lt;&#x2F;strong&gt;:
&lt;ul&gt;
&lt;li&gt;コードとドキュメントの関係性をより深く理解&lt;&#x2F;li&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;&#x2F;li&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;&#x2F;li&gt;
&lt;li&gt;コードレビューとドキュメントレビューの統合&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;この統合は特に、複雑なプロジェクトやドキュメント駆動開発を実践している開発者にとって大きなメリットをもたらします。知識の管理と活用、コード生成、ドキュメント作成の一連のプロセスがシームレスに繋がることで、開発プロセス全体の質と効率が向上するでしょう。&lt;&#x2F;p&gt;
</content>
        <summary type="html">前回はInkdropとClaudeのMCP統合について紹介しましたが、今回はClaude Codeを MCPサーバーとして活用する方法とそのメリットについて解説します。 開発者にとって、Claude CodeとInkdropの組み合わせがどのように効率的な 知識管理と開発プロセスの向上につながるかを探ります。</summary>
        </entry><entry xml:lang="en">
        <title>InkdropとClaudeのMCP統合</title>
        <published>2025-03-28T00:00:00+00:00</published>
        <updated>2025-03-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/claude-integration-with-inkdrop/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/claude-integration-with-inkdrop/</id>
        
            <content type="html">&lt;p&gt;作者の方の記事「
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.devas.life&#x2F;integrating-my-note-app-with-claudes-mcp&#x2F;&quot;&gt;Integrating my note app with Claude&#x27;s MCP&lt;&#x2F;a&gt;
」と&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ou4BYmY8Dq0&amp;amp;t=116s&amp;amp;themeRefresh=1&quot;&gt;YouTube&lt;&#x2F;a&gt;
を参考にしながら、実際にmacOSで検証してみました。前提としてClaude Desktopが稼働している必要が
あります。
元記事が英語なので日本語でまとめてみました。&lt;&#x2F;p&gt;
&lt;!-- toc --&gt;
&lt;h2 id=&quot;メリットとユースケース&quot;&gt;メリットとユースケース&lt;&#x2F;h2&gt;
&lt;p&gt;実施するまえに、InkdropとClaudeが統合すると何がうれしいのでしょう？&lt;&#x2F;p&gt;
&lt;p&gt;MCP統合により、ClaudeがInkdropのノートに直接アクセスし検索・作成・更新が可能となります。
これにより、次のようなメリットがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Claudeがユーザーの書きためた複数ノートの知見を横断的に分析・活用できる&lt;&#x2F;li&gt;
&lt;li&gt;InkdropのNote管理作業を自動化し効率化できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&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;技術メモや学習ノートが蓄積されたInkdropで「JavaScriptのPromiseについて教えて」と質問すると、
Claudeはあなたの過去のノートから関連情報を抽出し、あなた自身の理解や用語に合わせた説明を提供。
さらに「これをプロジェクトXに適用するには？」と質問すると、プロジェクトXのノートも参照しながら具体的な実装アドバイスを返せる。&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;「先月の週次会議ノートを要約して月次報告として重要なアクションアイテムを抽出し、新しいノートにまとめて」と指示すると、
Claudeは該当期間の会議ノートを検索・分析し、重要ポイントとアクションアイテムを抽出した新規ノートを自動生成。
定期的なレビューや進捗管理が効率化される。&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;まず &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;inkdropapp&#x2F;mcp-server?tab=readme-ov-file&quot;&gt;Inkdrop MCP Server&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;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g @inkdropapp&#x2F;mcp-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次にInkdrop内のHTTP Serverをセットアップのために、&lt;code&gt;config.json&lt;&#x2F;code&gt;を修正します。&lt;&#x2F;p&gt;
&lt;p&gt;Macの場合は&lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;inkdrop&#x2F;&lt;&#x2F;code&gt; です。&lt;&#x2F;p&gt;
&lt;p&gt;Inkdropを修了させて、既存の設定を壊さないように次の設定を追加します。&lt;code&gt;username&lt;&#x2F;code&gt;と&lt;code&gt;password&lt;&#x2F;code&gt;の設定は例なので、ちゃんと書き換えましょう。&lt;&#x2F;p&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;*&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;core&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;server&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;enabled&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19840&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;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;bindAddress&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;127.0.0.1&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;auth&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;username&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;foo&amp;quot;&lt;&#x2F;span&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;password&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;bar&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-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;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;設定したら、Inkdropを起動し次のコマンドで確認できます。&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;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -v -u foo:bar http:&#x2F;&#x2F;localhost:19840&#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;# -&amp;gt; {&amp;quot;version&amp;quot;:&amp;quot;5.10.0&amp;quot;,&amp;quot;ok&amp;quot;:true}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;{&quot;version&quot;:&quot;5.10.0&quot;,&quot;ok&quot;:true}&lt;&#x2F;code&gt;と表示されればOKです。&lt;&#x2F;p&gt;
&lt;p&gt;次にCladue Desktopの設定が必要ですが、Claudeがどうもシェルに&lt;code&gt;bash&lt;&#x2F;code&gt;が使用されていることを前提としているため、
「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.devas.life&#x2F;integrating-my-note-app-with-claudes-mcp&#x2F;&quot;&gt;Integrating my note app with Claude&#x27;s MCP&lt;&#x2F;a&gt;」の記事通りに設定しても動作しませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;シェルの問題を回避するため、直接&lt;code&gt;npx&lt;&#x2F;code&gt;で実行するのでなく、シェルを指定したシェルスクリプトを作成しそれを実行させるように修正しました。
以下は&lt;code&gt;~&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;code&gt;などの名前で作成してください&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&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-shebang z-shell z-meta z-shebang z-shell&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env fish&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;# fish版の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;npx&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -y @inkdropapp&#x2F;mcp-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;1行目の&lt;code&gt;fish&lt;&#x2F;code&gt;の部分は自身の環境に合わせて修正してください。&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;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +x ~&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_Desktopの設定&quot;&gt;Claude Desktopの設定&lt;&#x2F;h2&gt;
&lt;p&gt;設定したInkdropのサーバーの設定をClaude Desktopに追加します。Claude Desktopの設定画面を開くと下記のようになっています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;claude-integration-with-inkdrop&amp;#x2F;setup-claude.webp?h=df5178f141a430c0eb04&quot;
  alt=&quot;Setting画面&quot; width=&quot;904&quot; height=&quot;672&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;この画面で「構成を編集」というボタンを押すと、Finderが起動して設定ファイルを示してくれます。このボタンを押さなくても、ターミナルから&lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;Claude&#x2F;claude_desktop_config.json&lt;&#x2F;code&gt;を開いて編集しても大丈夫です。&lt;&#x2F;p&gt;
&lt;p&gt;次のような設定を追加します。&lt;code&gt;command&lt;&#x2F;code&gt;の設定は先ほど作成したシェルスクリプトを絶対パスで指定します。&lt;&#x2F;p&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;inkdrop&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;&#x2F;Users&#x2F;foo&#x2F;bin&#x2F;inkdrop-mcp&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&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;env&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;INKDROP_LOCAL_SERVER_URL&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;http:&#x2F;&#x2F;localhost:19840&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_USERNAME&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;foo&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_PASSWORD&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;bar&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;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;編集後、Claude Desktopを再起動して設定画面を確認すると。&lt;code&gt;inkdrop&lt;&#x2F;code&gt;という設定が追加されているはずです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Inkdrop&#x2F;Claude統合を試してみる&quot;&gt;Inkdrop&#x2F;Claude統合を試してみる&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;MCP統合で何ができるか？&quot;&gt;MCP統合で何ができるか？&lt;&#x2F;h3&gt;
&lt;p&gt;MCP統合で何ができるかは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;inkdropapp&#x2F;mcp-server?ref=devas.life#&quot;&gt;inkdrop&#x2F;mcp-server&lt;&#x2F;a&gt;のREADME.mdを見ると何となく分かってきます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;Subheading&gt;Inkdrop MCPサーバーのComponents&lt;&#x2F;Subheading&gt;&lt;&#x2F;p&gt;
&lt;dl&gt;
  &lt;dt&gt;`read-note`&lt;&#x2F;dt&gt;
  &lt;dd&gt;Noteの参照&lt;&#x2F;dd&gt;
  &lt;dt&gt;`search-notes`&lt;&#x2F;dt&gt;
  &lt;dd&gt;キーワードでのNoteの検索&lt;&#x2F;dd&gt;
  &lt;dt&gt;`list-notes`&lt;&#x2F;dt&gt;
  &lt;dd&gt; Notebookを指定してのNoteのリスト&lt;&#x2F;dd&gt;
  &lt;dt&gt;`create-note`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;Noteの作成 &lt;&#x2F;dd&gt;
  &lt;dt&gt;`update-note`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;既存の Noteの更新 &lt;&#x2F;dd&gt;
  &lt;dt&gt;`list-notebooks`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;Notebookのリスト &lt;&#x2F;dd&gt;
  &lt;dt&gt;`list-tags`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;タグのリスト &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h3 id=&quot;実際に試してみる&quot;&gt;実際に試してみる&lt;&#x2F;h3&gt;
&lt;p&gt;この記事はInkdropでドラフトを執筆していますが、ここまで書いた時点でClaudeにInkdrop&#x2F;Claude統合の方法を聞いてみました。
敢えて英語で聞いてみました。途中MCPの使用を許可するかというダイアログが出てくるので、「このチャットで許可」を押します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;claude-integration-with-inkdrop&amp;#x2F;dialog-claude.webp?h=15d5e114b73bf62979cb&quot;
  alt=&quot;確認画面&quot; width=&quot;1112&quot; height=&quot;912&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;何度かダイアログが表示されますが、同様に許可していくと次のように表示されました。英語ですが、きちんとまとめられてます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;claude-integration-with-inkdrop&amp;#x2F;exampe-claude.webp?h=ea0bcdacaea552d3b212&quot;
  alt=&quot;結果画面&quot; width=&quot;1101&quot; height=&quot;1081&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Inkdrop内の自身のドキュメントがClaudeで活用できるのは思った以上に便利ですし、
Inkdropに知見をまとめていく行為もより価値を出せるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;プロジェクトでClaude Codeを利用すると、プロジェクト内のコードをClaude Codeが
見渡してくれるので生産性が飛躍的に向上しますが、同じことをドキュメンテーショ
ンでもInkdropとの組み合わせで実現できます。&lt;&#x2F;p&gt;
&lt;p&gt;実際この記事の「メリットとユースケース」の章はClaudeにドラフトさせて、
Inkdropに追記させたものをもとに微調整しただけです。&lt;&#x2F;p&gt;
&lt;p&gt;しかもClaude Codeはものすごい勢いでAnthoropicのAPIの課金を消費していきます
が、こちらはClaude Desktopを利用するのでProプランを使っていれば特にそれ以上
費用は必要ありません。&lt;&#x2F;p&gt;
&lt;p&gt;Claude周りは最近楽しいな。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;シェルスクリプトを作成するのでなく、Claudeでの指定で、npxをフルパスで
指定する方法もあります。お好みで。 &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">Inkdropの作者の方が、InkdropとClaudeのMCP統合についてYoutubeを上げていたので、早速検証しましたが、自分の書きためたKnowledgeをClaudeで活用できることがこんなに便利かと驚きました。</summary>
        </entry><entry xml:lang="en">
        <title>Next.jsでsitemap.xmlとrobots.txtを実装する</title>
        <published>2025-03-25T00:00:00+00:00</published>
        <updated>2025-03-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/creating-sitemap/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/creating-sitemap/</id>
        
            <content type="html">&lt;p&gt;ウェブサイトを検索エンジンに正しくインデックスしてもらうためには、&lt;code&gt;sitemap.xml&lt;&#x2F;code&gt;と&lt;code&gt;robots.txt&lt;&#x2F;code&gt;の適切な実装が不可欠です。
このブログではNext.jsのApp Routerを使用して、これらのファイルを動的に生成するよう実装しました。&lt;&#x2F;p&gt;
&lt;p&gt;この記事では、その実装方法とSEOの観点からの注意点を説明します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._sitemap.xml_実装を実装する&quot;&gt;1. sitemap.xml 実装を実装する&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1.1._sitemap.xmlとは&quot;&gt;1.1. sitemap.xmlとは&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;sitemap.xml&lt;&#x2F;code&gt;は、ウェブサイト内の各ページのURLや更新頻度、優先度などの情報をまとめたXMLファイルです。
これにより、検索エンジンのクローラーがサイト構造を理解しやすくなり、効率的なインデックス作成が可能になります。&lt;&#x2F;p&gt;
&lt;p&gt;主な要素は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;loc&amp;gt;&lt;&#x2F;code&gt; - ページのURL&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;lastmod&amp;gt;&lt;&#x2F;code&gt; - 最終更新日&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;changefreq&amp;gt;&lt;&#x2F;code&gt; - 更新頻度&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;priority&amp;gt;&lt;&#x2F;code&gt; - 重要度&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;1.2._sitemap.xml_の実装例&quot;&gt;1.2. sitemap.xml の実装例&lt;&#x2F;h3&gt;
&lt;p&gt;Next.jsのApp Routerでは、ルートハンドラーを使用して動的にsitemap.xmlを生成できます。
以下はこのブログでの実装例です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&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; src&#x2F;app&#x2F;sitemap.xml&#x2F;route.ts&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 z-storage z-modifier z-storage z-type&quot;&gt;export async function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; GET&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-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; siteUrl&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; process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;NEXT_PUBLIC_SITE_URL&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-keyword&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-variable z-other z-readwrite z-source&quot;&gt;siteUrl)&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;    throw&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Missing NEXT_PUBLIC_SITE_URL environment variable&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&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;  &#x2F;&#x2F; 記事のIDを取得する関数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getArticleIds&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-storage z-type&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; articlesDir&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; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;quot;src&#x2F;app&#x2F;articles&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; scanDir&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;dir&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-type z-primitive&quot;&gt; string&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; baseDir&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;&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-storage z-type&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; results&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-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type&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-source&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-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; entries&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; fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;readdirSync&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; withFileTypes&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-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; entries)&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-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; fullPath&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; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;name)&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-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; relativePath&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; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(baseDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;name)&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-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;isDirectory&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-variable z-other z-readwrite&quot;&gt;          results&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; [&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-other z-readwrite&quot;&gt;results&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-entity z-name z-function&quot;&gt;scanDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(fullPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; relativePath)]&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-keyword&quot;&gt; else if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&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;quot;page.mdx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;          results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;push&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(baseDir)&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;span class=&quot;z-keyword&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; results&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;&#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-entity z-name z-function&quot;&gt; scanDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(articlesDir)&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; articleIds&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; getArticleIds&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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; 最新の記事の日付を取得する関数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getLatestArticleDate&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-storage z-type&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; latestDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&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-comment z-comment&quot;&gt; &#x2F;&#x2F; 1970-01-01&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;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; articleIds)&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;      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-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; ファイルから直接コンテンツを読み込む&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxPath&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; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&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-source&quot;&gt;          process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;quot;src&#x2F;app&#x2F;articles&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-variable z-other z-readwrite&quot;&gt;          id&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;quot;page.mdx&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-source&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-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxContent&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; fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;readFileSync&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(mdxPath&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;quot;utf-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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; 日付を抽出&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; dateMatch&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; mdxContent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;match&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;date:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;+?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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 z-variable z-other z-readwrite&quot;&gt; (dateMatch)&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-storage z-type&quot;&gt;          const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dateMatch[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-comment z-comment&quot;&gt;          &#x2F;&#x2F; 有効な日付かつ最新の場合は更新&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; (&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;isNaN&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getTime&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; extractedDate&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-variable z-other z-readwrite z-source&quot;&gt; latestDate)&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-other z-readwrite&quot;&gt;            latestDate&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-other z-readwrite&quot;&gt; extractedDate&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;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (error)&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;        console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;error&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 z-definition z-string z-string&quot;&gt;          `Error processing article &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; for date extraction:`&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-other z-readwrite&quot;&gt;          error&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;        )&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ISO形式の日付を返す（例: 2025-03-25）&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; latestDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;toISOString&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;T&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&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&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;  &#x2F;&#x2F; 最新記事の日付を取得&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; latestArticleDate&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; getLatestArticleDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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; 静的ページのURL、changefreq、priority 設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; staticPages&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; [&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-source&quot;&gt;      url&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 z-definition z-string&quot;&gt; &amp;quot;&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-source&quot;&gt;      changefreq&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 z-definition z-string z-string&quot;&gt; &amp;quot;daily&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-source&quot;&gt;      priority&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 z-definition z-string z-string&quot;&gt; &amp;quot;1.0&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-source&quot;&gt;      lastmod&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-variable z-other z-readwrite&quot;&gt; latestArticleDate&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-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; ホームページ&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-source&quot;&gt; url&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 z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;about&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; changefreq&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 z-definition z-string z-string&quot;&gt; &amp;quot;monthly&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; priority&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 z-definition z-string z-string&quot;&gt; &amp;quot;0.5&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-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;      url&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 z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;articles&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-source&quot;&gt;      changefreq&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 z-definition z-string z-string&quot;&gt; &amp;quot;daily&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-source&quot;&gt;      priority&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 z-definition z-string z-string&quot;&gt; &amp;quot;0.9&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-source&quot;&gt;      lastmod&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-variable z-other z-readwrite&quot;&gt; latestArticleDate&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-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; 記事一覧ページには最新記事の日付&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-source&quot;&gt; url&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 z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;whisper&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; changefreq&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 z-definition z-string z-string&quot;&gt; &amp;quot;daily&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; priority&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 z-definition z-string z-string&quot;&gt; &amp;quot;0.4&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-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; url&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 z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;uses&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; changefreq&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 z-definition z-string z-string&quot;&gt; &amp;quot;monthly&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; priority&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 z-definition z-string z-string&quot;&gt; &amp;quot;0.7&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-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; url&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 z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;music&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; changefreq&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 z-definition z-string z-string&quot;&gt; &amp;quot;monthly&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; priority&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 z-definition z-string z-string&quot;&gt; &amp;quot;0.5&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-source&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;&#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; サイトマップXMLの作成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; sitemap&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;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;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;&amp;lt;urlset xmlns=&amp;quot;http:&#x2F;&#x2F;www.sitemaps.org&#x2F;schemas&#x2F;sitemap&#x2F;0.9&amp;quot;&amp;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&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;&#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; 静的ページをサイトマップに追加&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; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; page&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; staticPages)&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-other z-readwrite&quot;&gt;    sitemap&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;lt;url&amp;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;    &amp;lt;loc&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;loc&amp;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-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;lastmod&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;lt;lastmod&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;lastmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&amp;lt;&#x2F;lastmod&amp;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-string&quot;&gt; &amp;quot;&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-string&quot;&gt;    &amp;lt;changefreq&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;changefreq&amp;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;    &amp;lt;priority&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;priority&amp;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;  &amp;lt;&#x2F;url&amp;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&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&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;  &#x2F;&#x2F; 記事ページをサイトマップに追加&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; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; articleIds)&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;    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-punctuation z-definition z-comment z-comment&quot;&gt;      &#x2F;&#x2F; ファイルから直接コンテンツを読み込む&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxPath&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; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&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-source&quot;&gt;        process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;quot;src&#x2F;app&#x2F;articles&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-variable z-other z-readwrite&quot;&gt;        id&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;quot;page.mdx&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-source&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-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxContent&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; fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;readFileSync&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(mdxPath&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;quot;utf-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#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; 日付を抽出&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; dateMatch&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; mdxContent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;match&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;date:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;+?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-storage z-type&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;toISOString&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;T&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&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;&#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 z-variable z-other z-readwrite&quot;&gt; (dateMatch)&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-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dateMatch[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-comment z-comment&quot;&gt;        &#x2F;&#x2F; 有効な日付の場合のみ使用&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; (&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;isNaN&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getTime&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-variable z-other z-readwrite&quot;&gt;          date&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; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;toISOString&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;T&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&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&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;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; articleUrl&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; `&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;articles&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;id&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;`&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-variable z-other z-readwrite&quot;&gt;      sitemap&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;lt;url&amp;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;    &amp;lt;loc&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;articleUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;loc&amp;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;    &amp;lt;lastmod&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;lastmod&amp;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;    &amp;lt;changefreq&amp;gt;monthly&amp;lt;&#x2F;changefreq&amp;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;    &amp;lt;priority&amp;gt;1.0&amp;lt;&#x2F;priority&amp;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;  &amp;lt;&#x2F;url&amp;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&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&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (error)&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;      console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;`Error processing article &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; for sitemap:`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; error)&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; サイトマップを閉じる&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  sitemap&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;lt;&#x2F;urlset&amp;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;&#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-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(sitemap&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;    status&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-constant z-numeric&quot;&gt; 200&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;    headers&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;&#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;quot;content-type&amp;quot;&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 z-definition z-string z-string&quot;&gt; &amp;quot;application&#x2F;xml&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-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;cache-control&amp;quot;&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 z-definition z-string z-string&quot;&gt; &amp;quot;s-maxage=86400&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-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-source&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&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;ol&gt;
&lt;li&gt;&lt;strong&gt;記事の動的探索&lt;&#x2F;strong&gt;: &lt;code&gt;getArticleIds()&lt;&#x2F;code&gt;関数を使用して、articlesディレクトリ内のすべてのMDXファイルを再帰的に探索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;最新記事日付の検出&lt;&#x2F;strong&gt;: &lt;code&gt;getLatestArticleDate()&lt;&#x2F;code&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;changefreq&lt;&#x2F;code&gt;と&lt;code&gt;priority&lt;&#x2F;code&gt;の値を設定
&lt;ul&gt;
&lt;li&gt;個別記事ページ: &lt;code&gt;changefreq:monthly&lt;&#x2F;code&gt; と &lt;code&gt;priority: 1.0&lt;&#x2F;code&gt;で固定&lt;&#x2F;li&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;code&gt;lastmod&lt;&#x2F;code&gt;として使用し、これらのページが最新コンテンツを反映していることを検索エンジンに伝える&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;柔軟な構造&lt;&#x2F;strong&gt;: &lt;code&gt;page.lastmod&lt;&#x2F;code&gt;が存在する場合のみ&lt;code&gt;&amp;lt;lastmod&amp;gt;&lt;&#x2F;code&gt;タグを出力する条件付きレンダリング&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;キャッシュ設定&lt;&#x2F;strong&gt;: &lt;code&gt;cache-control&lt;&#x2F;code&gt;ヘッダーで24時間のキャッシュを設定&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;1.3._changefreq_の適切な設定&quot;&gt;1.3. changefreq の適切な設定&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;changefreq&lt;&#x2F;code&gt;値は検索エンジンへのヒントであり、実際のクロール頻度を保証するものではありません。
一般的な設定の目安。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;always&lt;&#x2F;code&gt;: 常に変化するページ（リアルタイムデータ表示など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;hourly&lt;&#x2F;code&gt;: 1時間単位で更新（ニュースページなど）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;daily&lt;&#x2F;code&gt;: 毎日更新（ブログトップ、記事一覧など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;weekly&lt;&#x2F;code&gt;: 週単位で更新（プロジェクトページなど）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;monthly&lt;&#x2F;code&gt;: 月単位で更新（Aboutページなど）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;yearly&lt;&#x2F;code&gt;: 年単位で更新（利用規約など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;never&lt;&#x2F;code&gt;: 更新されないページ（アーカイブなど）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ページの実際の更新パターンに合わせた設定が望ましいですが、最終的なクロール頻度は検索エンジンのアルゴリズムが決定します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.4._lastmod_の意義と適切な設定&quot;&gt;1.4. lastmod の意義と適切な設定&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;lastmod&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;ol&gt;
&lt;li&gt;&lt;strong&gt;個別記事&lt;&#x2F;strong&gt;: 記事のfrontmatterから日付を抽出して使用&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;p&gt;この方法により、各ページが適切な最終更新日を持ち、検索エンジンが最新のコンテンツを効率的に処理できるようになります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._robots.txt_を実装する&quot;&gt;2. robots.txt を実装する&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;robots.txt&lt;&#x2F;code&gt;はクローラーに対するルールを記述したファイルで、同様にルートハンドラーで実装できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&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; src&#x2F;app&#x2F;robots.txt&#x2F;route.ts&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-modifier z-storage z-type&quot;&gt;export async function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; GET&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-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; siteUrl&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; process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;NEXT_PUBLIC_SITE_URL&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-keyword&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-variable z-other z-readwrite z-source&quot;&gt;siteUrl)&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;    throw&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Missing NEXT_PUBLIC_SITE_URL environment variable&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&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-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; robotsTxt&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; `# https:&#x2F;&#x2F;www.robotstxt.org&#x2F;robotstxt.html&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;User-agent: *&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Allow: &#x2F;&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-string&quot;&gt;# Sitemaps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Sitemap: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;sitemap.xml&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&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;&#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-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(robotsTxt&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;    status&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-constant z-numeric&quot;&gt; 200&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;    headers&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;&#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;quot;content-type&amp;quot;&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 z-definition z-string z-string&quot;&gt; &amp;quot;text&#x2F;plain&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-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;cache-control&amp;quot;&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 z-definition z-string z-string&quot;&gt; &amp;quot;s-maxage=86400&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-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-source&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&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この実装ではすべてのロボットにサイト全体へのアクセスを許可し、sitemap.xmlの場所を明示しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2.1._robots.txt実装上の注意点&quot;&gt;2.1. robots.txt実装上の注意点&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;環境変数の設定&lt;&#x2F;strong&gt;: &lt;code&gt;NEXT_PUBLIC_SITE_URL&lt;&#x2F;code&gt;を必ず設定する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;キャッシュの検討&lt;&#x2F;strong&gt;: 頻繁に記事を追加する場合は、キャッシュ期間を短くする(個人のブログサイトなので現在の24時間で十分)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;エラーハンドリング&lt;&#x2F;strong&gt;: 記事読み込みエラーが全体に影響しないようtry-catchで処理&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;検証&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;search.google.com&#x2F;search-console&quot;&gt;Google Search Console&lt;&#x2F;a&gt;でサイトマップを登録し、エラーがないか確認する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;3._まとめ&quot;&gt;3. まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;適切な&lt;code&gt;sitemap.xml&lt;&#x2F;code&gt;と&lt;code&gt;robots.txt&lt;&#x2F;code&gt;の実装はSEOの基本です。Next.jsのApp Routerを使うと、これらのファイルを動的に生成できるため、コンテンツの増加に合わせて自動的に更新されるサイトマップを維持できます。&lt;&#x2F;p&gt;
&lt;p&gt;更新頻度や優先度の設定は、サイトのコンテンツ特性を考慮して決定しましょう。最終的には検索エンジンのアルゴリズムが実際のクロール頻度を決定しますが、適切なヒントを提供することで、より効率的なインデックス作成を促進できます。&lt;&#x2F;p&gt;
</content>
        <summary type="html">うっかり実装を忘れていたsitemap.xmlとrobots.txtをNext.jsのApp Routerを使用して実装しました。合わせて、検索エンジン最適化のためのベストプラクティスもまとめています。</summary>
        </entry><entry xml:lang="en">
        <title>ヘッドレスCMS Contentfulを活用したつぶやき機能の実装</title>
        <published>2025-03-24T00:00:00+00:00</published>
        <updated>2025-03-24T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/contentful/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/contentful/</id>
        
            <content type="html">&lt;h2 id=&quot;Contentfulとは&quot;&gt;Contentfulとは&lt;&#x2F;h2&gt;
&lt;p&gt;Contentfulは、ヘッドレスCMSのひとつで、コンテンツ管理とAPI配信に特化したサー
ビスです。ウェブサイトやアプリ向けのコンテンツを一元管理し、RESTful APIや
GraphQL APIを通じて、あらゆるデバイスやプラットフォームに配信できます。&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;www.contentful.com&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;構造化されたコンテンツモデルを定義でき、マークダウンやリッチテキストエディタを備
え、多言語対応も可能です。開発者はフロントエンドを自由に構築でき、コンテンツ
編集者は直感的なインターフェースでコンテンツを管理できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「つぶやき」機能を作ってみる&quot;&gt;「つぶやき」機能を作ってみる&lt;&#x2F;h2&gt;
&lt;p&gt;ブログにContentfulを使って「つぶやき」機能をつけてみましょう。&lt;&#x2F;p&gt;
&lt;p&gt;「つぶやき」コンテンツ自体はContentfulで管理します。
今回つぶやき投稿についてはContentfulのデフォルトのエディタを使用し、
特にコンテンツ作成用のアプリを作成しないことにします。&lt;&#x2F;p&gt;
&lt;p&gt;このブログの「つぶやき機能」ではContentfulからRESTful APIを使って読み出し、
時系列で表示するものとします。Paginationも入れましょう。&lt;&#x2F;p&gt;
&lt;p&gt;以下が実現イメージです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ContentfulでのContent_Modelの定義&quot;&gt;ContentfulでのContent Modelの定義&lt;&#x2F;h2&gt;
&lt;p&gt;ContentfulではまずSpaceを作ることになりますが、今回は無料枠を利用する予定な
ので、デフォルトのSpace &lt;code&gt;Blank&lt;&#x2F;code&gt;を使います。&lt;&#x2F;p&gt;
&lt;p&gt;次に&lt;strong&gt;Content Model&lt;&#x2F;strong&gt;を作成します。今回は &lt;code&gt;whisper&lt;&#x2F;code&gt;と名付けました。
シンプルに以下のようにしました。idは現時点では不要ですが、将来編集アプリを作
る時に備えて一応用意しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;contentful&amp;#x2F;content-model.webp?h=792dde0896adc5c8ff31&quot;
  alt=&quot;Content Model&quot; width=&quot;981&quot; height=&quot;292&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;&#x2F;th&gt;&lt;th&gt;Field ID&lt;&#x2F;th&gt;&lt;th&gt;Attribute&lt;&#x2F;th&gt;&lt;th&gt;Unique&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;id&lt;&#x2F;td&gt;&lt;td&gt;id&lt;&#x2F;td&gt;&lt;td&gt;Decimal&lt;&#x2F;td&gt;&lt;td&gt;Y&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;whisper_time&lt;&#x2F;td&gt;&lt;td&gt;whisperTime&lt;&#x2F;td&gt;&lt;td&gt;Date &amp;amp; time&lt;&#x2F;td&gt;&lt;td&gt;N&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;whisper&lt;&#x2F;td&gt;&lt;td&gt;whisper&lt;&#x2F;td&gt;&lt;td&gt;Short text&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;location&lt;&#x2F;td&gt;&lt;td&gt;location&lt;&#x2F;td&gt;&lt;td&gt;Location&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;Contentfulからのつぶやきの読み出し&quot;&gt;Contentfulからのつぶやきの読み出し&lt;&#x2F;h2&gt;
&lt;p&gt;Contentfulからのコンテンツの読み出しには、ContentfulのSDKを使用しています。&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;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; contentful&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; require&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;contentful&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; client&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; contentful&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;createClient&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;  space&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 z-definition z-string z-string&quot;&gt; &amp;quot;@@@@@@@&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-source&quot;&gt;  environment&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 z-definition z-string z-string&quot;&gt; &amp;quot;master&amp;quot;&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-comment z-comment&quot;&gt; &#x2F;&#x2F; defaults to &amp;#39;master&amp;#39; if not set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  accessToken&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 z-definition z-string z-string&quot;&gt; &amp;quot;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&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-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;  .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getEntry&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;@@@@@@@@@@@@@@@@@@@@@@@@&amp;quot;&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 z-accessor&quot;&gt;  .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;then&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&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;entry&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-function z-arrow z-ts&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(entry))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;  .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;catch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;error)&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;space&lt;&#x2F;code&gt;,
&lt;code&gt;environment&lt;&#x2F;code&gt;,&lt;code&gt;accessToken&lt;&#x2F;code&gt;などは、Amplifyのビルド設定で &lt;code&gt;.env&lt;&#x2F;code&gt;に書き込んで
環境変数から読み出しています。&lt;&#x2F;p&gt;
&lt;p&gt;Paginationについては、まず10個を上限で読み出し改ページの際にレコードの開始位置を変更して実現しています。
当初はISR &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; で実装しましたが、Contentfulとうまく連携できずWebhookでの実装も試しました。
しかし、いずれも思ったように動作しなかったりサーバーの負荷も高いため、
クライアントコンポーネントとしてクライアント側でカーソルを管理しページ制御を
実装しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Whisper実現イメージ&quot;&gt;Whisper実現イメージ&lt;&#x2F;h2&gt;
&lt;p&gt;このブログに「&lt;strong&gt;Whisper&lt;&#x2F;strong&gt;」というメニューを配置し、つぶやきを表示するように
しました。以下のようなイメージです。&lt;&#x2F;p&gt;
&lt;p&gt;Locationは緯度・軽度が記録されているので、緯度経度の表示とともに
Open Street Mapへのリンクも埋め込みました。&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;img src=&quot;whisper.webp&quot; alt=&quot;Whisper実現イメージ&quot; &#x2F;&gt;
  &lt;figcaption&gt;Whisper 実現イメージ&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回は非常に簡単な実装でしたが、Paginationの部分でAmplifyとの互換性の問題で
苦労しました。Contentfulを使うとコンテンツ管理はContentfulに任せてしまえる
ヘッドレスCMSのメリットは体感できました。&lt;&#x2F;p&gt;
&lt;p&gt;次のようなメリットがあります。&lt;&#x2F;p&gt;
&lt;ol&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;：一度作成したコンテンツをウェブ、モバイル、IoTなど複数のプラットフォームに配信可能&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;：静的サイト生成やCDN配信との相性が良く、高速なサイト表示が可能&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;将来性&lt;&#x2F;strong&gt;：新しいデバイスやプラットフォームにもフロントエンドだけ独立し
ているため柔軟に対応できる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;今回作成したWhisper機能は大した意味がありませんが、
将来的につぶやき投稿機能も別途作ろうかなと思います。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;Incremental Static Regenerationの略。増分静的再生成とも言われ、静的生
成（SSG）の拡張機能。事前にビルド済みの静的ページを提供しながら、revalidateパラメータにより再検証間隔を設定し
バックグラウンドで定期的に再生成する機能。 &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">このブログでは直接App Router配下に記事を書いていますが、ヘッドレスCMSを使うことも検討して諦めました。今回、ライトにつぶやき程度であればできそうかなとContentfulを使って実装してみました。</summary>
        </entry><entry xml:lang="en">
        <title>textlintで日本語ブログの品質を向上させよう</title>
        <published>2025-03-23T00:00:00+00:00</published>
        <updated>2025-03-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/textlint-introduction/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/textlint-introduction/</id>
        
            <content type="html">&lt;h2 id=&quot;textlintとは&quot;&gt;textlintとは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;textlint.github.io&#x2F;&quot;&gt;textlint&lt;&#x2F;a&gt;は、テキスト上の問題を洗い出すための静的解析ツールです。
特に日本語のテキスト校正において優れた機能を持っており、文章のスタイル、用語の統一、表記ゆれ、誤字脱字などをチェックできます。
Markdownファイルなどの構造化されたテキストファイルに対して適用できるため、
ブログ記事や技術文書の品質を向上させるのに最適です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜtextlintを導入したのか&quot;&gt;なぜtextlintを導入したのか&lt;&#x2F;h2&gt;
&lt;p&gt;技術ブログを書く際に直面する問題は、以下のようなものがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;「ですます調」と「である調」の混在&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;ul&gt;
&lt;p&gt;これらの問題は、読者にとって違和感を与え、プロフェッショナルさを損なう可能性があります。textlintを導入することで、これらの問題を自動的に検出し、一貫した文章スタイルを維持できるようになります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;インストールと設定&quot;&gt;インストールと設定&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1._必要なパッケージのインストール&quot;&gt;1. 必要なパッケージのインストール&lt;&#x2F;h3&gt;
&lt;p&gt;次のコマンドでtextlintと必要なルールをインストールします。&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;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install --save-dev textlint&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&quot;&gt;  textlint-rule-preset-ja-spacing&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&quot;&gt;  textlint-rule-preset-ja-technical-writing&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&quot;&gt;  textlint-rule-no-mix-dearu-desumasu&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&quot;&gt;  textlint-filter-rule-comments&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&quot;&gt;  textlint-filter-rule-node-types&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&quot;&gt;  textlint-plugin-mdx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._.textlintrcの設定&quot;&gt;2. &lt;code&gt;.textlintrc&lt;&#x2F;code&gt;の設定&lt;&#x2F;h3&gt;
&lt;p&gt;プロジェクトのルートディレクトリに&lt;code&gt;.textlintrc&lt;&#x2F;code&gt;ファイルを作成し、以下のように設定します。&lt;&#x2F;p&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;filters&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;comments&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;node-types&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;nodeTypes&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;jsx&amp;quot;&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;quot;code&amp;quot;&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;quot;inline-code&amp;quot;&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;quot;html&amp;quot;&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;quot;BlockQuote&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-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;allowlist&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;allow&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 z-definition z-string z-string&quot;&gt;        &amp;quot;&#x2F;&amp;lt;blockquote[^&amp;gt;]*&amp;gt;[&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;s&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;S]*?&amp;lt;&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 z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;&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-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;&#x2F;&amp;lt;blockquote&amp;gt;([&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;s&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;S])*?&amp;lt;&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 z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;g&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;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;plugins&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;mdx&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;rules&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;preset-ja-spacing&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;ja-nakaguro-or-halfwidth-space-between-katakana&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-around-parentheses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-between-full-width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-between-half-and-full-width&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;space&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;always&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;exceptPunctuation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-exclamation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-question&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-around-code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preset-ja-technical-writing&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;sentence-length&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;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 200&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;no-exclamation-question-mark&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;allowHalfWidthQuestion&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowFullWidthQuestion&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-weak-phrase&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;max-kanji-continuous-len&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;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&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;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-mixed-period&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;allowPeriodMarks&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;箇条書き&amp;quot;&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;quot;リスト&amp;quot;&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;quot;。&amp;quot;&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;quot;、&amp;quot;&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;quot;」&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-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;forceAppendPeriod&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;checkBlockQuote&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;checkListItem&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowExceptionContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ignorePeriodInQuotation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;no-mix-dearu-desumasu&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;preferInHeader&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;である&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInBody&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;ですます&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInList&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;である&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-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;strict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;@textlint-rule&#x2F;textlint-rule-no-invalid-control-character&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-technical-writing&#x2F;no-doubled-conjunction&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-technical-writing&#x2F;no-doubled-conjunctive-particle-ga&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;h3 id=&quot;3._package.jsonにスクリプトを追加&quot;&gt;3. package.jsonにスクリプトを追加&lt;&#x2F;h3&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;scripts&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;check&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;textlint &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;src&#x2F;app&#x2F;articles&#x2F;**&#x2F;*.mdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&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-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;h2 id=&quot;設定の詳細解説&quot;&gt;設定の詳細解説&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;フィルター&quot;&gt;フィルター&lt;&#x2F;h3&gt;
&lt;p&gt;MDXファイルには、本文の他にJSXコンポーネントやコードブロックが含まれています。
これらに対してtextlintのルールを適用すると誤検出が多発します。そのため、
フィルターを設定して特定の部分をチェック対象から除外しました。&lt;&#x2F;p&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 z-definition z-string z-string&quot;&gt;&amp;quot;filters&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;comments&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;node-types&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;nodeTypes&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;jsx&amp;quot;&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;quot;code&amp;quot;&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;quot;inline-code&amp;quot;&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;quot;html&amp;quot;&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;quot;BlockQuote&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-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;allowlist&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;allow&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 z-definition z-string z-string&quot;&gt;      &amp;quot;&#x2F;&amp;lt;blockquote[^&amp;gt;]*&amp;gt;[&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;s&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;S]*?&amp;lt;&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 z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;&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-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;&#x2F;&amp;lt;blockquote&amp;gt;([&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;s&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;S])*?&amp;lt;&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 z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;g&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;ul&gt;
&lt;li&gt;&lt;code&gt;comments&lt;&#x2F;code&gt;: コメント部分をチェック対象から除外&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;node-types&lt;&#x2F;code&gt;: JSX、コードブロック、インラインコード、HTMLタグ、引用文をチェック対象から除外&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;allowlist&lt;&#x2F;code&gt;: 正規表現で指定したパターンをチェック対象から除外&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;blockquote要素内の引用文は自分の文章でなく修正しようもないため、
対象から外しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ルール&quot;&gt;ルール&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;1._「ですます調」と「である調」の統一_(no-mix-dearu-desumasu)&quot;&gt;1. 「ですます調」と「である調」の統一 (no-mix-dearu-desumasu)&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;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;no-mix-dearu-desumasu&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInHeader&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;である&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInBody&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;ですます&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInList&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;である&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;strict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;ul&gt;
&lt;li&gt;見出しは「である調」とする&lt;&#x2F;li&gt;
&lt;li&gt;本文は「ですます調」とする&lt;&#x2F;li&gt;
&lt;li&gt;リストは「である調」とする&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;strict: false&lt;&#x2F;code&gt;で厳密すぎるチェックを回避する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;2._日本語の間隔に関するルール_(preset-ja-spacing)&quot;&gt;2. 日本語の間隔に関するルール (preset-ja-spacing)&lt;&#x2F;h4&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 z-definition z-string z-string&quot;&gt;&amp;quot;preset-ja-spacing&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-nakaguro-or-halfwidth-space-between-katakana&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-around-parentheses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-between-full-width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-between-half-and-full-width&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;space&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;always&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-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;exceptPunctuation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-exclamation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-question&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&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;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-around-code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&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;ul&gt;
&lt;li&gt;カタカナ語の間には中黒または半角スペースを入れる規則である&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;li&gt;感嘆符と疑問符の後にはスペースを入れる規則である&lt;&#x2F;li&gt;
&lt;li&gt;コードの前後のスペースは不要とする規則である&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;3._技術文書向けのルール_(preset-ja-technical-writing)&quot;&gt;3. 技術文書向けのルール (preset-ja-technical-writing)&lt;&#x2F;h4&gt;
&lt;p&gt;技術文書に適した日本語表現をチェックする包括的なルールセットです。冗長な表
現、読みにくい文章構造、一文の長さなどをチェックする。以下のような設定を追加
しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;max-kanji-continuous-len&lt;&#x2F;code&gt;: 漢字の連続使用を20文字までに制限を緩和&lt;&#x2F;li&gt;
&lt;li&gt;助詞の重複や冗長表現、不自然なアルファベット使用などを検出する機能を含む&lt;&#x2F;li&gt;
&lt;li&gt;技術文書らしい表現をチェックし、読みやすさを向上させる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;MDXファイルの対応と実行時の問題解決&quot;&gt;MDXファイルの対応と実行時の問題解決&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsのブログでは、多くの場合MDXファイルを使用しています。
デフォルトのtextlint設定ではMDXファイルを認識できないことがあります。
実際に&lt;code&gt;npm run check&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;No Process files that are un-support extensions: [&amp;quot;&#x2F;path&#x2F;to&#x2F;your&#x2F;blog&#x2F;src&#x2F;app&#x2F;articles&#x2F;...&#x2F;page.mdx&amp;quot;,...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この問題を解決するには、前述のインストール手順にあるように、&lt;code&gt;textlint-plugin-mdx&lt;&#x2F;code&gt;パッケージを追加し、&lt;code&gt;.textlintrc&lt;&#x2F;code&gt;ファイルの設定に&lt;code&gt;&quot;plugins&quot;: [&quot;mdx&quot;]&lt;&#x2F;code&gt;を追加する必要があります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;正しく設定した後の実行結果&quot;&gt;正しく設定した後の実行結果&lt;&#x2F;h3&gt;
&lt;p&gt;正しく設定した後、&lt;code&gt;npm run check&lt;&#x2F;code&gt;を実行すると、ブログ内のMDXファイルが検査され、以下のような結果が表示されます。&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;path&#x2F;to&#x2F;your&#x2F;blog&#x2F;src&#x2F;app&#x2F;articles&#x2F;...&#x2F;page.mdx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  23:138  ✓ error  原則として、全角文字と半角文字の間にスペースを入れます。                 ja-spacing&#x2F;ja-space-between-half-and-full-width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  27:32   error    文末が&amp;quot;。&amp;quot;で終わっていません。                                           ja-technical-writing&#x2F;ja-no-mixed-period&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  40:7    ✓ error  原則として、全角文字と半角文字の間にスペースを入れます。                 ja-spacing&#x2F;ja-space-between-half-and-full-width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  167:15  ✓ error  かっこの外側、内側ともにスペースを入れません。                           ja-spacing&#x2F;ja-no-space-around-parentheses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  167:41  error    箇条書き: &amp;quot;である&amp;quot;調 でなければなりません                                no-mix-dearu-desumasu&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;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npx&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; textlint --fix &amp;quot;src&#x2F;app&#x2F;articles&#x2F;**&#x2F;*.mdx&amp;quot;&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;CI&#x2F;CDパイプラインへの組み込み&quot;&gt;CI&#x2F;CDパイプラインへの組み込み&lt;&#x2F;h3&gt;
&lt;p&gt;品質チェックを自動化するために、GitHub Actionsなどのワークフローにtextlintを組み込むこともできます。例えば、以下のような&lt;code&gt;.github&#x2F;workflows&#x2F;textlint.yml&lt;&#x2F;code&gt;ファイルを作成することで、プルリクエスト時に自動的に文章をチェックできます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&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-string&quot;&gt; Textlint&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-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  pull_request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;src&#x2F;app&#x2F;articles&#x2F;**&#x2F;*.mdx&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-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  textlint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    runs-on&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-string&quot;&gt; ubuntu-latest&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-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt; uses&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-string&quot;&gt; actions&#x2F;checkout@v3&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-tag z-yaml&quot;&gt; uses&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-string&quot;&gt; actions&#x2F;setup-node@v3&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-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;          node-version&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 z-definition z-string z-string&quot;&gt; &amp;quot;20&amp;quot;&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-tag z-yaml&quot;&gt;          cache&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 z-definition z-string z-string&quot;&gt; &amp;quot;npm&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;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; run&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-string&quot;&gt; npm ci&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-tag z-yaml&quot;&gt; run&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-string&quot;&gt; npm run check&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;textlintを導入することで得られる主な効果は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&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;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;CI&#x2F;CDパイプラインとの統合&lt;&#x2F;strong&gt;: Node.jsベースのツールであるため、GitHub ActionsやJenkins、AWS CodeBuildなどのCI&#x2F;CDパイプラインに容易に組み込める&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;textlintは、日本語の技術ブログを書く際の強力な味方です。
適切な設定により、文章の品質を向上させ、読者にとって読みやすく一貫性のある記事を提供できます。特にMDXを使ったブログでは、フィルター設定により、記事本文とコードやJSXを適切に区別してチェックできます。&lt;&#x2F;p&gt;
&lt;p&gt;Next.js + Tailwind Plus(旧Tailwind UI)をベースにしたブログシステムとの相性
も抜群です。Node.jsベースのツールであるため、同じエコシステム内で簡単に導入
でき、npmスクリプトとして実行できます。さらに、GitHub ActionsなどのCI&#x2F;CD
パイプラインに組み込むことで、プルリクエスト時に自動的に文章をチェックし、品
質を担保も可能です。&lt;&#x2F;p&gt;
&lt;p&gt;今回紹介した設定は、MDXファイルを使ったNext.jsブログに最適化されていますが、他の形式の文書にも応用可能です。自分の文書スタイルや好みに合わせてカスタマイズしてみてください。&lt;&#x2F;p&gt;
&lt;p&gt;定期的に&lt;code&gt;npm run check&lt;&#x2F;code&gt;を実行し、指摘された問題を修正することで、ブログ記事の品質を着実に向上させることができます。&lt;&#x2F;p&gt;
</content>
        <summary type="html">textlintを活用して日本語の技術ブログ記事の品質を向上させる方法を紹介します。特にこのブログではMarkdownでなくMDXを使用しているので、MDXファイルに対する最適な設定と導入手順を解説します。</summary>
        </entry><entry xml:lang="en">
        <title>Authorization Bypass in Next.js Middleware</title>
        <published>2025-03-22T00:00:00+00:00</published>
        <updated>2025-03-22T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/cve-2025-29927/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/cve-2025-29927/</id>
        
            <content type="html">&lt;h2 id=&quot;CVE情報&quot;&gt;CVE情報&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;CVE番号: CVE-2025-29927&lt;&#x2F;li&gt;
&lt;li&gt;GHSAコード: GHSA-f82v-jwr5-mffw&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;攻撃者が特定のHTTPヘッダーを操作することで、ミドルウェアの認証チェックを迂回
し、保護されたリソースにアクセスできてしまう問題のようです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;アップデート手順&quot;&gt;アップデート手順&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-punctuation z-definition z-comment z-comment&quot;&gt;# Next.jsのアップデート&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 next@15.2.3 @next&#x2F;mdx@15.2.3 eslint-config-next@15.2.3&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;# npx next updateでもいいか。&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;# アップデート後問題ないか、一応Lintをかけておく&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 lint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">Next.js 15.2.3未満で認証をバイパスできる脆弱性の通知がGitHubから飛んできたので、一応このブログもアップデートしました。</summary>
        </entry><entry xml:lang="en">
        <title>エンジニア的ブログ再構築 : Next.js × Tailwind Plusで得る柔軟性</title>
        <published>2025-03-17T00:00:00+00:00</published>
        <updated>2025-03-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/nextjs-tailwindui-blog/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/nextjs-tailwindui-blog/</id>
        
            <content type="html">&lt;h2 id=&quot;Micro.blogから移行&quot;&gt;Micro.blogから移行&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.micro.blog&#x2F;&quot;&gt;Indie Microblogging&lt;&#x2F;a&gt;&quot;というコンセプトに共感し、
X.comのようなプラットフォームに依存せず
長文の記事だけでなくマイクロブログも可能なMicro.blog
を昨年から利用していました。
気軽なつぶやきと長文記事を同じプラットフォームで書けて、
Micro.blogのコミュニティーで海外のユーザーとのコミュニケーションも楽しくはありました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、半年くらい使ってみると次のような点で不満を持ちました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;長文記事とつぶやきが混在するので、読みづらい。そのためテーマをカスタマイズ
して両者を分離したくなるが、よく考えると本末転倒でないかと思い始めた。Micro.blog自体も
長文を意識したSummery欄を追加したりLongformにフォーカスしたテーマが人気だったり、
コンセプトがブレてきていると感じてしまった。&lt;&#x2F;li&gt;
&lt;li&gt;やはり、Compose画面が長文には向いておらず、エディタで編集して切り貼りすることが多
く非効率。海外ユーザーはMarsEditを使っているユーザーが多いようだが、
リッチテキストを好きになれない。&lt;&#x2F;li&gt;
&lt;li&gt;Micro.blogは独自の機能とプラグインとして提供されているテーマ、バックエンドでHugo
で構成されており、それぞれの依存からカスタマイズ時の制約が大きく独自のノウハ
ウが必要となる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;モダンな技術スタックでブログ&quot;&gt;モダンな技術スタックでブログ&lt;&#x2F;h2&gt;
&lt;p&gt;先日に遊びでNext.js + Tailwind CSSでPortfolioサイトを作りましたが、
CMSのような制約がなく、コードで部品を書いていける体験が
楽しかったのでブログも同じような技術スタックで構成することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;Next.jsベースでのブログのStarter Kitのようなものはいくつか存在しますが、
興味から有償のTailwind Plusを購入したので、Tailwind Plusが提供する個人向け
Blogの&quot;Spotlight&quot;という&lt;strong&gt;Template&lt;&#x2F;strong&gt;をベースにカスタマイズしました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;nextjs-tailwindui-blog&amp;#x2F;spotlight.webp?h=b31a6334b27994b8c48d&quot;
  alt=&quot;Tailwind Plus: Spotlight template&quot; width=&quot;1535&quot; height=&quot;232&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Tailwind PlusのTemplateは、完全に動作するReactベースのアプリケーションコード
で、Javascript版とTypeScript版が提供されており、Tailwind CSSを利用したUI要素
だけでなく状態管理やルーティング、APIとの連携など本番環境ですぐに使用でき
る機能を全て含んでいます。next-themesを利用したダークモード対応やPrismJSを
使ったSyntax Highlight、レスポンシブ対応、画像最適化やコンポーネントのプリ
ロードなどは最初から組み込まれています。開発者はこれらのテンプレートを導入す
るだけで、最小限のカスタマイズで完全な機能を持つReactアプリケーションを短時
間で構築できると謳われています。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、実際にブログで運用にはそこそこカスタマイズが必要でした。&lt;&#x2F;p&gt;
&lt;p&gt;主なカスタマイズポイントとしては以下のような点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI&#x2F;UXの改善&lt;&#x2F;strong&gt;：個人用のブログに合わせヘッダー、フッターのカスタマイズ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;記事管理システム&lt;&#x2F;strong&gt;：App Routerの構造を活かしたシンプルなMDXベースの記事管理&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;：Giscusを使用したGitHubベースのコメント機能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;通常であれば、gray-matterやremarkなどを入れてヘッドレスCMSなどからMarkdown記事を取り込み
動的ルーティングで記事を生成するのが美しいのでしょうが、
「そのままMDXで書けばいいか」と割り切ってApp Routerの下に記事を書いていくスタイルにしました。
記事の執筆とサイトのコーディングの区別がつかない今のスタイルは不便もありますが、
気に入っています。HMR&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;まだ記事の移行も終わっていませんし、元のテンプレートからそのまま未修正のもの
もありますが、ぼちぼちと修正していこうと思います。&lt;&#x2F;p&gt;
&lt;p&gt;Deploy先は、AWSの&lt;strong&gt;Amazon Amplify&lt;&#x2F;strong&gt;としました。ゆくゆくメールフォームなども作っ
ていきたいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;カスタムコンポーネントの活用&quot;&gt;カスタムコンポーネントの活用&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsとTailwind UIの大きな魅力の1つは、カスタムコンポーネントを簡単に作成
して再利用できる点です。従来のCMSであればプラグインやテンプレートの変更とな
り気軽にできませんが、今のスタイルであればTypescriptでコードを書けばすぐに利
用できます。コードなのでClaude CodeなどのAI支援も活用できます。&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;tsx&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; src&#x2F;components&#x2F;ShopInfo.tsx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; ShopInfoProps&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-object z-property&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-support z-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;  address&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;  osmAddress&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;  phone&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;  closedDays&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-type z-primitive&quot;&gt; string&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-object z-property&quot;&gt;  website&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-type z-primitive&quot;&gt; string&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; ShopInfo&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;  name&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;  address&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;  osmAddress&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;  phone&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;  closedDays&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;  website&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-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; ShopInfoProps&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; コンポーネントの実装...&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;&#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;店名&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;兵庫県 神戸市西区 学園西町1-4 キャンパススクェア&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;地図&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.openstreetmap.org&#x2F;?mlat=34.683006&amp;amp;mlon=135.057619#map=17&#x2F;34.683006&#x2F;135.057619&quot;&gt;OpenStreetMap&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;電話&lt;&#x2F;td&gt;&lt;td&gt;078-798-7613&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;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ウェブサイト&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;store.starbucks.co.jp&#x2F;detail-1718&#x2F;&quot;&gt;https:&#x2F;&#x2F;store.starbucks.co.jp&#x2F;detail-1718&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;レストランやカフェだけでなく、様々な店舗情報を表示できます。&lt;&#x2F;p&gt;
&lt;p&gt;このようなコンポーネントは、情報を構造化して表示するだけでなく、スタイリングの一貫性を保ち、コードの再利用性を高めるメリットがあります。MDXの中でReactコンポーネントをシームレスに使用できるのは、このブログシステムの大きな魅力の1つです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Micro.blogからNext.js × Tailwind Plus × Amazon Apmplify(AWS)へのブログ移行は、
モダンなWeb技術スタックを活用するという点で非常に満足のいく選択でした。&lt;&#x2F;p&gt;
&lt;p&gt;新しいプラットフォームでは、以下のようなメリットを実感しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;開発の柔軟性&lt;&#x2F;strong&gt;: フロントエンドとしてReactベースのNext.jsを使うことで、好きなようにカスタマイズできる自由度を得られた&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;執筆体験の向上&lt;&#x2F;strong&gt;: MDXを使うことで、マークダウンの手軽さとReactコンポーネントの柔軟性を両立できる&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;: 実際のプロジェクトを通じて最新のWebフロントエンド技術を深く学べる点も大きな魅力&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;もちろん、まだ改善点もあります。コンテンツの移行や検索機能の実装、SEO対策など、今後も少しずつアップデートしていく予定です。自分のペースで改良していける点が、自前のプラットフォームの最大の魅力だと感じています。&lt;&#x2F;p&gt;
&lt;p&gt;Next.jsとTailwind Plusの組み合わせは、Webアプリケーション構築だけでなく
個人ブログの構築においても非常に強力なツールセットになっていると実感しています。
興味がある方はぜひ試してみることをおすすめします。&lt;&#x2F;p&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;HMR (Hot Module Replacement)アプリケーション実行中にコードが変更された
時、ページ全体をリロードせずに変更されたモジュールのみを動的に置き換える
技術。Webpackなどのバンドラーがファイル変更を監視し、ウェブソケット接続を通じて変更部分だけをブラウザに送信するため、アプリケーションの状態を保持したまま即座に変更が反映される。 &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">Micro.blogを利用したブログを運用していましたが、Next.js + Tailwind Plus(旧Tailwind UI)を使ってエンジニアから見て柔軟なブログを再構築してみました。</summary>
        </entry><entry xml:lang="en">
        <title>Exploring Claude Code: Hands-On with Anthropic&#x27;s AI-Powered Coding Assistant</title>
        <published>2025-03-12T00:00:00+00:00</published>
        <updated>2025-03-12T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/claude-code/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/claude-code/</id>
        
            <content type="html">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&quot;&gt;Claude Code&lt;&#x2F;a&gt;を試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeは、Anthropicが開発した最新のAI駆動型コーディングアシスタントです。
コマンドラインコーディングツールで、AnthropicのサーバーにAPIを介して接続し
Claude 3.7 Sonnetモデルを活用して開発者を支援します。従って、
ブラウザからClaude 3.7 Sonnetを扱うのと同等の高度なAI推論の支援を受けることができます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Getting_Started_With_Claude_Code&quot;&gt;Getting Started With Claude Code&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを使う前提がいくつかあります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude Codeはまだβ版でResearch Previewのため、
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&quot;&gt;Claude Codeのページ&lt;&#x2F;a&gt;からβ版参加のWaiting Listの登録して、アクセ
ス許可をもらう必要があ。&lt;&#x2F;li&gt;
&lt;li&gt;Node.js 18以上が必要。以下のソフトウェアはオプション。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;git 2.23+&lt;&#x2F;li&gt;
&lt;li&gt;GitHub or GitLab CLI for PR workflows&lt;&#x2F;li&gt;
&lt;li&gt;ripgrep&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;supported-countries&quot;&gt;Supported Countries&lt;&#x2F;a&gt;に居
る必要。日本は対象となっているので大丈夫。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;もちろん、ターミナルから使うものなので、MacであればiTerm2などがあったほうが
よいでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;上記がクリアできたら、Claude Codeを認証して使用するために、AnthropicからAPI
キーを生成して払い出しておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeのインストールは以下のコマンドで行います。&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;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g @anthropic&#x2F;claude-code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;インストールが完了したら、次のコマンドでClaude Codeを起動して、初回だけOAuth
認証を完了させておきます。&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;claude&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;What_Claude_Code_Can_Do_For_You?&quot;&gt;What Claude Code Can Do For You?&lt;&#x2F;h2&gt;
&lt;p&gt;見てもらったほうが早いので、下に操作した例を貼り付けておきます。
適当に作った&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;yostos-portfolio&quot;&gt;Webサイトのリポジトリ
&lt;&#x2F;a&gt;について、分析したのに
&lt;code&gt;README.md&lt;&#x2F;code&gt;の更新を依頼してみました。引用ブロック担っている部分が私の指示したものです。&lt;&#x2F;p&gt;
&lt;p&gt;単純なWebサイトですが、Next.jsを使いそこそこコードの量もありましたが、
数秒で私が適当に書いていた&lt;code&gt;README.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-text&quot;&gt;╭──────────────────────────────────────────────────────────────╮&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ ✻ Welcome to Claude Code research preview! │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-text&quot;&gt;│ &#x2F;help for help │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-text&quot;&gt;│ cwd: &#x2F;Users&#x2F;yostos&#x2F;ghq&#x2F;github.com&#x2F;yostos&#x2F;yostos-portfolio │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Tips for getting started:&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;1.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;  Run &#x2F;init to create a CLAUDE.md file with instructions for 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-list z-begin z-markdown&quot;&gt;2.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;  Ask Claude questions about your codebase.&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;3.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;  Ask Claude to implement changes to your codebase.&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-quote z-begin z-markup z-quote&quot;&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 class=&quot;z-text&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-text&quot;&gt;⏺ Task(Please analyze this project to understand its purpose and overview. Check the following:…)…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⎿  Done (6 tool uses · 14.6k tokens · 22.1s)&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-text&quot;&gt;⏺ これは Next.js で構築された個人ポートフォリオサイトです。ウェブ技術とデザイン手法をテストするための練習プロジェ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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;&#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; Next.js と TypeScript を使用&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; Tailwind CSS とdaisyUI でスタイリング&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; Three.js と React Three Fiber による3D要素&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; Framer Motion によるアニメーション&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; AWS サービス（SES、Amplify）をバックエンド機能に使用&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-text&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; 3D要素、サービス、ニュース、作品を含むホームページ&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; About ページ&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;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; ニュース&#x2F;ブログセクション&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-quote z-begin z-markup z-quote&quot;&gt;&amp;gt; では、README.mdは内容を正しく書き示しているでしょうか？もし齟齬があればアップデートしてください。&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-text&quot;&gt;⏺ README.mdの内容を確認します。&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-text&quot;&gt;⏺ Read(file_path: &amp;quot;README.md&amp;quot;)…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  ⎿  # Porfolio Site with Next.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;個人でWeb技術とデザイン手法の検証を目的として 片手間で作った練習用ポートフォリオです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;... (+27 lines)&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-text&quot;&gt;⏺ Task(Compare the actual project features and technologies with what&amp;#39;s listed in the README.md. The README seems minimal …&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;and might be missing some technologies used in the project. …)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⎿  Done (6 tool uses · 18k tokens · 30.4s)&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-text&quot;&gt;⏺ READMEには更新が必要です。現在のREADMEは非常にシンプルで、プロジェクトで使われている多くの技術が記載されていませ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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;&#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;1.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; タイトルのタイプミス（&amp;quot;Porfolio&amp;quot; → &amp;quot;Portfolio&amp;quot;）&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;2.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 使用技術の詳細リスト（Three.js、Framer Motion、AWS services等が未記載）&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;3.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; プロジェクト機能の説明（3D要素、ポートフォリオ表示、問い合わせフォーム等）&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-text&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-quote z-begin z-markup z-quote&quot;&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 class=&quot;z-text&quot;&gt;⏺ READMEを日本語で更新します。&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-text&quot;&gt;⏺ Update(file_path: README.md)…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⎿ Updated README.md with 54 additions and 14 removals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;1 # Porfolio Site with Next.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;1 # ポートフォリオサイト with Next.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;3 個人でWeb技術とデザイン手法の検証を目的として 片手間で作った練習用ポートフォリオです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;3 個人でWeb技術とデザイン手法の検証を目的として片手間で作った練習用ポートフォリオです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;5 以下を使用しています。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;5 ## 使用技術&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;7 - &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;[Next.js]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&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-text&quot;&gt;8 - &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;[Tailwind CSS]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;tailwindcss.com&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-text&quot;&gt;9 - &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;[daisyUI]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;daisyui.com&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-text&quot;&gt;7 本プロジェクトでは以下の技術を使用しています。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;9 ## Getting Started&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;9 ### フロントエンド&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;10 - &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;[Next.js]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Reactフレームワーク（サーバーサイドレンダリングとルーティング）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;11 - &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;[React]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;reactjs.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - ユーザーインターフェース構築のためのJavaScriptライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;12 - &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;[TypeScript]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;www.typescriptlang.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;13 - &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;[Tailwind CSS]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;tailwindcss.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - ユーティリティファーストのCSSフレームワーク&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;14 - &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;[daisyUI]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;daisyui.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Tailwind CSS用コンポーネントライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;15 - &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;[Three.js]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;threejs.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - WebGL用3Dグラフィックスライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;16 - &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;[React Three Fiber]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;pmndrs&#x2F;react-three-fiber&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Three.js用Reactレンダラー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;17 - &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;[React Three Drei]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;pmndrs&#x2F;drei&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - React Three Fiber用ヘルパー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;18 - &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;[Framer Motion]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;www.framer.com&#x2F;motion&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - React用アニメーションライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;19&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;20 First, run the development server:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;20 ### バックエンド&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;21 - &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;[AWS SES]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;aws.amazon.com&#x2F;ses&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;22 - &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;[AWS Amplify]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;aws.amazon.com&#x2F;amplify&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;Webおよびモバイルアプリケーションのためのプラットフォーム&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;23&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;24 ### UI&#x2F;UX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;25 - &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;[FontAwesome]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;fontawesome.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;26 - &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;[M PLUS 1 Code]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;fonts.google.com&#x2F;specimen&#x2F;M+PLUS+1+Code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;27&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;28 ## 機能&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;29&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;30 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;3Dインタラクティブ要素&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Three.jsとReact Three Fiberを用いたインタラクティブな3Dキューブ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;31 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;レスポンシブデザイン&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;32 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;ポートフォリオショーケース&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;33 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;問い合わせフォーム&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - AWS SESを統合した直接コミュニケーション用フォーム&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;34 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;ダーク&#x2F;ライトモード&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;35 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;音楽プレーヤー&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - 音楽ショーケース用SoundCloud統合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;36&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;37 ## 始め方&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;38&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;39 まず、開発サーバーを実行します:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;40&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;41 `bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     42  npm run dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     43  # or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     43  # または&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     44  yarn dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     45  # or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     45  # または&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     46  pnpm dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     47  # or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     47  # または&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     48  bun dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     49  `&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;50&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;51 Open &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;[http:&#x2F;&#x2F;localhost:3000]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;http:&#x2F;&#x2F;localhost:3000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; with your browser to see the result.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;51 ブラウザで &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;[http:&#x2F;&#x2F;localhost:3000]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;http:&#x2F;&#x2F;localhost:3000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&quot;&gt;52&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;53 You can start editing the page by modifying &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`app&#x2F;page.tsx`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;. The page auto-updates as you edit the file.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;53 &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`app&#x2F;page.tsx`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-text&quot;&gt;54&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;55 This project uses &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`next&#x2F;font`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&#x2F;docs&#x2F;app&#x2F;building-your-application&#x2F;optimizing&#x2F;fonts&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-text&quot;&gt;to automatically optimize and load &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;[Geist]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;vercel.com&#x2F;font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;, a new font family for Vercel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;55 ## 環境変数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;56&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;57 問い合わせフォーム機能を使用するには、以下のAWS環境変数を設定する必要があります:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;58&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;59 `      60  AWS_ACCESS_KEY_ID=あなたのAWSアクセスキー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     61  AWS_SECRET_ACCESS_KEY=あなたのAWSシークレットキー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     62  SES_REGION=あなたのAWSリージョン (デフォルト: ap-northeast-1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     63  SES_FROM_EMAIL=送信者メールアドレス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     64  SES_TO_EMAIL=受信者メールアドレス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     65  `&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;66&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;67 ## その他&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;68&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;69 このプロジェクトでは&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-link z-title&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`next&#x2F;font`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&#x2F;docs&#x2F;app&#x2F;building-your-application&#x2F;optimizing&#x2F;fonts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&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-text&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-text&quot;&gt;⏺ README.mdを日本語に完全更新しました。以下の内容を追加・修正しました：&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;1.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; タイトルを「ポートフォリオサイト with Next.js」に修正&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;2.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 詳細な技術スタックをフロントエンド、バックエンド、UI&#x2F;UXの3セクションに分けて記載&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;3.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; プロジェクトの主要機能（3D要素、レスポンシブデザイン、ポートフォリオ機能など）を追加&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;4.&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;5.&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;これでREADMEは実際のプロジェクトの機能と技術をより正確に反映しています。&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-text&quot;&gt;╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ &amp;gt; quit │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&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-text&quot;&gt;! for bash mode · &#x2F; for commands · esc to undo ✓ Update installed · Restart to apply&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;今回はAnthropicが開発したAI駆動型コーディングアシスタント「Claude Code」を試
してみました。まだResearch Previewの段階ですが、その能力は非常に印象的です。
コマンドラインから簡単に使用でき、コードベースの分析や更新を数秒で行うことが
できます。&lt;&#x2F;p&gt;
&lt;p&gt;実際の使用例として示したように、プロジェクトの概要を理解し、READMEの更新を行
う作業も正確かつ迅速に実行してくれました。Claude 3.7 Sonnetモデルの高度な推
論能力をコマンドラインから活用できることで、開発ワークフローが大幅に効率化さ
れる可能性を感じました。&lt;&#x2F;p&gt;
&lt;p&gt;AI駆動型の開発支援ツールはますます進化しており、Claude Codeはその最前線にあ
るツールの1つと言えるでしょう。今後の正式リリースや機能拡張に期待したいと思
います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">I tried Claude Code.Claude Code is the latest AI-driven coding assistant developed by Anthropic.It&#x27;s a command-line coding tool that connects to Anthropic&#x27;s servers via API andutilizes the Claude 3.7 Sonnet model to support developers. Therefore,you can receive the same level of advanced AI reasoning support as when using Claude 3.7 Sonnet from a browser.</summary>
        </entry><entry xml:lang="en">
        <title>ウェブデザイン技能検定は必要か？ - 技術変化の時代の資格価値</title>
        <published>2025-03-09T00:00:00+00:00</published>
        <updated>2025-03-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/web-design/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/web-design/</id>
        
            <content type="html">&lt;p&gt;少しだけ通ったVY訓練校では、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sikaku.gr.jp&#x2F;web&#x2F;wc&#x2F;&quot;&gt;Webクリエイター能力認定試験&lt;&#x2F;a&gt;が取得できそうことを言っていました。内容見ると、メモ帳でHTMLを書かすようなアホな試験でした。
何かで有利に働くこともなさそうです。受験者数は多そうですが、一体何を目指しているんでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;気になってWEBデザイン関連の認定資格を調べていたら、「&lt;strong&gt;ウェブデザイン技能検定&lt;&#x2F;strong&gt;」という国家検定があるのに気付きました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;資格試験の現状と基本構造&quot;&gt;資格試験の現状と基本構造&lt;&#x2F;h2&gt;
&lt;p&gt;ウェブデザイン技能検定は、厚生労働省が認定する国家検定制度として2008年に創設されています。
運営は厚生労働大臣指定試験機関である特定非営利活動法人&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.netskill.jp&#x2F;&quot;&gt;インターネットスキル認定普及協会&lt;&#x2F;a&gt;が行っています。
この検定は職業能力開発促進法に基づく技能検定の1つであり、Webデザインにおけ
る実務的な技能を公的に証明するものです。1級から3級までのレベル別に実施さ
れています。&lt;&#x2F;p&gt;
&lt;p&gt;ウェブデザイン技能検定1級では、HTML5、CSS3、JavaScript等のコーディング技術に加え、情報設計、ユーザビリティ、アクセシビリティなどの幅広い知識が問われます。Webサイト全体の設計や企画、ディレクション能力も評価対象です。出題形式は選択問題、記述問題、実技課題があります。&lt;&#x2F;p&gt;
&lt;p&gt;特定非営利活動法人インターネットスキル認定普及協会が公開している&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.webdesign.gr.jp&#x2F;pass&#x2F;&quot;&gt;取得者数&lt;&#x2F;a&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;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;2019年度&lt;&#x2F;td&gt;&lt;td&gt;51人&lt;&#x2F;td&gt;&lt;td&gt;12人&lt;&#x2F;td&gt;&lt;td&gt;23.5%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2020年度&lt;&#x2F;td&gt;&lt;td&gt;46人&lt;&#x2F;td&gt;&lt;td&gt;8人&lt;&#x2F;td&gt;&lt;td&gt;17.4%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2021年度&lt;&#x2F;td&gt;&lt;td&gt;51人&lt;&#x2F;td&gt;&lt;td&gt;9人&lt;&#x2F;td&gt;&lt;td&gt;17.6%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2022年度&lt;&#x2F;td&gt;&lt;td&gt;61人&lt;&#x2F;td&gt;&lt;td&gt;3人&lt;&#x2F;td&gt;&lt;td&gt;4.9%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2023年度&lt;&#x2F;td&gt;&lt;td&gt;63人&lt;&#x2F;td&gt;&lt;td&gt;9人&lt;&#x2F;td&gt;&lt;td&gt;14.3%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;1級になるとなかなかの難関です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;技術的乖離_-_古い技術標準&quot;&gt;技術的乖離 - 古い技術標準&lt;&#x2F;h2&gt;
&lt;p&gt;技能検定の内容や対策本などから検定で求められている技術やスキルを確認してみました。&lt;&#x2F;p&gt;
&lt;p&gt;内容を見る限り、最新の技術スタックに追いついておらず、一昔前の技術標準にとどまっているようです。&lt;&#x2F;p&gt;
&lt;p&gt;例えばJavaScriptについては、ES6(ECMAScript 2015)以降の最新機能への対応が限定的であり、
主にES5レベルの機能に基づいていると推測されます。
出題傾向を見る限り、アロー関数、Promise、async&#x2F;await、モジュールシステムなど、現代のJavaScript開発において標準となっている多くの機能が試験範囲外となっているのかなと思います。
公式資料では明確なバージョン指定はありませんが、基本的なDOM操作やコールバックパターンが中心となっており、2015年以降に標準化された現代的な実装手法との間に大きなギャップが生じています。&lt;&#x2F;p&gt;
&lt;p&gt;現在のウェブ開発現場ではReact、Vue、Angularなどのフレームワークが標準的に使用されていますが、技能検定ではこれらモダンフレームワークについては全く扱っていないようです。また、現代のウェブ開発においてnpm、Webpack、Vite等のビルドツール、Gitなどのバージョン管理システム、CIパイプラインなどは標準的な環境では必須ですが、技能検定にはほとんど言及がなく、従来型の静的なファイル編集アプローチに留まっている可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;WEBデザイナーがフロントエンドエンジニアと呼ばれる現状において、モダンフレームワークやモダンなツールチェーンを知らず従来型のJavaScriptとjQueryの知識のみでは就職市場での競争力の足しになりそうな気がしません。コンポーネント指向開発の概念や状態管理といった現代的なアプローチが試験に含まれていないことも、実務との乖離を深めているように思います。
モダンな開発ワークフローへの理解がないまま現場に出てしまっては、実務での大きな壁となりそうです。&lt;&#x2F;p&gt;
&lt;p&gt;イメージ的は2000年代によく見かけたHTML&#x2F;CSS&#x2F;Javascriptが書けてPHP(今どき
PHP)もちょっと書ける「Webデザイナー」でしょうか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;グローバル標準との比較&quot;&gt;グローバル標準との比較&lt;&#x2F;h2&gt;
&lt;p&gt;他の国の同じような認定制度と比較してみました。&lt;&#x2F;p&gt;
&lt;p&gt;米国では、ウェブデザイン技能検定と似たような認定制度は以下のようなものでしょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;W3Schools Certified Web Developer&#x2F;Designer&lt;&#x2F;strong&gt; - HTML, CSS, JavaScriptなど基本的なウェブ技術の知識を証明する国際的なオンライン認定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;freeCodeCamp Certifications&lt;&#x2F;strong&gt; - 無料だが業界で認知度が高まっているウェブ開発認定プログラム&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CIW (Certified Internet Web Professional)&lt;&#x2F;strong&gt; - ウェブデザインおよび開発に関する体系的な国際認定制度&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;W3SchoolsとCIWは比較的伝統的なウェブ技術に焦点を当てており、ウェブデザイ
ン技能検定と近いかもしれません。freeCodeCampは現代的な技術スタックをカバー
しているようです。&lt;&#x2F;p&gt;
&lt;p&gt;いずれも米国市場ではデザイナーのキャリアとしては、ほとんど評価されず意味がありません。
これらの認定に時間をかけるならAWSやGoogleなどの認定資格のほうが市場価値はあり、
給与へ直接インパクトがあります。&lt;&#x2F;p&gt;
&lt;p&gt;海外の採用市場では、特定のフレームワーク（React、Angular、Vue.js）
の実践的経験や、AWS&#x2F;Google Cloud等のクラウドサービスの知識が重視されます。
国際的な企業の採用基準では、現場で使われているツールや技術への適応能力が最優先される傾
向にあります。
実務から乖離した資格よりも、実務で実践したポートフォリオや有力なプラットフォームの知識が評価されます。&lt;&#x2F;p&gt;
&lt;p&gt;特にAWS&#x2F;Google&#x2F;Azureの認定などは技術の変化に伴い、認定内容自体も常に更新されており、認定も2年程度の有効期間があり、再認定が必要なため、継続的に最新の技術にキャッチアップし学習が必要です。だからこそ、評価されているのでしょう。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;ウェブデザイン技能検定は学科と実技合わせると32,000円もの費用が検定に必要です。&lt;&#x2F;p&gt;
&lt;p&gt;検定の難度と、業界で求められるスキルの証明にならなさそうなことを考えると、
取得する価値はあまりなさそうです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">最近気になってWEBデザイン関連の認定資格を調べていたら、「ウェブデザイン技能検定」という国家検定があるのに気付きました。折角なので、深掘りして調べてみました。</summary>
        </entry><entry xml:lang="en">
        <title>エンジニアのためのポートフォリオサイトの構築</title>
        <published>2025-03-08T00:00:00+00:00</published>
        <updated>2025-03-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/portfolio-site-for-engieer/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/portfolio-site-for-engieer/</id>
        
            <content type="html">&lt;p&gt;今更ながら年初からWebデザインを教わるというシーンがありました。
しかし、毎朝タイピング練習で始まり、
「BRタグは非奨励」などとW3Cの仕様を知らないレベルの講師が
レベルの低い授業をやっていました。
100年かけてもWebデザインに行きつきそうにない。吐き気がしました。
割り切って我慢できるレベルを超えていました。&lt;&#x2F;p&gt;
&lt;p&gt;辞めましたが、
まぁ折角なのでWEBデザイナーが作るらしい「ポートフォリオ」なるものを、
3日ほど使ってこれまで深くやってこなかった技術スタックを作ってみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;ポートフォリオサイトは自分のスキルや実績を効果的にアピールするための重要な
ツールらしいです。&lt;&#x2F;p&gt;
&lt;p&gt;Illustratorでデザインカンプ描いて、HTML&#x2F;CSSでせっせとコーディング
なんてサイト作っても一体誰が見るんでしょう。
「あぁ、いいデザインだね」とか褒められると
本気で思っているバカがいるのでしょうか？
美的デザインだけで勝負するなんて、よほどの審美眼とセンスがないと無駄です。&lt;&#x2F;p&gt;
&lt;p&gt;この記事では、そんな90年代風なWebサイトでなく、
Node.js上でモダンなWebフレームワークであるNext.js&#x2F;ReactとCSSフレームワークのTailwindCSS、
そしてUIコンポーネントを提供するdaisyUIを組み合わせて
ポートフォリオサイトを構築したのでそれを記録しています。&lt;&#x2F;p&gt;
&lt;p&gt;そして、結局このブログサイトも同じような技術スタック使って
再構築してしまいました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;使用する技術スタック&quot;&gt;使用する技術スタック&lt;&#x2F;h2&gt;
&lt;p&gt;言語は型安全なTypeScriptを使用し、node&#x2F;Reactベースで以下のようなフレームワークを使っています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js&lt;&#x2F;strong&gt;: Reactベースのフルスタックフレームワーク&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;TailwindCSS&lt;&#x2F;strong&gt;: ユーティリティファーストのCSSフレームワーク&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;daisyUI&lt;&#x2F;strong&gt;: TailwindCSSのプラグインであるUIコンポーネントライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;React Three Fiber&lt;&#x2F;strong&gt;: 3DグラフィックスをReactで簡単に使うためのライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Font Awesome&lt;&#x2F;strong&gt;: グラフィカルなアイコン文字を使うためのライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Framer Motion&lt;&#x2F;strong&gt;: Framer Motionは、Reactアプリケーションにアニメーションを実装するためのライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AWS SDK&lt;&#x2F;strong&gt;: 問い合わせフォームからAWSのAmanzon SESを使ってメールを送信するため&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;プロジェクトセットアップ&quot;&gt;プロジェクトセットアップ&lt;&#x2F;h2&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-punctuation z-definition z-comment z-comment&quot;&gt;# Next.jsプロジェクトの作成（TypeScript対応）&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;npx&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; create-next-app@latest my-portfolio --typescript&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; Would you like to use ESLint? ... Yes&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; Would you like to use Tailwind CSS? ... Yes&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; Would you like to use&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-evaluation z-backticks z-shell&quot;&gt; `&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;src&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-evaluation z-backticks z-shell&quot;&gt;`&lt;&#x2F;span&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; ... Yes（好みに応じて）&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; Would you like to use App Router? ... Yes&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; Would you like to customize the default import alias&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (@&#x2F;*)&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; ... Yes&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; What import alias would you like configured? ... @&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&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;# 作成したプロジェクトディレクトリに移動&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; my-portfolio&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;# daisyUIのインストール&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 daisyui&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;tailwind.config.jsの設定&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;プロジェクトルートにある&lt;code&gt;tailwind.config.js&lt;&#x2F;code&gt;ファイルを開き、daisyUIをプラグインとして追加します。&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;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;**&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;type&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-type&quot;&gt;import(&amp;#39;tailwindcss&amp;#39;).Config&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-comment&quot;&gt; *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-object z-module z-js&quot;&gt;module&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-object z-module z-js&quot;&gt;exports&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;  content&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; [&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;quot;.&#x2F;src&#x2F;pages&#x2F;**&#x2F;*.{js,ts,jsx,tsx,mdx}&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-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;.&#x2F;src&#x2F;components&#x2F;**&#x2F;*.{js,ts,jsx,tsx,mdx}&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-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;.&#x2F;src&#x2F;app&#x2F;**&#x2F;*.{js,ts,jsx,tsx,mdx}&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-source&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;  theme&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    extend&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;&#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; 必要に応じてテーマの拡張を追加&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-source&quot;&gt;  plugins&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; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;require&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;daisyui&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;  daisyui&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    themes&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; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;light&amp;quot;&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;quot;dark&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-comment z-comment&quot;&gt; &#x2F;&#x2F; 使用するテーマを設定&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;ol start=&quot;3&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; install three @react-three&#x2F;fiber @react-three&#x2F;drei&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 framer-motion&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 @fortawesome&#x2F;fontawesome-svg-core&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&quot;&gt;            @fortawesome&#x2F;free-solid-svg-icons&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&quot;&gt;            @fortawesome&#x2F;free-regular-svg-icons&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&quot;&gt;            @fortawesome&#x2F;free-brands-svg-icons&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&quot;&gt;            @fortawesome&#x2F;react-fontawesome&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 aws-amplify @aws-sdk&#x2F;client-ses @aws-sdk&#x2F;client-sts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;turbooackの有効化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Next.jsの開発サーバーを高速化するために、package.jsonのscriptsセクションを編集してturbopackを有効にします。&lt;&#x2F;p&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 z-definition z-string z-string&quot;&gt;&amp;quot;scripts&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;dev&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;next dev --turbopack&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;build&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;next build&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;start&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;next start&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-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;lint&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;next lint&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;プロジェクトの構造&quot;&gt;プロジェクトの構造&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsのAppRouterを使用した基本的なプロジェクト構造を整えると、次のようなフォルダ構成になるはずです。&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;my-portfolio&#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;│   ├── app&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── about&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │   └── page.tsx （自己紹介ページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── api&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │   └── contact&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │       └── route.ts （メール送信）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── contact&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │   └── page.tsx （お問い合わせページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── globals.css （グローバルスタイル）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── layout.tsx （ルートレイアウト）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── page.tsx （トップページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   └── works&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │       └── page.tsx （作品紹介ページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── components&#x2F; （共通コンポーネント）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── public&#x2F; （静的ファイル）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── next.config.js&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;├── tailwind.config.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── tsconfig.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AWS_Amplify_へのデプロイ&quot;&gt;AWS Amplify へのデプロイ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はNext.jsアプリケーションのホスティング先としてVercelではなく、AWS Amplifyを選択しました。Amplifyを選んだ理由と、デプロイプロセスについて共有します。&lt;&#x2F;p&gt;
&lt;p&gt;Amplifyを選んだ理由は、次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWSエコシステムとの統合&lt;&#x2F;strong&gt;: Amazon SESなど他のAWSサービスとの連携がシーム
レスで、同じAWSコンソールから管理できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;既存のAWS知識の活用&lt;&#x2F;strong&gt;: Amplify自体は今回初見だが一応前職なので管理コンソールなどは慣れており、
Vercelを新たに学ぶ手間が不要だった。&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;ol&gt;
&lt;li&gt;AWS管理コンソールからAmplifyサービスにアクセス&lt;&#x2F;li&gt;
&lt;li&gt;「新しいアプリを作成」→「GitHubからホスティング」を選択&lt;&#x2F;li&gt;
&lt;li&gt;リポジトリと使用するブランチを選択（今回は&lt;code&gt;main&lt;&#x2F;code&gt;ブランチ）&lt;&#x2F;li&gt;
&lt;li&gt;ビルド設定を確認（Next.jsの場合は自動的に検出される）。認証情報などは面
倒なので以下のようにビルドステップに組み込んだ。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;version&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-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-entity z-name z-tag z-yaml&quot;&gt;frontend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;  phases&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    preBuild&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-string&quot;&gt; npm ci&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;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-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo &amp;quot;NEXT_PUBLIC_XXXX_API_URL=https:&#x2F;&#x2F;api.example.com&amp;quot; &amp;gt;&amp;gt;.env&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;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo &amp;quot;AWS_XXXXX_ACCESS_KEY_ID=&amp;quot;hogehogetaratara&amp;quot; &amp;gt;&amp;gt; .env&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-tag z-yaml&quot;&gt;    build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-string&quot;&gt; npm run build&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-tag z-yaml&quot;&gt;  artifacts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    baseDirectory&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-string&quot;&gt; .next&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-tag z-yaml&quot;&gt;    files&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;**&#x2F;*&amp;quot;&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-tag z-yaml&quot;&gt;  cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-tag z-yaml&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&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-string&quot;&gt; node_modules&#x2F;**&#x2F;*&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;ul&gt;
&lt;li&gt;ヘッダー・コンポーネントについてはdaisyUIのNavbarを使わず、レスポンシブ対応、メニューの開閉に対応している。Navbarを使わない理由はないと思われるが、今回は実装検証のため自身で対応してみた。&lt;&#x2F;li&gt;
&lt;li&gt;Works(作品)コンポーネントについては、トップページと作品ページで共用するため、作品情報をコンポーネントに内包させ引数で表示する作品の数を制御している。&lt;&#x2F;li&gt;
&lt;li&gt;一方でニュースのリストを作成するNewsコンポーネントは、現時点ではTopページしか使っていないが他のページでも使いまわせると考え、ニュース自体はコンポーネントに引数で渡すようにしている。&lt;&#x2F;li&gt;
&lt;li&gt;グラフィカルな要素があまりないので3Dの立方体をトップページに置いている。3DCubeコンポーネントはモデリングする手間が面倒で、立方体をくるくる回しているだけである。&lt;&#x2F;li&gt;
&lt;li&gt;問い合わせフォームは、自身で検証したかったのでAmazon SESを使って実際にフォームをメールで飛ばすところまで作り込んでいる。必要な宛先アドレスや認証情報は、ビルド時に設定して環境変数で受け渡している。認証情報はシークレット情報経由などの方が良いと思われるが、どうもうまくいかなかったので妥協した。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;具体的なソースは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;yostos-portfolio&quot;&gt;GitHubで公開&lt;&#x2F;a&gt;しています。なお、ポートフォリオサイト自体は運用コスト等の都合で既に公開を終了しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回初めてまともにNext.jsを使いました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;今回はインターラクティブな要素もあったのでSEO的には良くないと思われるが、SSR&#x2F;SSGを使わず全てクライアントコンポーネントとした。&lt;&#x2F;li&gt;
&lt;li&gt;ファイルベースのルーティングは直感的で分かりやすいと感じた。&lt;&#x2F;li&gt;
&lt;li&gt;APIルートでバックエンドの開発も同じプロジェクトでできるので、開発を分離することなくスムーズで行うことが出来そうである。フルスタックの開発者である前提ではあるが。&lt;&#x2F;li&gt;
&lt;li&gt;今回はVercelでなく、GitHubと連携させてAWSのAmplifyにデプロイした。思いの外スムーズにデプロイできた。&lt;&#x2F;li&gt;
&lt;li&gt;CMSのようにテンプレートベースでなく、コードベースで部品の再利用、共通化ができるので、プログラマーがサイトを作るには非常にCMS特有のテンプレートのお手前を覚える必要がないので生産性がよい感じである。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;楽しいお遊びでした。&lt;&#x2F;p&gt;
</content>
        <summary type="html">あまり経験してこなかった技術スタックでポートフォリオサイトを作ってみました</summary>
        </entry><entry xml:lang="en">
        <title>How to Configure Tinylytics Analytics for Production Environment Only</title>
        <published>2025-02-25T00:00:00+00:00</published>
        <updated>2025-02-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/02/houw-to-configure-tinylytics-analytics/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/02/houw-to-configure-tinylytics-analytics/</id>
        
            <content type="html">&lt;h2 id=&quot;Why_is_this_code_needed?&quot;&gt;Why is this code needed?&lt;&#x2F;h2&gt;
&lt;p&gt;When incorporating tinylytics javascript, accesses during development are also reflected in the statistics, so we added code so that statistics are obtained only in production. There may be a better way to do this, but for now, I&#x27;ll introduce it here because it does what I want to do.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;How_this_code_works&quot;&gt;How this code works&lt;&#x2F;h2&gt;
&lt;p&gt;This code works as follows:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;When the page loads, JavaScript checks the current hostname (domain)&lt;&#x2F;li&gt;
&lt;li&gt;Only if the hostname exactly matches &quot;your.domain.com&quot;, it will add the tinylytics script&lt;&#x2F;li&gt;
&lt;li&gt;For all other domains (such as localhost or staging environments), the script won&#x27;t be added. Only a console message will be displayed&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;Implementation&quot;&gt;Implementation&lt;&#x2F;h2&gt;
&lt;p&gt;Place this code in the &amp;lt;head&amp;gt; section of your HTML and remove the original tinylytics script tag.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;!--&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; Check domain and enable analytics only for specific domain&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; --&amp;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-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;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;  &#x2F;&#x2F; Get current hostname&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  const currentHostname = window.location.hostname;&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;  &#x2F;&#x2F; Specify production domain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  const productionDomain = &amp;#39;your.domain.com&amp;#39;;&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;  &#x2F;&#x2F; Only load analytics on production domain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  if (currentHostname === productionDomain) &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; Dynamically add tinylytics script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    const analyticScript&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; document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;createElement&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;script&amp;#39;&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-source&quot;&gt;    analyticScript&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;src&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;https:&#x2F;&#x2F;tinylytics.app&#x2F;embed&#x2F;Xx-xxxxxxxxxxxxxx.js&amp;#39;&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-source&quot;&gt;    analyticScript&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;defer&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-boolean&quot;&gt; true&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-source&quot;&gt;    document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;appendChild&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(analyticScript);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Production environment: Analytics enabled&amp;#39;&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-source&quot;&gt; else &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;    console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Development environment: Analytics disabled&amp;#39;&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">I have tried to prevent tinylytics stats from being retrieved outside of the production environment.</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>A Failed Experiment: Using OpenCV to Read Printed Dates from Scanned Photos</title>
        <published>2025-01-06T00:00:00+00:00</published>
        <updated>2025-01-06T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/a-failed-experiment-using-opencv/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/a-failed-experiment-using-opencv/</id>
        
            <content type="html">&lt;h3 id=&quot;Organizing_Old_Photographs&quot;&gt;Organizing Old Photographs&lt;&#x2F;h3&gt;
&lt;p&gt;I recently purchased a scanner at the end of the year to digitize old photographs. The photographs have dates printed on them, and I&#x27;ve been manually setting these dates in the EXIF information using ExifTool.&lt;&#x2F;p&gt;
&lt;p&gt;I use Hazel to organize image files, and I&#x27;ve already created a tool that updates file creation dates that Hazel can read with the shooting dates from EXIF data. However, since setting EXIF information manually is time-consuming, I explored the possibility of automating this process using OpenCV.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Date_Reading_Tool&quot;&gt;Date Reading Tool&lt;&#x2F;h3&gt;
&lt;p&gt;Below is a script that uses OpenCV to read dates from images and set them using ExifTool.&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; datetime&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; datetime&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; preprocess_image&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&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-string&quot;&gt;    Extract and process the date stamp portion from the image&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&quot;&gt;    &amp;quot;&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-punctuation z-definition z-comment z-comment&quot;&gt;    # Load image&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; cv2&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;imread&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-source&quot;&gt;    height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; width&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-indexed-name z-python&quot;&gt;shape&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;2&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;    # Crop the bottom right region&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    x1&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-type z-python&quot;&gt; int&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;width&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.65&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;    y1&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-type z-python&quot;&gt; int&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;height&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.75&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;    cropped&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-indexed-name z-python&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-item-access z-python&quot;&gt;y1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt; x1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;width&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;    # Split channels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; r&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; cv2&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;split&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;cropped&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;    # Enhance red channel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    red_emphasis&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; cv2&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;subtract&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;r&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; cv2&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;max&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;b&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; g&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;    # Enhance contrast using CLAHE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    clahe&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; cv2&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;createCLAHE&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;clipLimit&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;3.0&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; tileGridSize&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;8&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    enhanced&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; clahe&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;apply&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;red_emphasis&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;    # Strong thresholding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&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; binary&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; cv2&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;threshold&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;enhanced&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; 30&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;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&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;THRESH_BINARY&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;    # Remove noise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    kernel&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;ones&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;2&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;2&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; 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-arguments z-python&quot;&gt;uint8&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;    cleaned&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; cv2&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;morphologyEx&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;binary&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; cv2&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;MORPH_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; kernel&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;    # Detect and filter contours&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    contours&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&quot;&gt; cv2&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;findContours&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;cleaned&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; cv2&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;RETR_EXTERNAL&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; cv2&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;CHAIN_APPROX_SIMPLE&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;    # Filter by area&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    mask&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;zeros_like&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;cleaned&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;    min_area&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; 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    max_area&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; 500&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 z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; contour&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; contours&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;        area&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; cv2&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;contourArea&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;contour&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; min_area&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; area&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; max_area&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;            cv2&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;drawContours&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;mask&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;contour&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;255&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;&#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;    # Resize to 4x&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; cv2&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;resize&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;mask&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&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; fx&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;4&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; fy&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;4&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; interpolation&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-arguments z-python&quot;&gt;cv2&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;INTER_CUBIC&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;    # Save debug images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    debug_dir&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; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&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-meta z-function-call z-arguments z-python&quot;&gt;os&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;path&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;dirname&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;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;debug&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;    os&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;makedirs&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;debug_dir&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; exist_ok&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;&#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;    basename&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; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&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;basename&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-source&quot;&gt;    cv2&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;imwrite&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;os&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;path&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-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&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;#39;cropped_&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;basename&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;#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-arguments z-python&quot;&gt; cropped&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;    cv2&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;imwrite&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;os&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;path&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-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&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;#39;red_emphasis_&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;basename&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;#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-arguments z-python&quot;&gt; red_emphasis&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;    cv2&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;imwrite&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;os&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;path&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-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&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;#39;enhanced_&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;basename&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;#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-arguments z-python&quot;&gt; enhanced&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;    cv2&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;imwrite&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;os&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;path&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-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&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;#39;binary_&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;basename&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;#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-arguments z-python&quot;&gt; binary&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;    cv2&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;imwrite&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;os&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;path&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-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&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;#39;result_&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;basename&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;#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-arguments z-python&quot;&gt; result&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-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; result&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; extract_date_from_image&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;&#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;quot;&amp;quot;&amp;quot;Extract date from image using OCR&amp;quot;&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-punctuation z-definition z-comment z-comment&quot;&gt;    # Preprocess image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    processed_image&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; preprocess_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-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;&#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 configuration for single line text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    custom_configs&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;--psm 6 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&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-comment z-comment&quot;&gt;  # Uniform text block&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;--psm 7 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&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-comment z-comment&quot;&gt;  # Single text line&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;--psm 8 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&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-comment z-comment&quot;&gt;  # Single word&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;--psm 10 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Single character&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;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; custom_configs&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;        # Run OCR&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        text&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; pytesseract&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;image_to_string&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;processed_image&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; config&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-arguments z-python&quot;&gt;config&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;        text&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; text&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;strip&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;OCR result (config=&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;config&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;): [&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;text&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;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # Normalize spaces&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        text&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;#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-meta z-function-call z-arguments z-python&quot;&gt;text&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;split&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;        # Simple pattern matching&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        pattern&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 z-string z-python&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;{2}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;{1,2}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;{1,2}&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-end&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-source&quot;&gt;        match&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; re&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;search&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;pattern&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; text&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-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; match&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;                year&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-type z-python&quot;&gt; int&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;match&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;group&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;span class=&quot;z-source&quot;&gt;                month&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-type z-python&quot;&gt; int&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;match&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;group&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;2&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;                day&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-type z-python&quot;&gt; int&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;match&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;group&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;&#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;                # Handle 2000s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                year&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; 2000&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; year&lt;&#x2F;span&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; year&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; 50&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; else&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1900&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; year&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 z-control z-flow z-python&quot;&gt;                if&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&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; month&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; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; and&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&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; day&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; 31&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;                    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; datetime&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;year&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; month&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; day&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; ValueError&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;                continue&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 z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&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; set_exif_date&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; date&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;quot;&amp;quot;&amp;quot;Set EXIF date information using ExifTool&amp;quot;&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-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;    if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; date&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;No date found in: &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;image_path&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;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&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-source&quot;&gt;    date_str&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; date&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;strftime&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;quot;%Y:%m:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;%d&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;&#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;    # EXIF tags to set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    exif_tags&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;quot;DateTimeOriginal&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-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;CreateDate&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-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;ModifyDate&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;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    command&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;quot;exiftool&amp;quot;&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;quot;-overwrite_original_in_place&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;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; tag&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; exif_tags&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;        command&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;extend&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;-&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;tag&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;=&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;date_str&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-source&quot;&gt;    command&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;append&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;&#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;        subprocess&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;run&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;command&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; check&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; capture_output&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;&#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;Date set successfully: &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;image_path&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;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-meta z-function-call z-arguments z-python&quot;&gt;date_str&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;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; True&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-source&quot;&gt; subprocess&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;CalledProcessError&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;Failed to set EXIF information: &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;e&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;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&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;&#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; process_images&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;directory&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;quot;&amp;quot;&amp;quot;Process all images in the specified directory&amp;quot;&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-source&quot;&gt;    processed&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-source&quot;&gt;    failed&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;&#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;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; filename&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&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;listdir&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;directory&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; filename&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;lower&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;endswith&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;.png&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;.jpg&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;.jpeg&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;            image_path&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; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&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-meta z-function-call z-arguments z-python&quot;&gt;directory&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; filename&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;            date&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; extract_date_from_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-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;&#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-meta z-function-call z-python&quot;&gt; set_exif_date&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;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; date&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;                processed&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;&#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;            else&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;                failed&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;&#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 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;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Processing complete:&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;    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;Success: &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;processed&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;    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;Failed: &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;failed&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-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-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; len&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;sys&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;argv&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; 2&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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Usage: photodate &amp;lt;image_directory&amp;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-source&quot;&gt;        sys&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;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;span class=&quot;z-source&quot;&gt;    directory&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; sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;argv&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;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;    if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&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;isdir&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;directory&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-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Specified path is not a valid directory&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-source&quot;&gt;        sys&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;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;span class=&quot;z-meta z-function-call z-python&quot;&gt;    process_images&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;directory&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;quot;__main__&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-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;&lt;h3 id=&quot;Results&quot;&gt;Results&lt;&#x2F;h3&gt;
&lt;p&gt;I tested the script on 27 scanned photographs.&lt;&#x2F;p&gt;
&lt;p&gt;Out of 27 images, the script only detected dates in 4 images, and among those, only 1 date was correctly recognized.&lt;&#x2F;p&gt;
&lt;p&gt;Well, this isn&#x27;t practical enough to use.&lt;&#x2F;p&gt;
</content>
        <summary type="html">I recently purchased a scanner and was challenged to see if I could capture the shooting date from the images when digitizing old photos that have dates printed on them.</summary>
        </entry><entry xml:lang="en">
        <title>LogSeq at a Glance: An Overview for Beginners</title>
        <published>2025-01-01T00:00:00+00:00</published>
        <updated>2025-01-01T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/logseq/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/logseq/</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;h3 id=&quot;LogSeqとは何か、シンプルな説明&quot;&gt;LogSeqとは何か、シンプルな説明&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqは、あなたの考えやアイデア、メモを自由に書き留め、それらをつなぎ合わせることができるデジタルノートアプリです。紙のノートとは違い、書いた内容を後から簡単に整理したり、関連する情報どうしをリンクでつなげたりできます。&lt;&#x2F;p&gt;
&lt;p&gt;特徴的なのは、以下の3つのポイントです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;箇条書きベースで書ける&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;考えたことを思いつくままメモできる&lt;&#x2F;li&gt;
&lt;li&gt;後から簡単に整理できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;日付ごとにページが自動で作られる&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日記のように、その日のことを記録できる&lt;&#x2F;li&gt;
&lt;li&gt;カレンダーのように過去の記録を見返せる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ページ同士をつなげられる&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する情報どうしを簡単にリンクできる&lt;&#x2F;li&gt;
&lt;li&gt;新しい気づきや発見を見つけやすい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;なぜLogSeqが便利なのか&quot;&gt;なぜLogSeqが便利なのか&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqが便利な理由は、私たちの脳の働き方と合わせた設計にあります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;思考の自然な流れを妨げない&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;思いついたことを、その場でさっと書き留められる&lt;&#x2F;li&gt;
&lt;li&gt;後でどこに書いたか探すことを気にせず、まずメモできる&lt;&#x2F;li&gt;
&lt;li&gt;整理は後からでもできる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;情報同士のつながりを自然に作れる&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する情報を&lt;code&gt;[[リンク]]&lt;&#x2F;code&gt;で簡単につなげられる&lt;&#x2F;li&gt;
&lt;li&gt;一度つないだ情報は、双方向から見つけられる&lt;&#x2F;li&gt;
&lt;li&gt;気づかなかった情報のつながりが自然と見えてくる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;記憶と振り返りをサポート&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日付ごとのページが自動で作られるので、いつ何を考えたかが残る&lt;&#x2F;li&gt;
&lt;li&gt;過去の記録が自然とタイムライン化される&lt;&#x2F;li&gt;
&lt;li&gt;定期的な振り返りが簡単にできる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知識が育っていく&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;書いた内容は単なる記録として終わらない&lt;&#x2F;li&gt;
&lt;li&gt;新しい情報を追加するたびに、既存の知識とつながっていく&lt;&#x2F;li&gt;
&lt;li&gt;それによって新しい発見や気づきが生まれる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;つまり、LogSeqは「とりあえずメモ」から始めて、そこから自然と「つながりのある知識」を育てていけるツールなのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;LogSeqの基本的な使い方&quot;&gt;LogSeqの基本的な使い方&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;最初の画面の見方&quot;&gt;最初の画面の見方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqを開くと、シンプルな画面が表示されます。画面の構成を理解しましょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;左側のサイドバー&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ジャーナル（日付ごとのページ）へのリンク&lt;&#x2F;li&gt;
&lt;li&gt;お気に入りページの一覧&lt;&#x2F;li&gt;
&lt;li&gt;全てのページ一覧&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;メイン画面&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現在の日付のページが自動で開&lt;&#x2F;li&gt;
&lt;li&gt;ここに自由に文章を書いていく&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;右側のサイドバー&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;開いているページに関連する情報が表示&lt;&#x2F;li&gt;
&lt;li&gt;リンクされているページの一覧なども表示&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;新しいページの作り方&quot;&gt;新しいページの作り方&lt;&#x2F;h3&gt;
&lt;p&gt;新しいページを作るには2つの方法があります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;直接作成する方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;画面上部の検索バーに新しいページ名を入力&lt;&#x2F;li&gt;
&lt;li&gt;エンターキーを押すと、新しいページが作られる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;リンクから作る方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;文章の中に&lt;code&gt;[[新しいページ名]]&lt;&#x2F;code&gt;と書く&lt;&#x2F;li&gt;
&lt;li&gt;自動的にリンクが作られ、クリックで新しいページを作られる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;Markdownで記入する&quot;&gt;Markdownで記入する&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqでは、Markdownという書き方を使います。難しく考える必要はありません。
以下のような基本的な書き方を覚えましょう。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;見出しの書き方&lt;&#x2F;strong&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-text&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-heading z-markdown z-heading z-\31  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-heading z-markdown z-heading z-\32  z-markdown&quot;&gt;## 小見出し&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;文字の装飾&lt;&#x2F;strong&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-italic&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&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&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&quot;&gt;~~&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-strikethrough&quot;&gt;打ち消し線&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;strong&gt;箇条書き&lt;&#x2F;strong&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-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&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 z-definition z-list z-begin z-markdown&quot;&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 箇条書き1-1&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; 箇条書き1-2&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; 箇条書き2&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;h3 id=&quot;箇条書きの書き方&quot;&gt;箇条書きの書き方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqでは、箇条書きを基本としてノートを作成します。箇条書きには、以下のような特徴があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本の書き方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;行頭に「-」（ハイフン）と半角スペースを入力&lt;&#x2F;li&gt;
&lt;li&gt;Enterキーを押すと、自動的に次の箇条書きが始まる&lt;&#x2F;li&gt;
&lt;li&gt;Tabキーで階層を下げる（字下げ）&lt;&#x2F;li&gt;
&lt;li&gt;Shift + Tabで階層を上げる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;箇条書きのコツ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1つの項目は短めに書く&lt;&#x2F;li&gt;
&lt;li&gt;詳しい説明が必要な場合は、階層を下げて書く&lt;&#x2F;li&gt;
&lt;li&gt;関連する内容は、同じ階層にまとめる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;日付ページの使い方&quot;&gt;日付ページの使い方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqでは、毎日自動的に日付のページ（ジャーナル）が作られます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;日付ページの特徴&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;起動時に自動的に今日の日付のページが開く&lt;&#x2F;li&gt;
&lt;li&gt;左サイドバーの「Journals」から過去の日付を開ける&lt;&#x2F;li&gt;
&lt;li&gt;日付ページには、その日に考えたことや行ったことを自由に書ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;効果的な使い方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;朝：今日やることを箇条書きで書き出す&lt;&#x2F;li&gt;
&lt;li&gt;日中：気づいたことや考えたことをメモ&lt;&#x2F;li&gt;
&lt;li&gt;夜：その日の振り返りを書く&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;タグの付け方と活用法&quot;&gt;タグの付け方と活用法&lt;&#x2F;h3&gt;
&lt;p&gt;タグは情報の整理と検索を助ける強力なツールです。ページリンクと組み合わせることで、より効果的な知識管理が可能になります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;タグの基本&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;単語の前に「#」（ハッシュ）を付ける&lt;&#x2F;li&gt;
&lt;li&gt;例：#勉強 #アイデア #ToDo&lt;&#x2F;li&gt;
&lt;li&gt;スペースを含む場合は「&lt;code&gt;#[[読書メモ]]&lt;&#x2F;code&gt;」のように[[]]で囲む&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;タグとページリンクの特徴と使い分け&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;タグ（#）の特徴&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;複数のページに共通する「性質」を示すのに適している&lt;&#x2F;li&gt;
&lt;li&gt;一覧表示やフィルタリングが簡単&lt;&#x2F;li&gt;
&lt;li&gt;例：#未完了、#重要、#要復習&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ページリンク([[]])の特徴&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;特定の「主題」についての詳細な記述に適している&lt;&#x2F;li&gt;
&lt;li&gt;概念間の関係性を表現しやすい&lt;&#x2F;li&gt;
&lt;li&gt;例：&lt;code&gt;[[数学]]&lt;&#x2F;code&gt;、&lt;code&gt;[[微分]]&lt;&#x2F;code&gt;、&lt;code&gt;[[Newton]]&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;効果的な併用方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;主題と性質を組み合わせる
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[[微分]]&lt;&#x2F;code&gt; のページに #数学 #要復習を付ける&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[[読書記録]]&lt;&#x2F;code&gt; のページに #継続中 #インプットを付ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;概念の関係性を示す
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[[微分]]&lt;&#x2F;code&gt;のページで &lt;code&gt;[[極限]]&lt;&#x2F;code&gt; と &lt;code&gt;[[関数]]&lt;&#x2F;code&gt; を参照しつつ、#数学を付ける&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[[Newton]]&lt;&#x2F;code&gt;のページで &lt;code&gt;[[力学]]&lt;&#x2F;code&gt; を参照しつつ、#物理学者を付ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;このように、タグとページリンクはそれぞれの特徴を活かして使うことで、より効率的な知識管理が可能になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;知識のつながりを作る&quot;&gt;知識のつながりを作る&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;ページ間のリンクの作り方&quot;&gt;ページ間のリンクの作り方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqの強力な特徴は、ページ同士をつなげられることです。知識と知識を結びつけることで、新しい気づきが生まれやすくなります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本的なリンクの作り方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[[ページ名]]&lt;&#x2F;code&gt; と入力する（&lt;code&gt;[[&lt;&#x2F;code&gt;と&lt;code&gt;]]&lt;&#x2F;code&gt;で囲む）&lt;&#x2F;li&gt;
&lt;li&gt;リンク先のページがなければ、自動的に新しいページが作られる&lt;&#x2F;li&gt;
&lt;li&gt;エイリアスをつける場合：&lt;code&gt;[[ページ名]][表示したい文字]&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;例：&lt;code&gt;[[アインシュタイン]][彼]&lt;&#x2F;code&gt;と書くと、「彼」と表示される&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;効果的なリンクの付け方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;重要な概念や用語が出てきたらリンクにする&lt;&#x2F;li&gt;
&lt;li&gt;関連する話題が出てきたら積極的にリンクする&lt;&#x2F;li&gt;
&lt;li&gt;あとで詳しく書きたい内容があればリンクにする&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;バックリンクの概念と確認方法&quot;&gt;バックリンクの概念と確認方法&lt;&#x2F;h3&gt;
&lt;p&gt;バックリンクとは、「どのページからリンクされているか」を示す機能です。自動的に作られる双方向のつながりにより、知識の関係性が見えてきます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;バックリンクの特徴&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自動的に作られる（手動で作る必要はない）&lt;&#x2F;li&gt;
&lt;li&gt;右サイドバーに表示される&lt;&#x2F;li&gt;
&lt;li&gt;リンク元のページの該当部分が引用として表示される&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;バックリンクの活用法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する記述を後から発見できる&lt;&#x2F;li&gt;
&lt;li&gt;同じ概念が出てくる文脈を確認できる&lt;&#x2F;li&gt;
&lt;li&gt;知識のunexpectedな関連性に気づける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;関連する情報のつながりを見つける方法&quot;&gt;関連する情報のつながりを見つける方法&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqには、知識のつながりを見つけるための様々な機能があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;グラフビュー&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ページ間のつながりを視覚的に表示&lt;&#x2F;li&gt;
&lt;li&gt;右上のグラフアイコンをクリック&lt;&#x2F;li&gt;
&lt;li&gt;ノードをクリックすると関連するページに移動&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;検索機能の活用&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;キーワードで関連ページを検索&lt;&#x2F;li&gt;
&lt;li&gt;タグとページリンクを組み合わせて検索&lt;&#x2F;li&gt;
&lt;li&gt;日付範囲を指定して検索&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知識のつながりを育てる方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;定期的にバックリンクを確認する&lt;&#x2F;li&gt;
&lt;li&gt;関連しそうなページを積極的にリンクする&lt;&#x2F;li&gt;
&lt;li&gt;グラフビューで全体の構造を確認する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;このように、LogSeqでは知識同士を様々な方法でつなげることができます。つながりが増えるほど、新しい発見や気づきが生まれやすくなります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;日常的な使い方のおすすめパターン&quot;&gt;日常的な使い方のおすすめパターン&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqを効果的に活用するために、以下のような使い方がおすすめです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;1日の基本的な流れ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;朝：今日やることを箇条書きで書き出す&lt;&#x2F;li&gt;
&lt;li&gt;日中：思いついたことを &lt;code&gt;[[]]&lt;&#x2F;code&gt; でリンクしながらメモ&lt;&#x2F;li&gt;
&lt;li&gt;夜：その日の振り返りと、重要な項目に &lt;code&gt;#タグ&lt;&#x2F;code&gt; をつける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知識を育てる方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;気になる言葉は積極的に &lt;code&gt;[[]]&lt;&#x2F;code&gt; でリンク&lt;&#x2F;li&gt;
&lt;li&gt;関連する過去のメモは右サイドバーのバックリンクで確認&lt;&#x2F;li&gt;
&lt;li&gt;時々グラフビューを開いて知識の関係性を見直す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;継続的な活用のコツ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;完璧を目指さず、まずはメモを取ることから始める&lt;&#x2F;li&gt;
&lt;li&gt;少しずつ機能を試して、自分に合う使い方を見つける&lt;&#x2F;li&gt;
&lt;li&gt;定期的に過去のメモを見返して、知識をアップデート&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;困ったときの対処法&quot;&gt;困ったときの対処法&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqを使っていて困ったときは、以下の方法を試してみましょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;書き方を忘れたとき&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Markdownの基本：&lt;code&gt;#&lt;&#x2F;code&gt; で見出し、&lt;code&gt;-&lt;&#x2F;code&gt; で箇条書き&lt;&#x2F;li&gt;
&lt;li&gt;リンクとタグ：&lt;code&gt;[[ページ名]]&lt;&#x2F;code&gt; と &lt;code&gt;#タグ名&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;これらは画面下部のヘルプアイコンでいつでも確認可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;情報が見つからないとき&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;検索バーに関連するキーワードを入力&lt;&#x2F;li&gt;
&lt;li&gt;タグで絞り込み検索&lt;&#x2F;li&gt;
&lt;li&gt;グラフビューで関連ページを探す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;整理が必要と感じたとき&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する情報を新しいページにまとめる&lt;&#x2F;li&gt;
&lt;li&gt;適切なタグをつけて分類する&lt;&#x2F;li&gt;
&lt;li&gt;不要になったメモは、アーカイブとしてタグ付け&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;LogSeqは、使い始めは普通のメモ帳として、慣れてきたら知識を育てるツールとして活用できます。一度にすべての機能を使いこなす必要はありません。自分のペースで、少しずつ使い方を広げていってください。&lt;&#x2F;p&gt;
</content>
        <summary type="html">I created this simple guide to LogSeq to help friends get started with the tool. Written in Japanese, this overview aims to help new users understand LogSeq&#x27;s key features and daily usage patterns from a bird&#x27;s-eye perspective.</summary>
        </entry><entry xml:lang="en">
        <title>A Command to Sync EXIF Data with File System Timestamps</title>
        <published>2024-12-30T00:00:00+00:00</published>
        <updated>2024-12-30T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/12/exif-tool/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/12/exif-tool/</id>
        
            <content type="html">&lt;p&gt;The scanner&#x27;s performance has been impressive - it handled even my old San Francisco business trip photos from 2001 beautifully, producing crisp, clear scans.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Setting_EXIF_Information&quot;&gt;Setting EXIF Information&lt;&#x2F;h2&gt;
&lt;p&gt;Unlike photos taken with a digital camera, scanned images don&#x27;t come with proper EXIF data. To preserve the actual capture dates of these photos, I used exiftool from the command line to set the correct EXIF information:&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;# Example: Setting the original capture date&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-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;-DateTimeOriginal=2001:04:15 10:00:00&amp;quot; photo.jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This command successfully embeds the correct capture date in the photo&#x27;s EXIF data.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Photo_Organization&quot;&gt;The Photo Organization&lt;&#x2F;h2&gt;
&lt;p&gt;For managing my photo files, I rely on Hazel, a powerful file organization tool for Mac. Hazel offers some fantastic automation features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Filtering based on file creation and modification dates&lt;&#x2F;li&gt;
&lt;li&gt;Automatic folder organization&lt;&#x2F;li&gt;
&lt;li&gt;Smart file renaming&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;However, Hazel has one limitation that&#x27;s been bugging me: it can&#x27;t directly read EXIF data. This means that even though I&#x27;ve carefully added the correct capture dates to the EXIF data, I can&#x27;t use this information for Hazel&#x27;s automated organization.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Solution:_adj-photodate_Script&quot;&gt;The Solution: adj-photodate Script&lt;&#x2F;h2&gt;
&lt;p&gt;To bridge this gap, I created a script that syncs EXIF information with the file system timestamps (creation and modification dates). This enables Hazel to organize photos based on their actual capture dates.&lt;&#x2F;p&gt;
&lt;p&gt;The script provides the following features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Syncs &lt;code&gt;DateTimeOriginal&lt;&#x2F;code&gt; from EXIF to file system timestamps&lt;&#x2F;li&gt;
&lt;li&gt;Includes a dry-run mode for previewing changes&lt;&#x2F;li&gt;
&lt;li&gt;Handles batch processing of multiple files&lt;&#x2F;li&gt;
&lt;li&gt;Supports recursive directory processing&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;Installation&quot;&gt;Installation&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a file named &quot;adj-photodate&quot; and paste the following script:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;yostos&#x2F;9c301b2831ad3e810cbb4131586687a7&quot;&gt;adj-photodate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Make it executable:&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;chmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +x adj-photodate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Optionally, move it to your path:&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;cp&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; adj-photodate ~&#x2F;bin&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dependencies:&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;bash shell&lt;&#x2F;li&gt;
&lt;li&gt;exiftool&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;Usage&quot;&gt;Usage&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;# Process a single file&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;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; photo.jpg&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;# Preview changes with dry-run&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;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -n photo.jpg&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;# Process all JPEG files in a directory recursively&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;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -r ~&#x2F;Pictures&#x2F;Scanned&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To see available options:&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;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">I recently embarked on a journey to digitize my old photographs. Since mypre-digital photos exist only as physical prints, I decided to invest in aPFU scanner to bring these memories into the digital age.</summary>
        </entry><entry xml:lang="en">
        <title>Berkeley Mono: A Worthy Successor to MonoLisa in My Terminal</title>
        <published>2024-12-19T00:00:00+00:00</published>
        <updated>2024-12-19T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/12/berkeley-mono/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/12/berkeley-mono/</id>
        
            <content type="html">&lt;p&gt;ずっとMacのターミナルでは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.monolisa.dev&#x2F;&quot;&gt;MonoLisa&lt;&#x2F;a&gt;フォントを利用してきましたが、
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;Berkeley Mono&lt;&#x2F;a&gt;フォントに入れ替えました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MonoLisaフォントの課題&quot;&gt;MonoLisaフォントの課題&lt;&#x2F;h2&gt;
&lt;p&gt;MonoLisaフォントは紛らわしい文字の区別やリガチャのサポートなどコーディングをサポートするためのデザインがなされており読みやすいフォントで愛用していました。一部筆記体のようなデザインも気に入っていました。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、次の2点が課題だと思っていました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;読みやすさを考慮しているのだと思いますが、文字間隔が広すぎて間延びして逆にコードを把握しにくい。&lt;&#x2F;li&gt;
&lt;li&gt;ライセンス費用が割高でWebフォントまで入手しようとすると非常に高額になる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;また、単純に飽きたということもあります。&lt;&#x2F;p&gt;
&lt;p&gt;Cascadia Next JPのプレビューが出ているので少し使ってみしたが、かなり文字間隔が狭く凝縮した印象です。MonoLisaのように文字間隔が広すぎるより、個人的は好みでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Berkeley_Mono_を導入する&quot;&gt;Berkeley Mono を導入する&lt;&#x2F;h2&gt;
&lt;p&gt;Berkeley Monoは少し前に一部で話題になっていましたが、リガチャのサポートがなかったのでその時は見送りました。
ところが最近になって確認するとリガチャをサポートしたようだったので、購入しました。&lt;&#x2F;p&gt;
&lt;p&gt;紹介文には以下のように書かれています。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;
  Berkeley Mono is a love letter to the golden era of computing. The era that
  gave rise to a generation of people who celebrated automation and reveled in
  the joy of computing, when transistors replaced cogs, and machine-readable
  typefaces were developed, for when humans and machines truly interfaced on an
  unprecedented scale.
  &lt;footer&gt;
    &lt;cite&gt;
      Berkeley Graphics -{&quot; &quot;}
      &lt;a href=&quot;https:&#x2F;&#x2F;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;
        Berkeley Mono
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;確かにちょっと懐かしい「コンピューター」らしい文字のデザインです。&lt;&#x2F;p&gt;
&lt;p&gt;気に入っている点は、次の3点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ちょうど良い文字間隔&lt;&#x2F;li&gt;
&lt;li&gt;スクエアなデザイン&lt;&#x2F;li&gt;
&lt;li&gt;買い切りでWebフォントまで含んでいる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に文字間隔や高さが日本語フォントとバランス良いよいに思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;フォント比較&quot;&gt;フォント比較&lt;&#x2F;h2&gt;
&lt;p&gt;以下のスクリーンショットは、適当なプログラムCascadia Next &#x2F; MonoLisa &#x2F; Berkeley Monoを使って表示させた例です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2024&amp;#x2F;12&amp;#x2F;berkeley-mono&amp;#x2F;fonts.jpg?h=dc626dd5229814723749&quot;
  alt=&quot;Fonts Comparison&quot; width=&quot;1800&quot; height=&quot;996&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;文字間隔の違いがよくわかると思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ずっとMacのターミナルではMonoLisaフォントを利用してきましたが、Berkeley Monoフォントに入れ替えました。</summary>
        </entry><entry xml:lang="en">
        <title>Goodbye Bartender!</title>
        <published>2024-11-12T00:00:00+00:00</published>
        <updated>2024-11-12T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/goodbye-bartender/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/goodbye-bartender/</id>
        
            <content type="html">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.macbartender.com&#x2F;&quot;&gt;Bartender&lt;&#x2F;a&gt; was menu bar wizard I&#x27;d been geeking out over. Turned out Ben Surtees had sold it to some shadowy outfit called Applause in March 2024. Reddit blew up with users freaking out.
Today, I&#x27;ve now ditched Bartender for Ice,too.&lt;&#x2F;p&gt;
&lt;p&gt;Keep it FOSS, keep it safe, am I right?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.macbartender.com&#x2F;&quot;&gt;バーテンダー&lt;&#x2F;a&gt;はメニューバーの魔術師で、私は熱中していました。ベン・サーティーズが2024年3月にApplauseという正体不明の会社に売却していたことが判明しました。Redditではユーザーたちが大騒ぎしていました。
今日、私もバーテンダーを捨ててIceに乗り換えました。&lt;&#x2F;p&gt;
&lt;p&gt;オープンソースを守れば安全、そうでしょ？&lt;&#x2F;p&gt;
</content>
        <summary type="html">Macのメニュー管理アプリのBartenderが結構まずいことになっていました。</summary>
        </entry><entry xml:lang="en">
        <title>Google Cloud Digital Leader</title>
        <published>2024-11-08T00:00:00+00:00</published>
        <updated>2024-11-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/cloud-digital-leader/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/cloud-digital-leader/</id>
        
            <content type="html">&lt;p&gt;Googleも資格認定管理にCertMerticsを使っていますが、結果はおろか受験履歴ですら受験日になっても表示されず、受験時は受験者承認コードという &quot;yyxxzze12345000&quot;的な意味のない長いコードを会場で手書きさせられました。AWSの認定資格と比べるとなんだかなという感じです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2024&amp;#x2F;11&amp;#x2F;cloud-digital-leader&amp;#x2F;badge.png?h=e564e1ce3e4558300a52&quot;
  alt=&quot;Google Cloud Digital Leader Budge&quot; width=&quot;187&quot; height=&quot;187&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Google CloudのCloud Digital Leaderを受験してきました。レベル的にはAWSのCloudPractitioner相当だと思いますので、ほぼ準備せずに受験しても大丈夫でした。</summary>
        </entry><entry xml:lang="en">
        <title>S3静的ウェブサイトのインデックス解決をCloudFront Functionsで修正</title>
        <published>2024-11-05T00:00:00+00:00</published>
        <updated>2024-11-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/fixing-s3-cloudfront-index-resolution/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/fixing-s3-cloudfront-index-resolution/</id>
        
            <content type="html">&lt;p&gt;メインブログをCloudflareからAWS S3へと移行した際、
S3のBlock pubic accessをオフ、Static website hostingをオンにしていたので、
CloudFrontがS3のREST APIエンドポイントを使用するよう修正しました。&lt;&#x2F;p&gt;
&lt;p&gt;この場合CloudFrontはサブディレクトリのindex.htmlファイルを自動的に解決できないので、以下のURLのパスを適切に変換するCloudFront Functionsを追加しました。&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;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; handler&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;event&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-storage z-type&quot;&gt;  var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; request&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; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;request&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-storage z-type&quot;&gt;  var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; uri&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; request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;uri&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;  &#x2F;&#x2F; URIが&#x2F;で終わる場合、index.htmlを追加&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; (uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;endsWith&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;    request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;uri&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;quot;index.html&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-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; 拡張子がない場合もindex.htmlを追加&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 if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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-source&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;includes&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;.&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&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;    request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;uri&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;quot;&#x2F;index.html&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-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-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; request&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;</content>
        <summary type="html">CloudFlareからブログを移行した際に、パスの指定で問題がでていたので修正しました。</summary>
        </entry><entry xml:lang="en">
        <title>The Ultimate Showdown: A Deep Dive into Modern Messaging Apps</title>
        <published>2024-10-23T00:00:00+00:00</published>
        <updated>2026-07-01T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/10/modern-messaging-apps/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/10/modern-messaging-apps/</id>
        
            <content type="html">&lt;p&gt;市川強盗傷害事件で犯人たちが「秘匿性が高い通信アプリを使用」とアプリ名を伏せて報道されています。
どうやら&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;signal.org&#x2F;ja&#x2F;&quot;&gt;Signal&lt;&#x2F;a&gt;を使っていたようです。こうなるとバカなメディアや視聴者が「邪悪なアプリ」と騒ぎ出しそうですね。&lt;&#x2F;p&gt;
&lt;p&gt;プライバシー&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;
を考慮すると当然の選択ですね。公安や自衛隊でもSignalを奨励しているようです。
不完全な暗号化やメタデータ収集するLINEとかいうアプリを使っている能天気なメディアや視聴者より、
犯人たちのほうがよほど高いリテラシーを持っていたということでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;気になったので、主要なメッセージングアプリについての比較表を作ってみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリの総合比較表&quot;&gt;メッセージングアプリの総合比較表&lt;&#x2F;h2&gt;
&lt;p&gt;以下は主なメッセージングアプリのついての比較をまとめた表です。&lt;&#x2F;p&gt;
&lt;p&gt;犯人たちが&lt;strong&gt;Signal&lt;&#x2F;strong&gt;を使ったのも納得です。日本ではユーザーが少ないので利用シーンは限られますが。
次点で &lt;strong&gt;Threema&lt;&#x2F;strong&gt; ですね。私は家族で使用しています。&lt;&#x2F;p&gt;
&lt;p&gt;iPhoneユーザーであれば &lt;strong&gt;iMessage&lt;&#x2F;strong&gt; は無難でしょう。完全にE2Eで暗号化されており、メタ情報の収集はされているようですが、Appleなので多少はマシだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Telegram&lt;&#x2F;strong&gt; はテロリストが使用しているイメージはありますが、意外に脆弱です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;LINE&lt;&#x2F;strong&gt;については、日本でもユーザーが多いので補足を入れています。
やはりLINEは暗号化も不完全でデフォルトの状態ですし、メタ情報&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-2&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;をかなり収集してお
り、おまけに透明性の観点でもいろいろと問題&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;p&gt;こう並べてみると、&lt;strong&gt;LINE&lt;&#x2F;strong&gt; を選択する意味が私にはわかりません。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&#x2F;特徴&lt;&#x2F;th&gt;&lt;th&gt;LINE&lt;&#x2F;th&gt;&lt;th&gt;Signal&lt;&#x2F;th&gt;&lt;th&gt;Threema&lt;&#x2F;th&gt;&lt;th&gt;WhatsApp&lt;&#x2F;th&gt;&lt;th&gt;iMessage&lt;&#x2F;th&gt;&lt;th&gt;Telegram&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;E2E暗号化&lt;&#x2F;td&gt;&lt;td&gt;部分対応[暗号化WP] ※1&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;Secret Chatのみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;グループチャット暗号化&lt;&#x2F;td&gt;&lt;td&gt;50人以下のみ[暗号化WP]&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;Secret Chatのみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;メタデータ収集&lt;&#x2F;td&gt;&lt;td&gt;多い[PP] ※2&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&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;サーバー保存[暗号化WP,PP] ※3&lt;&#x2F;td&gt;&lt;td&gt;端末のみ&lt;&#x2F;td&gt;&lt;td&gt;端末のみ&lt;&#x2F;td&gt;&lt;td&gt;クラウド可能&lt;&#x2F;td&gt;&lt;td&gt;iCloud連携時保存&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;はい[PP]&lt;&#x2F;td&gt;&lt;td&gt;はい&lt;&#x2F;td&gt;&lt;td&gt;いいえ&lt;&#x2F;td&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;24時間のみ[PP]&lt;&#x2F;td&gt;&lt;td&gt;1秒～4週間&lt;&#x2F;td&gt;&lt;td&gt;カスタム設定可&lt;&#x2F;td&gt;&lt;td&gt;24時間～90日&lt;&#x2F;td&gt;&lt;td&gt;2分～4週間&lt;&#x2F;td&gt;&lt;td&gt;1秒～1週間&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;法執行機関への情報開示&lt;&#x2F;td&gt;&lt;td&gt;多い[TR] ※4&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&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;スタンプ&#x2F;ゲーム&#x2F;決済&#x2F;音声・ビデオ通話[PP]&lt;&#x2F;td&gt;&lt;td&gt;スタンプ&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;td&gt;投票&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;td&gt;ステータス&#x2F;音声・ビデオ通話&#x2F;決済&lt;&#x2F;td&gt;&lt;td&gt;Apple統合&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;td&gt;Bot&#x2F;チャンネル&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;オープンソース&lt;&#x2F;td&gt;&lt;td&gt;一部のみ[暗号化WP]&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;一部のみ&lt;&#x2F;td&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;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;ul&gt;
&lt;li&gt;※1: LINEのE2E暗号化（Letter Sealing）対応範囲(doc.1) &lt;ins&gt;（2026年7月追記: 2024年後半にLetter Sealingの保護対象が拡大されました。出典: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.lycorp.co.jp&#x2F;ja&#x2F;privacy-security&#x2F;security&#x2F;transparency&#x2F;encryption-report&#x2F;2025&#x2F;&quot;&gt;LINE暗号化状況レポート（2025年）&lt;&#x2F;a&gt;）&lt;&#x2F;ins&gt;
&lt;ul&gt;
&lt;li&gt;対応: テキスト・位置情報（1対1と50人以下グループ）、1対1音声・ビデオ通話&lt;ins&gt;、画像・動画・音声メッセージ・ファイル添付（2024年後半に対応。1対1と50人以下グループ）&lt;&#x2F;ins&gt;&lt;&#x2F;li&gt;
&lt;li&gt;非対応: &lt;del&gt;画像、動画、ファイル添付、&lt;&#x2F;del&gt;50人以上グループ、グループ通話、LINEミーティング&lt;ins&gt;、アルバム、ノート&lt;&#x2F;ins&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;※2: LINEのメタデータ収集内容(doc.2)
&lt;ul&gt;
&lt;li&gt;アカウント情報（電話番号、メールアドレス）&lt;&#x2F;li&gt;
&lt;li&gt;デバイス情報（使用OS、言語設定）&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;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;※3: LINEのデータストレージ(doc.1,doc.2)
&lt;ul&gt;
&lt;li&gt;メッセージはサーバーに保存&lt;&#x2F;li&gt;
&lt;li&gt;クラウドバックアップ時は暗号化解除&lt;&#x2F;li&gt;
&lt;li&gt;URL preview等の機能利用時はサーバーに内容送信&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;※4: 法執行機関への開示可能情報(doc.3)
&lt;ul&gt;
&lt;li&gt;7日分のテキストチャット履歴&lt;&#x2F;li&gt;
&lt;li&gt;アカウント情報&lt;&#x2F;li&gt;
&lt;li&gt;通信ログ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;判断は以下の[LINEの公式ドキュメント]より確認しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;暗号化ホワイトペーパー(doc.1)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-linewhitepaper-1&quot;&gt;&lt;a href=&quot;#fn-linewhitepaper&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;terms2.line.me&#x2F;globalnews_PP&#x2F;sp&quot;&gt;プライバシーポリシー&lt;&#x2F;a&gt;(doc.2)&lt;&#x2F;li&gt;
&lt;li&gt;透明性レポート(doc.3)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-linecorp-1&quot;&gt;&lt;a href=&quot;#fn-linecorp&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私自身は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threema.ch&#x2F;en&quot;&gt;Threema&lt;&#x2F;a&gt;を使用しています。&lt;&#x2F;p&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;a href=&quot;#fr-1-2&quot;&gt;↩2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;2021年のZホールディングとの経営統合で、トークの画像などの情報が韓国の
サーバーでホスティングされていたり、通報確認などが中国企業に委託されてい
たり、このようなことが「第三国」としかレポートされていなかったりと透明性の観
点で問題がありました。現在は解消されたと報告されていますが。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-linewhitepaper&quot;&gt;
&lt;p&gt;元のホワイトペーパー: https:&#x2F;&#x2F;scdn.line-apps.com&#x2F;stf&#x2F;linecorp&#x2F;en&#x2F;csr&#x2F;line-encryption-whitepaper-ver2.1.pdf は現在アクセスできません &lt;a href=&quot;#fr-linewhitepaper-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-linecorp&quot;&gt;
&lt;p&gt;元のレポートページは削除されました &lt;a href=&quot;#fr-linecorp-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">市川強盗傷害事件で犯人たちがSignalを使っていたということで、「SIgnalは危険アプリ」とか言い出すバカがいそうなのでまとめてみました。</summary>
        </entry><entry xml:lang="en">
        <title>メインブログのAWS移行</title>
        <published>2024-10-21T00:00:00+00:00</published>
        <updated>2024-10-21T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/10/blog-hosted-on-aws/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/10/blog-hosted-on-aws/</id>
        
            <content type="html">&lt;p&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;th&gt;月間コスト (USD)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;S3&lt;&#x2F;td&gt;&lt;td&gt;ストレージ&lt;&#x2F;td&gt;&lt;td&gt;$0.0075&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;S3&lt;&#x2F;td&gt;&lt;td&gt;GET リクエスト&lt;&#x2F;td&gt;&lt;td&gt;$0.0012&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ACM&lt;&#x2F;td&gt;&lt;td&gt;証明書&lt;&#x2F;td&gt;&lt;td&gt;$0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CloudFront&lt;&#x2F;td&gt;&lt;td&gt;データ転送&lt;&#x2F;td&gt;&lt;td&gt;$0.765&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CloudFront&lt;&#x2F;td&gt;&lt;td&gt;HTTPS リクエスト&lt;&#x2F;td&gt;&lt;td&gt;$0.00225&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;合計&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;$0.78&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</content>
        <summary type="html">メインブログを CloudflareからAWS S3に移行してみました。</summary>
        </entry><entry xml:lang="en">
        <title>AWS SAA再認定</title>
        <published>2024-10-11T00:00:00+00:00</published>
        <updated>2024-10-11T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/10/re-certification-saa/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/10/re-certification-saa/</id>
        
            <content type="html">&lt;p&gt;「SAPじゃなく、3年前のSAAの再認定だし楽勝だ」と思いフラリと受験しました。
3年でサービスも増え出題範囲自体が広くなっており焦りました。しかも、受験してたPC
が途中30分程度フリーズしてPearsonの対応もよくわからないのでぶち切れて帰ると
ころでした。&lt;&#x2F;p&gt;
&lt;p&gt;以前はその場で結果が出ましたが、現在は「5日以内に通知」とされているようで
す。他の合格者の記事を読むと当日の夜21時にメールされてくることが多いようで
す。私の場合まだメールは来ていませんが、Cermetricsの&quot;Exam History&quot;で確認でき
ました。&lt;&#x2F;p&gt;
&lt;p&gt;DeveloperとSysOps AdministratorももうすぐExpireしてしまいますが、これはもう
いいかな。2025年2月までAWS Certified AI Practitionerの再試験の無料キャン
ペーンが行われているようなので、次はこちらを受験しようかなと思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">AWSを離れたのでもう要らないかなと思いましたが、自分を説明するのにSAAくらいは持っていたほうが分かりやすいなと思いSAA再認定を取りました。</summary>
        </entry><entry xml:lang="en">
        <title>OpenAI o1-preview</title>
        <published>2024-09-17T00:00:00+00:00</published>
        <updated>2024-09-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/09/o1-preview/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/09/o1-preview/</id>
        
            <content type="html">&lt;p&gt;Currently evaluating OpenAI&#x27;s o1-preview. Although it is said that it is not
always more accurate than GPT-4o, when checked with the &quot;[World Model](https:
&#x2F;&#x2F;github.com&#x2F;SingularitySociety&#x2F;WorldModels&#x2F;)&quot;. It collects problems that
LLMs struggle with, o1-preview correctly solves questions like the following
that GPT-4o gets wrong.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Q1. What happens if you push a door labeled &quot;Pull&quot; from the opposite side?&lt;&#x2F;li&gt;
&lt;li&gt;Q2. A cotton candy is 8 centimeters tall, and a brick is 7 centimeters tall. If you place the brick on top of the cotton candy, what is the total height?&lt;&#x2F;li&gt;
&lt;li&gt;Q3. I left a wallet on a park bench near Shibuya Station for three hours. On that day, the temperature exceeded 39 degrees Celsius, and the wallet was exposed to direct sunlight. What happens to the wallet?&lt;&#x2F;li&gt;
&lt;li&gt;Q4. Do man-eating tigers live in unexplored jungles?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;OpenAIのo1-previewを現在評価しています。GPT-4oより常に精度が高いわけではないと言われていますが、LLMが苦手な問題を集めた「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SingularitySociety&#x2F;WorldModels&#x2F;&quot;&gt;World Model&lt;&#x2F;a&gt;」で確認すると、GPT-4oで不正解となる次のような問題をo1-previewでは正確に解いてしまいます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Q1.「引く」と書かれたドアを反対側から押すとどうるか？&lt;&#x2F;li&gt;
&lt;li&gt;Q2. 綿菓子の高さは8センチ、レンガの高さは7センチである。綿菓子の上にレ
ンガを置くと、全体の高さは何センチになるか？&lt;&#x2F;li&gt;
&lt;li&gt;Q3. 渋谷駅近くの公園のベンチに財布を3時間置き忘れた。
その日は気温が39度を超え、財布は直射日光にさらされていた。
財布はどうなるか？&lt;&#x2F;li&gt;
&lt;li&gt;Q4. 前人未到のジャングルに人喰い虎は生息しているか？&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">OpenAIのo1-previewを現在評価しています。</summary>
        </entry><entry xml:lang="en">
        <title>生成AIハイプ・サイクル</title>
        <published>2024-09-11T00:00:00+00:00</published>
        <updated>2024-09-11T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/09/ai-hype-cycle/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/09/ai-hype-cycle/</id>
        
            <content type="html">&lt;p&gt;幻滅期に入っているとも言われますが、「マルチモーダル」はAIの使い勝手を劇的に変えてくれます。
すでに業界をリードするOpenAI&#x2F;Microsoft、Google、Anthropicの御三家は「マルチモーダル」をリリース済みですが、やはりOpenAIの使い勝手がよいようでです。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;japan.zdnet.com&#x2F;article&#x2F;35223718&#x2F;&quot;&gt;
  同ハイプ・サイクルにおいて、「マルチモーダル生成 AI」は「オープンソースの
  大規模言語モデル（LLM）」とともに、「早期に採用することで顕著な競争優位性
  と市場投入までの期間短縮をもたらす可能性があるテクノロジー」として取り上げ
  られている。その上で、両技術とも今後 5 年以内に組織に大きな影響を及ぼす可
  能性を秘めているとしている。
  &lt;footer&gt;
    &lt;cite&gt;
      &lt;a href=&quot;https:&#x2F;&#x2F;japan.zdnet.com&#x2F;article&#x2F;35223718&#x2F;&quot;&gt;
        ZDNET - ガートナー、「生成 AI のハイプ・サイクル：2024 年」を発表
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
</content>
        <summary type="html">ガートナージャパンは9月10日、「生成AIのハイプ・サイクル：2024年」を発表したようです。</summary>
        </entry><entry xml:lang="en">
        <title>AWS ALBの脆弱性？</title>
        <published>2024-08-28T00:00:00+00:00</published>
        <updated>2024-08-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/vulnerability-aws-alb/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/vulnerability-aws-alb/</id>
        
            <content type="html">&lt;blockquote&gt;
&lt;p&gt;First, the attacker creates their own ALB instance with authentication
configured in their account. The attacker then uses this ALB to sign a
token they fully control. Next, the attacker alters the ALB configuration
and sets the issuer field to the victim&#x27;s expected issuer. AWS
subsequently signs the attacker&#x27;s forged token with the victim&#x27;s issuer.
Finally, the attacker uses this minted token against the victim&#x27;s
application, bypassing both authentication and authorization.&lt;&#x2F;p&gt;
&lt;p&gt;まず、攻撃者は自身のアカウント内に認証を設定した独自の ALB インスタンスを作成します。
次に、この ALB を使用して、攻撃者が完全に制御できるトークンに署名します。
その後、攻撃者は ALB の設定を変更し、発行者フィールドを被害者が期待する発行者に設定します。
AWS はその結果、攻撃者が偽造したトークンに対して、被害者の発行者として署名を行います。
最後に、攻撃者はこの生成されたトークンを使用して被害者のアプリケーションに対して攻撃を仕掛け、認証と認可の両方を回避します。&lt;&#x2F;p&gt;
&lt;cite&gt;
  [ALBeast Security Advisory by Miggo Research |
  Miggo](https:&#x2F;&#x2F;www.miggo.io&#x2F;resources&#x2F;albeast-security-advisory-alb-vulnerability)
&lt;&#x2F;cite&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;「AWS ALBの脆弱性」と騒がれているけれど、普通にIssuerの検証、JWTトークンの検証、ALBのトラフィックの制限、セキュリティグループの設定をやっていれば関係なくない？「AWS ALBの&lt;strong&gt;ベストプラクティスを無視した間抜けが作ったアプリ&lt;&#x2F;strong&gt;の脆弱性」では？&lt;&#x2F;p&gt;
</content>
        <summary type="html">AWS ALBの脆弱性と騒がれているが・・・</summary>
        </entry><entry xml:lang="en">
        <title>Finaleがフィナーレを迎える</title>
        <published>2024-08-27T00:00:00+00:00</published>
        <updated>2024-08-27T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/finale-discontinued/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/finale-discontinued/</id>
        
            <content type="html">&lt;p&gt;採譜ソフトのFinaleが開発・販売を終了するそうです。&lt;&#x2F;p&gt;
&lt;p&gt;音楽はざっくり言うと作曲-&amp;gt;アレンジ-&amp;gt;採譜-&amp;gt;演奏というプロセスが必要ですが、
「採譜」というプロセスは現代では端折られることも多いし、
何か新しい革新があるわけでもないから「incremental value for our customers」
が無くなったというのは確かにそうなんだろうと思います。&lt;&#x2F;p&gt;
&lt;p&gt;ただ日本のクラシック音楽界隈ではデファクトスタンダードなどで、関係者には
「Finaleがフィナーレを迎えた」などと冗談を言える雰囲気ではないくらい深刻なよ
うです。&lt;&#x2F;p&gt;
&lt;p&gt;The music notation software Finale will be discontinued in terms of
development and sales.
In music, the general process involves:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;composition&lt;&#x2F;li&gt;
&lt;li&gt;arrangement&lt;&#x2F;li&gt;
&lt;li&gt;notation&lt;&#x2F;li&gt;
&lt;li&gt;performance&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;However, the notation process is often skipped in modern times, and since there hasn&#x27;t been any significant innovation in this area, it&#x27;s understandable.
They feel there is &quot;no incremental value for our customers&quot; anymore.
That said, Finale is the de facto standard in Japan&#x27;s classical music community.
So for those involved, it&#x27;s not exactly a laughing matter where they can joke that &quot;Finale has reached its finale.&quot;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
  Today, Finale is no longer the future of the notation industry—a reality after
  35 years, and I want to be candid about this. Instead of releasing new
  versions of Finale that would offer only marginal value to our users, we’ve
  made the decision to end its development.
  &lt;footer&gt;
    &lt;cite&gt;
      {&quot; &quot;}
      the finale blog -{&quot; &quot;}
      &lt;a href=&quot;https:&#x2F;&#x2F;www.finalemusic.com&#x2F;blog&#x2F;end-of-finale-new-journey-dorico-letter-from-president&#x2F;&quot;&gt;
        {&quot; &quot;}
        The End of Finale
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
</content>
        <summary type="html">採譜アプリとして有名なFinaleが開発・販売を修了するそうです。</summary>
        </entry><entry xml:lang="en">
        <title>こだわりのNostr Pubkeyを手に入れる</title>
        <published>2024-08-25T00:00:00+00:00</published>
        <updated>2024-08-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/pubkey-of-nostr/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/pubkey-of-nostr/</id>
        
            <content type="html">&lt;p&gt;NostrでVanity pubkeyのMiningをやってみました。
プリフィックスに&lt;code&gt;yostos&lt;&#x2F;code&gt;と近い&lt;code&gt;y0st0s&lt;&#x2F;code&gt;を得るため、&lt;code&gt;rana&lt;&#x2F;code&gt;を使って数時間Miningしました。&lt;&#x2F;p&gt;
&lt;p&gt;得られた、Pubkeyが&lt;code&gt;npub1y0st0svvu5xg6dvswx7dz5m2p7004kmvsx6n22w4yjp3l6fa3mvsef2zz7&lt;&#x2F;code&gt;で、npub1に続く部分が&lt;code&gt;y0st0s&lt;&#x2F;code&gt;となっています。自己満足ですが。&lt;&#x2F;p&gt;
&lt;p&gt;ranaのインストールと使い方は次の通りです。Rustの実行環境が事前に必要です。&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;cargo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install rana&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;rana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --vanity-n-prefix y0st0s&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;Started&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; mining process for vanity bech32 prefix[es]: &amp;#39;npub1[&amp;quot;y0st0s&amp;quot;]&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (estimated&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pow:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 24&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-entity z-name z-function&quot;&gt;Benchmarking&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; of cores disabled for vanity npub key upon proper calculation.&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;Mining&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; using&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cores...&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;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;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;Vanity npub found: y0st0s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Found matching Nostr public key:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Hex public key: 23e0b7c18ce50c8d359071bcd1536a0f9efadb6c81b53529d524831fe93d8ed9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Hex private key: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Npub public key: npub1y0st0svvu5xg6dvswx7dz5m2p7004kmvsx6n22w4yjp3l6fa3mvsef2zz7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Nsec private key: nsec1@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;2597711770 iterations (about 2x10^9 hashes) in 3433 seconds. Avg rate 756688 hashes&#x2F;second&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;プリフィックスに指定する桁数が増えるほどマイニングに時間がかかるので注意しましょう。上記の例ではM3 MAXのMacbook Proで1時間ほどかかりました。&lt;&#x2F;p&gt;
&lt;p&gt;また、PubkeyはNative SegWit(Bech32)でエンコードされており、小文字でl,b,i,oを除いた32文字しか使えません。これらの文字については数字などに置き換えて指定する必要があります（yostos-&amp;gt;y0st0sなど）&lt;&#x2F;p&gt;
</content>
        <summary type="html">Nostrで自分の好きなPubkeyを入手するためにがんばってみました。</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><entry xml:lang="en">
        <title>AWS CodeCommit新規受付凍結の影響について</title>
        <published>2024-08-13T00:00:00+00:00</published>
        <updated>2024-08-13T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/codecommit-impact/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/codecommit-impact/</id>
        
            <content type="html">&lt;blockquote&gt;
  Amazon&#x27;s recent decision to stop accepting new users for several cloud
  services caught some customers, partners and even a few employees by surprise.
  (Amazon
  が展開中の複数のクラウドサービスについて新規ユーザー登録受付を中止したことで、顧客や協力企業の間で混乱が広がっている。)
  &lt;footer&gt;
    &lt;cite&gt;
      Business Insider -{&quot; &quot;}
      &lt;a href=&quot;https:&#x2F;&#x2F;www.businessinsider.com&#x2F;aws-deprioritized-cloud-services-surprising-customers-salespeople-2024-8&quot;&gt;
        Amazon decision to deprioritize 7 cloud services caught customers and
        even some salespeople by surprise
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;以下の記事は、最近の報道などを見た個人的な意見です。既に中の人ではないので、この件に関しては報道以上の情報は持ち合わせていません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;サービス凍結の状況&quot;&gt;サービス凍結の状況&lt;&#x2F;h2&gt;
&lt;p&gt;同記事によると、次のように説明されている模様です。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;As the public outcry grew, AWS&#x27;s chief evangelist Jeff Barr wrote a short X post on Tuesday to explain that the company decided to &quot;discontinue new access to a small number of services,&quot; but it would continue running them in a secure environment.&lt;&#x2F;p&gt;
&lt;p&gt;関係者から懸念の声が高まったことを受け、AWSのバイスプレジデント兼チーフエバンジェリストを務めるジェフ・バー氏は7月30日のX（旧Twitter）投稿を通じて詳細な事実を説明するとともに、今後の対応を明らかにした。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;これまで使ってきたユーザーはそのまま使用でき、新規ユーザーはGitHubなど別のソリューションを選択すればよいのですぐに何か問題となる訳でありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;新規受付凍結の影響&quot;&gt;新規受付凍結の影響&lt;&#x2F;h2&gt;
&lt;p&gt;この変更により直近大きな影響はなさそうですが、顧客としては不安でしょう。&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;aws.amazon.com&#x2F;jp&#x2F;blogs&#x2F;devops&#x2F;how-to-migrate-your-aws-codecommit-repository-to-another-git-provider&#x2F;&quot;&gt;AWSのブログ&lt;&#x2F;a&gt;でリポジトリーの移行方法が紹介されていますが、CodeCommitやCloud9などのツールは開発プロセスの中に組み込まれて使用しているので、最低でも次のような対応が必要です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;リポジトリーの移行&lt;&#x2F;li&gt;
&lt;li&gt;ユーザーの移行&lt;&#x2F;li&gt;
&lt;li&gt;CI&#x2F;CDの組み直し&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;ul&gt;
&lt;p&gt;ちょっとした組織横断のプロジェクトになりそうです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;何が悪かったのか？&quot;&gt;何が悪かったのか？&lt;&#x2F;h2&gt;
&lt;p&gt;第一の問題は、AWSがCodeCommitやCloud9のサービスの重要性をAWSが図り損ねたことでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;想像するに、CodeCommitやCloud9はそれほど利用者が多くなかったのでしょう。
ユーザーの利用度が低い、サービス提供側から見ると金を生まないサービスを統廃合していくのは当たり前の話です。&lt;&#x2F;p&gt;
&lt;p&gt;これが本番環境のRuntimeだけに関わる問題であれば、ここまでの問題にならなかったかもしれません。
ところが、CodeCommitやCloud9などは企業ITの組織やプロセスに深く関わるので、サービスの移行だけでなく人やプロセスの移行も必要です。
少数かもしれませんが、AWSを信じてCodeCommitやCloud9を利用していた企業は多大な移行コストが必要となります。&lt;&#x2F;p&gt;
&lt;p&gt;その認識がAWSには足りてなかったのではないかと思います。
アプリ開発の側の人だったので偏見かもしれませんが、どうもインフラ屋さんというのはこういう部分のセンスが足りていないのではないかと思うことがよくあります。&lt;&#x2F;p&gt;
&lt;p&gt;結果として、Business Insiderが報じるよう、AWS自身も以下のようは羽目になってしまっています。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The company is trying to keep supporting clients while signaling that these offerings are no longer a strategic priority.&lt;&#x2F;p&gt;
&lt;p&gt;同社は、これらのサービスがもはや戦略的優先事項ではないことを示しながら、顧客のサポートを続けようとしている。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;2点目は、これらの決定に至るAWS社内での連携の問題でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;AWS CLIの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;aws&#x2F;aws-cli&#x2F;blob&#x2F;v2&#x2F;CHANGELOG.rst&quot;&gt;CHANGE LOG&lt;&#x2F;a&gt;を見ると、7月26日にCommitされた2.17.18のコメントに以下のように記述されています。これを受けて一部の顧客が気付いて徐々に騒ぎが大きくなっていったようです。&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;api-change:`codecommit`: CreateRepository API now throws OperationNotAllowedException when the account has been restricted from creating a repository.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;実際には6月6日から新規顧客への制限を加えていたという話もあります。当然これらの決定は更に数ヶ月前には行われていたことでしょう。一方でBusiness Insiderが報じるようにAWS内部でも十分に周知されないまま決定されたようです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It turns out that even some of Amazon&#x27;s own salespeople were not aware of the change until after it was made public late last week.&lt;&#x2F;p&gt;
&lt;p&gt;なお、アマゾンの営業部門の中には事前に何も聞かされておらず、同社が先週末に受付中止を公表した時点で初めてその事実を知った従業員が複数いることも分かった。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;アグレッシブな機能の改善は美点でもあり機能やサービスをどんどん追加している時はよかったかもしれませんが、ある程度利用が定着した段階に入っているこれからはこれまでのようなカジュアルな変更は難しいのかもしれません。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Business Insider などを読んでいるとAWSのCodeCommitやCloud9の新規受付凍結は、米国でもかなり問題になっている模様。</summary>
        </entry><entry xml:lang="en">
        <title>Software Development Using Generative AI</title>
        <published>2024-08-09T00:00:00+00:00</published>
        <updated>2024-08-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/software-development-using-ai/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/software-development-using-ai/</id>
        
            <content type="html">&lt;p&gt;日本語は下の方に。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Dramatic_Cost_Reduction&quot;&gt;Dramatic Cost Reduction&lt;&#x2F;h2&gt;
&lt;p&gt;The use of generative AI has dramatically reduced the costs of producing images and music.
For example, tasks like illustration creation and music creation (using services like Udio and Suno) previously required specialists.
These tasks can now be done by individuals in about five minutes using generative AI-powered services.&lt;&#x2F;p&gt;
&lt;p&gt;In software development, the use of generative AI for development support is also spreading.
Many developers are likely using tools like Github Copilot.&lt;&#x2F;p&gt;
&lt;p&gt;However, applications of generative AI in software development are progressing beyond mere coding support.
For example, I recently changed the static site generator for my main blog, which required converting the metadata of several hundred articles.
I wrote a conversion program in Python.
But by providing ChatGPT with the prerequisites and requirements, I only needed to make about 10% modifications to the generated code.&lt;&#x2F;p&gt;
&lt;p&gt;This example shows that generative AI can shoulder not only development support but also the creation of software itself.
It is similar to image and music production.
In the example above, what would have taken about two weeks if outsourced to a development vendor was reduced significantly.
This reduction brought the work down to about 30 minutes using generative AI.&lt;&#x2F;p&gt;
&lt;p&gt;The cost is only 0.6%.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;What_Generative_AI_Software_Development_Brings&quot;&gt;What Generative AI Software Development Brings&lt;&#x2F;h2&gt;
&lt;p&gt;The rationale for traditional software development was that it could reduce the
workload of many people through repeated use. Therefore, single-use software
development for specific users was not permitted.&lt;&#x2F;p&gt;
&lt;p&gt;However, there is a world where single-use software development has been
allowed: the realm of data science. This is because of the unique nature of
datasets and the need for trial and error, where speed is prioritized over
reuse. The most significant reason is that the benefits gained from single-use
software development outweigh the costs.&lt;&#x2F;p&gt;
&lt;p&gt;By leveraging generative AI, it becomes possible to reduce costs in general
software development similarly. This means that even single-use software
development for one user, which does not contribute to reducing the workload of
many, becomes feasible.&lt;&#x2F;p&gt;
&lt;p&gt;In other words, we are entering an era where problems that could be solved by software but were left unaddressed due to development costs.
These problems can now be resolved quickly using generative AI for software development.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, when you ask ChatGPT a question like &quot;What is the date 100 days after August 9, 2024?&quot;, a single-use Python code is generated.
This specialized code is executed behind the scenes to solve this specific problem.&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-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&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; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; timedelta&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;# Starting date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;start_date&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; datetime&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;2024&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-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;&#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;# Calculate the date 100 days later&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;end_date&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; start_date&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; timedelta&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;days&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;100&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;end_date&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;strftime&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;%Y-%m-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&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;h2 id=&quot;Differences_from_RPA_and_No-Code&quot;&gt;Differences from RPA and No-Code&lt;&#x2F;h2&gt;
&lt;p&gt;Similar technologies include RPA and no-code solutions. Many companies have
adopted these technologies, riding the wave of the DX trend.&lt;&#x2F;p&gt;
&lt;p&gt;Both have the effect of lowering software development costs, but there are
significant differences in their technology and implementation effects.&lt;&#x2F;p&gt;
&lt;p&gt;From a technical perspective, generative AI software development involves custom development by AI according to requirements.
RPA and no-code solutions appear to meet user requests, but in reality, only pour parameters into pre-made software provided by vendors.
Therefore, what can be achieved must be based on the templates of the pre-made software.&lt;&#x2F;p&gt;
&lt;p&gt;More importantly than these technical differences is the impact of their implementation.
In many cases with RPA and no-code solutions, user departments develop the software themselves.
This happens when they become frustrated with waiting for the development department.&lt;&#x2F;p&gt;
&lt;p&gt;This means that non-developers are creating reusable software, or corporate software assets, which is a nightmare.
Years later, the software will likely become a maintenance burden due to the users&#x27; transfer or the vendors&#x27; product lifecycle.&lt;&#x2F;p&gt;
&lt;p&gt;In contrast, single-use software development using generative AI emphasizes the outcomes rather than the software itself.
Thus, the specifics of the software do not matter.
Even so, a verifiable artifact in the form of &quot;source code&quot; is created, making it a completely transparent process (white box).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Seeing companies that claim to have achieved &quot;DX&quot; by introducing RPA and no-code solutions gives me chills.
In contrast, companies should recognize the new application methods of software development.
These methods allow generative AI to be used to solve problems on the spot, similar to the approach taken by data scientists.
This approach is similar to the methods employed by data scientists.&lt;&#x2F;p&gt;
&lt;p&gt;In such a world, engineers with the ability to read source code will become
increasingly necessary. Companies currently investing in RPA and no-code
solutions should be cautious, as they may be going against the trend.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;劇的なコスト削減&quot;&gt;劇的なコスト削減&lt;&#x2F;h2&gt;
&lt;p&gt;生成系AIの活用により、画像や音楽の制作コストが劇的に削減されています。例えば、
これまで専門家に依頼しなければならなかったイラスト作成（MidjourneyやDALL-E 2な
ど）や音楽作成（UdioやSunoなど）を、生成系AIを取り入れたサービスを使うことで、
自分で5分ほどで望みの画像や音楽を制作できます。&lt;&#x2F;p&gt;
&lt;p&gt;ソフトウェア開発においても、生成系AIを活用した開発支援が広がってきています。実
際に、Github Copilotのようなツールを使用している開発者も多いでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、これらのコーディング支援とは別の次元で、ソフトウェア開発への応用も進ん
でいます。例えば、最近私はメインブログの静的サイトジェネレータを変更しました
が、それに伴い記事のメタデータの変換が必要でした。数百ある記事の変換プログラム
をPythonで書きましたが、ChatGPTに前提と要件を伝えて生成されたコードをベースに、
10%程度の修正するだけで済みました。&lt;&#x2F;p&gt;
&lt;p&gt;これは、開発作業の支援だけでなく、画像や音楽の制作と同様にソフトウェア制作その
ものを生成系AIに肩代わりさせることができる例です。上記の例では、開発ベンダーに
依頼すると2週間ほどの時間がかかるところを、生成系AIを使って自分でコードを作成す
れば30分程度で済みます。&lt;&#x2F;p&gt;
&lt;p&gt;コストは0.6%で済んでしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;生成系AIによるソフトウェア開発がもたらすもの&quot;&gt;生成系AIによるソフトウェア開発がもたらすもの&lt;&#x2F;h2&gt;
&lt;p&gt;従来のソフトウェア開発のRationale（根拠）は、何度も使用されることで多くの人の作
業を軽減できることにありました。そのため、特定のユーザーのための使い切りのソフ
トウェア開発は許されませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、使い切りのソフトウェア開発が許されてきた世界があります。それはデータサ
イエンスの領域です。これは、データセットの特異性やそれに伴う試行錯誤の必要性、
再利用より迅速性が重視されたためです。最も大きな理由は、使い切りのソフトウェア
開発のコストに対して得られる成果が大きいからです。&lt;&#x2F;p&gt;
&lt;p&gt;生成系AIを活用すれば、一般的なソフトウェア開発でも同様にコスト削減が可能とな
り、多くの人の作業軽減に貢献しない、一人のユーザーのためだけの使い切りのソフト
ウェアを開発することも可能になります。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、これまで開発コストを理由にソフトウェアで解決出来る問題が放置されていた
状況を「生成系AI使って、ささっとソフトウェア開発をして解決すればよい」という時
代になってきていると感じます。&lt;&#x2F;p&gt;
&lt;p&gt;実際、ChatGPTで「2024年8月9日の100日後は何日？」というような質問の回答を作るの
に、裏では以下のようはこの問題に特化した使い切りのPythonコードが生成されて実行
されています。&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-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&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; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; timedelta&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;# Starting date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;start_date&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; datetime&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;2024&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-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;&#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;# Calculate the date 100 days later&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;end_date&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; start_date&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; timedelta&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;days&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;100&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;end_date&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;strftime&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;%Y-%m-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&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;h2 id=&quot;RPAやノーコードとの違い&quot;&gt;RPAやノーコードとの違い&lt;&#x2F;h2&gt;
&lt;p&gt;似たような技術にはRPAやノーコードがあります。DXの流行に乗って、これらを導入した
企業も多いと思います。&lt;&#x2F;p&gt;
&lt;p&gt;どちらもソフトウェア開発コストを下げるという効果がありますが、その技術と導入効
果の面で大きな違いがあります。&lt;&#x2F;p&gt;
&lt;p&gt;技術面で見ると、生成系AIによるソフトウェア開発では要件に従いAIよるソフトウェア
のカスタム開発が行われています。しかし、RPAやノーコードではユーザーのリクエストに沿っ
て必要なソフトウェアを実現しているように見えますが、実際にはベンダーが用意した
ソフトウェアにパラメータを流し込んでいるだけです。そのため、実現できることもあ
らかじめ用意されたソフトウェアのひな形を意識した要件に落とし込む必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;こういった技術的な違いよりも、問題はその導入効果です。
RPAやノーコードで多く行われているのは、開発要望が開発部門のバックログ
いつまでも実現されないと
業を煮やしたユーザー部門が自身で開発するというパターンです。これは使い回すソフト
ウェア、つまり企業のソフトウェア資産を開発者でない素人が開発してしまうことを意
味します。悪夢でしかありません。数年後には開発したユーザーの異動やベンダーの製
品ライフサイクルから、メンテナンスできないソフトウェアという負の遺産になってい
ることでしょう&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;一方で生成系AIによる使い切りソフトウェア開発は生成したソフトウェアそのもので
はなく成果が重視されるため、どのようなソフトウェアだったかは問題になりま
せん。それでも、「ソースコード」という検証可能な成果物が作成されるため、完全に
透明な状態（ホワイトボックス）です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;RPAやノーコードのソリューションを導入して「DX実現」としている企業の将来を思うと
暗い未来しか想像できません。&lt;&#x2F;p&gt;
&lt;p&gt;一方で従来のソフトウェア開発とは異なる、これまでデータサイエンティストが取り組
んできたようなアプローチ、つまるソフトウェア開発によるその場の問題解決が生成系
AIを使うと可能になるので、新しいソフトウェアの応用方法として企業はしっかりと認
知すべきだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;こういった世界ではソースコードを読む能力を持ったエンジニアはますます必要になっ
てくるので、そういった意味でもRPAやノーコードに取り組んでいる企業は逆流している
ので気をつけたほうがよいと思います。&lt;&#x2F;p&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;「サーバー型RPAならば集中管理できてそうはならない」という意見もあり
ます。それならばIT部門が開発して管理すればよくベンダー依存のランタイム
上でシステムを構築する意味がないのではないでしょうか？　もっともここに
AIを応用すると世界が変わる可能性はありますが、現時点ではまだ予測不能で
す。 &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">Recently, I had a conversation with someone about software development using ChatGPT, and a few things caught my attention. I decided to summarize my thoughts here.</summary>
        </entry>
</feed>
