Claude Fable が会計アプリを1セッションで自律完成させた記録

2026.07.12 約 18 分で読めます

最上位モデルの Claude Fable 5 に、freee を参考にした個人事業主向けの会計アプリを作らせてみました。指示は最初にまとめて3問だけ。あとは人が口を挟まないまま、複式簿記から決算書・請求書・銀行明細の取り込みまでが、ひと続きの作業で動く形になりました。できあがったコードと、私が実機で試した結果から、なぜ自律で品質が保てたのかを分解します。

結論:1セッションで会計アプリが動いた。効いたのは3つの地味な習慣

結論から言うと、Claude Fable 5 の会計アプリは、ひとつの作業セッション(人が新しい指示を挟まない、ひと続きの作業)で最後まで動きました。仕訳の入力、総勘定元帳、青色申告方式の決算書、請求書の発行と入金、銀行 CSV の取り込みまで。13の画面と、その裏で動く14のサーバー処理。そこそこの規模です。

正直、動くだけなら驚きません。驚いたのは、壊れにくさのほうでした。できあがったコードを読み、私自身が実機で試して分かった「効いた習慣」は、大きく3つです。

  • コードを書く前に、不確かな前提を先に潰す(環境の確認・技術の1行検証・データの決まりごとの固定)
  • 答えを先に手で計算してから、画面と1円単位で突き合わせる
  • エラー処理や画面の枠を、最初に1つずつ部品にして、すべての画面で使い回す

この3つは、腕のいい人間の開発者がやっていることと同じです。特別な魔法ではありません。ただ、AI がそれを頼まれずに最後までやり切ったのが、今回のいちばんの発見でした。ひとつずつ、実物のコードと画面で見ていきます。

先に前提を1つ。このアプリの制作履歴は、バージョン管理上は「最初のコミット」1件しか残っていません。つまり、作っていく途中経過はコミット履歴からは追えません。ここで書く「制作の判断」は、作業中の記録と、できあがったコードを突き合わせて裏を取ったものです。

何を作ったか:freee を参考にした複式簿記アプリ

お題は「会計 freee と同等のものを自分用に」。それに対して Claude Fable 5 は、最初に用途・v1で入れる機能・使う形態の3問だけを確認しました。そこから先はゼロ質問で、作り切っています。できあがったのは、次のような構成です。

中身
画面(ページ)13取引入力・仕訳帳・総勘定元帳・決算書・請求書・取引先・設定・明細の取込 ほか
API(サーバー処理)14仕訳・請求書・明細・開始残高・勘定科目 などの登録/取得
共通ロジック(lib)8会計計算・仕訳の検証・CSV解析・請求書・フォーマッタ
画面部品(components)24入力フォーム・一覧・グラフ・サイドバー など
技術構成は Next.js 16.2.10 / React 19.2 / TypeScript 5 / SQLite(better-sqlite3 12・SQLite をアプリから使うためのライブラリ)。データはすべて手元の1ファイルに保存され、外部には出ない設計。

複式簿記というのは、1件の取引を「借方(左)」と「貸方(右)」の両側に同じ金額で記録して、必ず左右が一致する会計の書き方です。ここが1円でもズレると、決算書がすべて狂います。会計アプリの心臓部が、この一致をどう守るか。そこに制作の質が出ます。

まずは、できあがった仕訳帳を見てください。開始残高、現金売上、請求書の発行と入金、銀行明細からの取り込み——出どころのちがう取引が、すべて借方と貸方のそろった形で並んでいます。請求書や明細から自動で作られた仕訳には、右側に小さなタグが付いています。

Claude Fable 5 が作った会計アプリの仕訳帳画面。開始残高・現金売上・請求書の発行と入金・銀行明細の取込が、借方と貸方のそろった複式の形で日付順に並び、請求書・明細・開始残高のタグが付いている
仕訳帳。請求書の発行(売掛金/売上高)や入金(普通預金/売掛金)、明細の取り込みが、すべて自動で複式の仕訳になっている。

判断①:コードを書く前に、不確かな前提を潰していた

いちばん人間くさかったのが、ここです。Claude Fable 5 は、いきなり機能を書き始めませんでした。先に、後で事故になりそうな前提を1つずつ確かめています。

  • 環境の確認:手元の Node(アプリを動かす土台)のバージョンを確認。
  • 技術の1行検証:SQLite を使うライブラリが、そのバージョンで本当に動くかを、アプリを書く前に1行のコマンドで実証。
  • データの決まりごとを先に固定:金額は整数の円、日付は「YYYY-MM-DD」の形、と最初に決めて、あり得ない値はデータベース側で弾く。

3つ目が効いています。データベースの定義そのものに、「この値以外は保存させない」という決まり(CHECK 制約)を先に埋め込んでいました。たとえば金額は必ずプラス、記帳の左右は「借方か貸方」だけ、勘定科目の区分は決まった5種類だけ、という具合です。

amount   INTEGER NOT NULL CHECK (amount > 0),            -- 金額は必ずプラス
side     TEXT    NOT NULL CHECK (side IN ('debit','credit')),  -- 左右はこの2つだけ
category TEXT    NOT NULL CHECK (category IN
           ('asset','liability','equity','revenue','expense')) -- 区分は5種類だけ

そして肝心の「借方と貸方の一致」は、保存する直前にサーバー側で必ずチェックし、合わなければ日本語のメッセージを出して止めます。画面のバリデーションだけに任せず、いちばん奥で守っているのがポイントです。

if (debit !== credit) {
  throw new Error(
    `借方合計(${debit.toLocaleString()})と貸方合計(${credit.toLocaleString()})が一致していません`
  );
}

青色申告の決算書には、もう一段ややこしい約束事があります。事業主の私的な出し入れ(事業主貸・事業主借)は当年ぶんだけを表に出し、前年より前の損益は「元入金」という項目にまとめて繰り越す、というものです。ここを曖昧なまま組むと、決算書の左右が合わなくなって、原因探しで何日も溶かします。制作の記録では、この左右が必ず一致することを、実装の前に筋道立てて確かめていました。実際、できあがったコードでも、資産の合計と「負債+資本+所得」の合計が、簿記の仕組み上いつも一致する形で計算されています。

判断②:答えを先に手計算し、画面と1円まで突き合わせた

ここが今回いちばん真似したい手法です。検証のとき、Claude Fable 5 は画面を先に見ませんでした。先に正解を手で計算しておき、あとから画面と突き合わせます。その順番です。制作の記録では、全取引を入れたあとの貸借対照表を「927,700円で一致するはず」と、画面を見る前に計算していました。そのうえで、1円単位で合うことを確認しています。

この手法、言葉だけだと伝わりにくいので、私が同じやり方で追試しました。まず用語を1つ。「貸借対照表」は、ある時点の財産の状態を、左に資産・右に負債と資本を並べて示す表です。複式簿記が正しく積み上がっていれば、左右の合計は必ず一致します。

方法:できあがった会計アプリに、合成のダミーデータ(実在しない架空の取引・個人情報なし)を、すべて実際の登録処理を通して入れました。開始残高、現金売上、経費、請求書の発行と入金、銀行明細の取り込み4件。そのうえで、貸借対照表の合計を先に手で計算しました。資産は現金358,000円と普通預金886,500円で合計1,244,500円。負債・資本は借入金300,000円・元入金650,000円・当年の所得294,500円で、これも合計1,244,500円。結果は、次のとおりです。

会計アプリの貸借対照表画面。資産の部は現金358,000円・普通預金886,500円で資産合計1,244,500円、負債・資本の部は借入金300,000円・元入金650,000円・所得294,500円で負債・資本合計1,244,500円と、左右がぴったり一致している
貸借対照表。手計算した1,244,500円と、画面の左右の合計が1円単位で一致した。下の注記も青色申告方式(事業主貸借は当年ぶん・前年損益は元入金へ繰越)どおり。

手で出した1,244,500円と、画面の資産合計・負債資本合計が、ぴったり同じ。左右も一致。地味ですが、これが会計アプリの「正しさ」の芯です。答えを先に用意しておくと、ズレた瞬間に気づけます。画面の数字を見てから「合ってそう」と判断するのとは、確からしさがまるで違いました。

ひとつ正直に断っておきます。私が出した1,244,500円は、この記事のために別に用意したダミーの取引による数字です。制作時の927,700円とは別のデータで、金額そのものは一致しません。制作時のテストデータはアプリを仕上げた際に消されていて、そのままの再現はできないためです。ここで見せたかったのは金額ではなく、「先に手で答えを出してから突き合わせる」という検証のやり方が、実機でもきちんと通る、という点です。

判断③:エラー処理を1か所にまとめ、すべての入り口で同じにした

数が増えると、書き方のばらつきが、そのまま品質のばらつきになります。Claude Fable 5 は、それを先回りしていました。たとえばエラーの扱い。ふつうに書くと、処理ごとにエラーの返し方がバラバラになりがちです。そこで、まず「エラーをまとめて受け止める部品」を1つ用意し、14本のサーバー処理すべてをその中に通していました。何か失敗しても、画面が真っ白に落ちるのではなく、日本語のメッセージがきちんと返る。その受け止め方が、どの処理でも同じになります。

export async function handle<T>(fn: () => T | Promise<T>): Promise<NextResponse> {
  try {
    const data = await fn();
    return NextResponse.json(data ?? { ok: true });
  } catch (e) {
    const message = e instanceof Error ? e.message : "エラーが発生しました";
    return NextResponse.json({ error: message }, { status: 400 });
  }
}

これが最初に1つあるだけで、あとのサーバー処理は「中身」だけ書けば済みます。エラーの返し方がぶれません。あとで直すときも、この1か所を直せば14本すべてに効きます。同じ発想で、画面のカードや見出し、金額・日付の表示も、先に部品を作って全画面で共有していました。どの画面も同じ作りでそろっているので、あとから読むのも直すのも迷いません。

実際に出たバグと、直し方:症状の場所と原因の場所は違う

うまくいった話ばかりだと嘘くさいので、詰まったところも。銀行明細の取り込みで、実際にバグが出ています。

症状:CSV を取り込んだ直後、勘定科目の自動提案がすべて空になる。やったこと:まず提案のロジック自体は正しいと確認(事実集め)。そのうえで、1つ仮説を立てました。「画面の状態を保持する仕組み(React の state)の初期化は、最初の1回しか走りません。だから取り込みで明細が増えても、増えたぶんの提案が計算されないのでは」。マウントのタイミングを確認して、この仮説を採用しました。直し方は、行の状態を最初にまとめて作らず、参照された時点で毎回その場で作る形に変えることでした。

// refresh で明細が増えても提案が効くよう、行の state は参照時に遅延生成する
const getRow = (t: BankTxn): RowState =>
  states[t.id] ?? {
    account_id: String(suggest(t.description) || ""),  // ← その場で提案を計算
    description: t.description,
    keyword: "",
  };

教訓は、コメントにも残っていました。症状が出た場所(提案が空)と、原因の場所(状態の初期化のタイミング)は違う。フレームワークの前提を、仮説の材料に入れる。これは人間のデバッグの定石そのものです。

もう1つ、検証中に見つかった穴も直っていました。銀行明細の摘要は、全角カタカナで届くことがあります。「トウキヨウデンリヨク」のような表記です。ところが最初の科目キーワード辞書には、拗音のある「デンリョク」しか入っておらず、拗音のない「デンリヨク」に当たりませんでした。実データの形で検証したことで、この漏れに気づき、カタカナの変種を辞書に足しています。できあがった取り込みパーサ(解析処理)を、私がそのまま Shift_JIS(Windows で多い日本語の文字コード)風のダミー明細に流したのが、これです。

=== 列の自動検出 ===
{ dateCol:0, descCol:1, amountMode:"expense_only", hasHeader:true }

=== 明細の解析 + 科目の自動提案 ===
2026-06-05  トウキヨウデンリヨク       出金6,500円  → 水道光熱費   ← 拗音なし変種に命中
2026-06-12  ドコモ携帯料金             出金4,200円  → 通信費
2026-06-20  JRヒガシニホン モバイル…   出金1,500円  → 旅費交通費
2026-06-25  アマゾンウェブサービス     出金3,300円  → 消耗品費

列の見出しから「日付・摘要・出金」の位置を自分で当て、Shift_JIS を読み分け、摘要から科目まで提案する。取り込み画面で見ると、未処理の明細に科目があらかじめ入った状態で並びます。さきほどの state のバグを直したからこそ、この提案が最初から効いています。

会計アプリの明細の取込画面。未処理3件(トウキヨウガスリヨウキン・ソフトバンクモバイル・クロネコヤマトタクハイビン)に、それぞれ水道光熱費・通信費・荷造運賃の勘定科目が自動提案であらかじめ選択されている
明細の取込画面。カタカナ摘要から科目(水道光熱費・通信費・荷造運賃)が自動でプリセットされている。あとは確認して登録するだけ。

まとめ:Fable に会計アプリを任せてみた感想

まず、率直な感想を。ここまで自分で走り切るとは、正直思っていませんでした。良かったところと、物足りなかったところを分けます。

良かったところは、このあたりです。

  • 最初に3問確認しただけで、複式簿記から決算書・請求書・銀行明細の取り込みまでを、途中で止まらず動く形にした。
  • 頼んでいない検証まで自分でやる。答えを先に手で計算して1円まで合わせ、あり得ない値を弾き、実データの形でキーワード辞書の穴まで見つけた。
  • 取り込みで出たバグを、症状ではなく原因まで切り分けて自分で直した。
  • 数が増えても作りがそろっていて、あとから読みやすい。決算書の左右が1円まで合う——その芯を最後まで守っていた。

いっぽうで、物足りない・気をつけたいところもありました。

  • 作っていく途中経過が残らない。「なぜこう作ったか」を、あとから履歴で追いにくい。任せきりにするなら、途中の記録を別に残す運用が要ります。
  • 会計のように間違えられないものは、最後に人が数字を確かめる工程は残したい。一発で仕上がるぶん、人が止めるポイントが減ります。
  • 要件がはっきりしているほど強い。裏を返せば、決めきれていないお題には向かない。今回ほどきれいには効かないはずです。

総じて、答えが決まっている実務アプリを、要件だけ渡して一気に形にする。この使い方との相性が、今回いちばんの収穫でした。仕様の固まった社内ツールや、個人事業の定型業務あたりは、特に向いていそうです。同じように「AI にどこまで実務アプリを任せられるか」を自社の開発で見極めたい場合は、導入支援・技術相談も受けています。

この記事は、Claude Fable 5 を追いかける連載の2本目です。1本目は、同じ Fable 5 と半額の Opus 4.8 に同じお題を素の状態で作らせて、素の実力を比べています(Claude Fable 5 と Opus 4.8 を実測比較)。ほかの実装・精度検証の記事は AI・LLM開発 のカテゴリにまとめています。次の3本目では、この Fable の進め方を手順とチェック項目にまとめて Opus 側に持たせ、別の新しいお題で差が埋まるかを試します。

こま

こま

元SE × AI開発 × 業務自動化の実践者

SE 4年 + プログラミング歴 8年。業務自動化と AI 組み込み開発を仕事にしながら、現場で使えるものだけを書いています。 最新のAIの現場を発信中!!