🚄

Cline(Roo Code)を暴走列車にしたら4日間で数ヶ月分のコードが生成できた

に公開1

アイコンが変わったerukitiです。最近はやりのgpt-4o image generationを使って、顔だけだったアイコンに全身が追加されました。2023年4月10日に初めてのLLMプロダクトの開発キックオフからもうすぐで二年です。rat yearなこの業界なんで、変化がめまぐるしすぎますね。

今回は、真に高速なAIコーディングのメソッドを確立するために、中規模くらいのコードをコーディングエージェントのみに書かせる実験をしています。コーディングエージェントはCline派生であるRoo Code(以後Rooと呼ぶ)を使っています。

※完全に個人研究としてやっているため、会社のリソースは使っていません。

  • 作っているものはコーディングエージェントのコアライブラリ + おまけのCLI
  • 規模としては136ファイル・26410行(一時期30000行弱までいった)

なぜコーディングエージェントを使って、コーディングエージェントを作ってるの?と言われそうですが、僕の本業はAIエージェント開発なので、既存のコーディングエージェントに対して「こう設計すればいいのに」が山ほどあったため、それを実際に実験したかったのが動機です。こういったやりたいことは他にも色々あり、別のリポジトリでそれぞれ検証をしています。

これまでは、こういうのは思ってたとしてもなかなか実装には移れないものでしたが、なんせ4日間程度でそれなりなレベルのモノができる時代になってしまいました。

コーディングエージェントのノウハウが体系化され、今よりもう少しコスパよくやれる頃には、「思いついたアイデアを実装しないなんてあり得ない」という世界観に移行しているでしょう。

ただし今回の4日間で開発したコードは、技術的負債が尋常じゃなく積み上がっていて、技術的負債の解消に要した期間は4日以上だったことをご報告申し上げます。おおよその技術的負債の解消ができたので記事にしました。

https://x.com/erukiti/status/1905274681890103755

この記事から学べることは

  • コーディングエージェントは短期間で大量のコード生成が可能だが、技術的負債も急速に蓄積するため、定期的で小粒度な負債解消が必須。
  • 技術的負債解消をAIに任せる場合、「一度にひとつの明確な課題」だけに集中させ、作業を必ず完結させる方法が効果的である。
  • AIエージェントは既存コードを「正」として模倣し増殖させる傾向があるため、初期のコード品質確保と明確な制約指示が重要となる。
  • モデルやプロンプトの複雑性が技術的負債の増減に強く影響するため、シンプルな指示や適切なモデル選定が必要である。

といったところでしょうか。

なお、個人的な面白ポイントは

  • たった数日で、「とんでもない技術的負債について実感する」なんていう経験ができる
  • たった数日で、そのとんでもない技術的負債を解消できる
  • たった数日で、様々な実験ができる、とても良質な実験用資産ができあがる

です。

このスピード感は、パラダイムシフトの証です。

https://note.com/erukiti/n/n9151d9636b80

レギュレーション

技術検証なのでいくつものレギュレーションがあります。

  • 基本的にRooが動いている間は他のことをする。最近はやりの高速目grepはしない
  • なるべく人間はリポジトリをいじらない
  • 実際の動作を正義とする
  • 初期からあまりあれこれ知識をぶち込まない
  • 基本的にはノリと運で乗り切るVibe Coding!

人間が楽をするための方法論を確立するために、極端なポリシーでやっています。

今回使ったルールファイル

`.clinerules`
# Project Rules

This guide outlines the best practices, conventions, and standards for development using modern web technologies.

**Always adhere to these guidelines**

## Environment

- Use bun
- Use bun test for unit tests

## Development Philosophy

- Write clean, maintainable, and scalable code
- Follow the principles of SOLID
- Prioritize functional and declarative programming patterns over imperative ones
- Emphasize type safety and static analysis
- Practice component-driven development

## Code Implementation Guidelines
### Code Style

- Eliminate unused variables
- Always handle error parameters in callbacks

### Naming Conventions

- Use PascalCase for:
  - Components
  - Type definitions
  - Interfaces
- Use kebab-case for:
  - Directory names (e.g., components/auth-wizard)
  - File names (e.g., user-profile.tsx)
- Use camelCase for:
  - Variables
  - Functions
  - Methods
  - Hooks
  - Properties
  - Props
- Use uppercase for:
  - Environment variables
  - Constants
  - Global settings
- Prefix boolean variables with a verb: isLoading, hasError, canSubmit
- Except for the following, use complete words instead of abbreviations:
  - err (error)
  - req (request)
  - res (response)
  - props (properties)
  - ref (reference)

### TypeScript Implementation

- Enable strict mode
- Follow verbatimModuleSyntax
- Use type guards to safely handle potential undefined or null values
- Use generics appropriately
- Use the unknown type appropriately
- Leverage TypeScript utility types (Partial, Pick, Omit) for cleaner and more reusable code
- Use mapped types to dynamically create variants of existing types
- Do not use TypeScript-specific syntaxes such as enum

### ES Modules

- When importing Node.js APIs, use the node: prefix (e.g., "node:fs")

### Unit Tests
- Place unit tests in the same directory as the file under test (e.g., foo.test.ts for foo.ts)
- Write thorough unit tests to verify individual functions and components
- Follow patterns like Arrange-Act-Assert to ensure clarity and consistency in tests
- Mock external dependencies and API calls to isolate unit tests

## Documentation
- Write TSDoc appropriately in Japanese
- Document all public functions, classes, methods, and interfaces
- Leave appropriate comments in Japanese
- Add examples where applicable
- Use complete sentences with appropriate punctuation
- Keep explanations clear and concise
- Use proper Markdown formatting
- Use appropriate code blocks
- Use proper links
- Use appropriate headings
- Use appropriate lists

設計のときのルールと、実装のときのルールを分割した方が良かったなーとは思っています。ルールファイルは他の人も書いている通り、シンプルな方が良いです。

実装の4日間でやったこと

新しいリポジトリでは、まっさらな状態から「bun initして」という指示から始めました。なので環境セットアップもRoo任せです。

  • TypeScript runtimeとしてbunを使用
  • ユニットテストはbun testを使用
  • ライブラリは依存しない(未だにdependenciesは空です)

さて、開発の基本的な手順は次の通りです。

  1. 新しいタスクを開始して、Architectモード(Rooにおける設計のみが許可されたモード)で、参考資料や僕の用意したプロンプトを元に、具体的な設計をさせて、memory-bankを作成・更新する
  2. 新しいタスクを開始して、Architectモードで「次のタスクはわかる?」と聞いて、memory-bankを参照させて、Rooの認識を一通り聞いた後に大丈夫そうなら、Codeモード(Rooにおける実装できるモード)に切り替えて実装をさせます。大丈夫じゃなければ、そのまま設計を続けさせるか、なかったことにして、最初からリトライをします
  3. 2の終了時に、ユニットテスト、型チェックをしてない場合は手動でチェックして「型エラーあんぞ」「ユニットテスト壊れてんぞ」と優しく伝えてあげて修正させる

これをひたすら繰り返す感じです。

https://www.google.com/search?q=memory-bank+Cline

1番の設計のときに、食わせるものは

  • ウェブ上の資料(たとえばAnthropic APIドキュメントなど)
  • 僕が作った設計や資料
  • 他のリポジトリの動作を分析した参考資料
  • 対話型AIでLLM(o1-proやgpt-4.5やDeep Research)が作った資料

などですが、「こういう機能が欲しいんだけど、どう実装したらいいと思う?」みたい壁打ちをすることもあります。気に入った案が出てきたらそのまま設計に移ります。気に入らなかったらそのタスクはなかったことにします。

そう、うまくいかなかったらそのタスクは破棄すればいいのです。現状のコーディングエージェントは挙動は必ずしも安定的とは限りません。リトライすればうまくいくケースは割とあります。AIとのやりとりを途中で消して別の文言を投げつけて再開するみたいなこともあります。ChatGPTのような対話型AIの使いこなしと同じですね。

Vibe Coding!

簡単でしょ????

あるとき異変に気づいた

途中から様子がおかしくなり始めたんですよね。開発サイクルの最後でユニットテスト、型チェックが毎回壊れるようになりました。しかも、その修復が回を追うごとに大変な感じになってきたのです。

で、さすがにこれはよくないなーってことで「このプロジェクトの背景情報を一切見ずに、ソースコードだけを読んだうえで、ソースコードや設計を批判してほしい」というプロンプトを投げると、あれこれ見つかる技術的負債。試しに自分でソースの一部を読んでみると、「うーんなるほどたしかに」って感じにだったので、技術的負債の解消を決意しました。

でも、普通のプロダクトなら、最低でも数ヶ月、普通なら数年かからないと技術的負債を強く意識することはあり得ません。たった4日でここまで到達したの、マジですごくないです?

そして始まる地獄

最初に「このプロジェクトの背景情報を一切見ずに、ソースコードだけを読んだうえで、ソースコードや設計を批判してほしい」で、批判させたものをMarkdownとして出力させて、「こういった問題があるんだけど技術的負債に取り組んでほしい」って投げてプランニングをさせました。

そのあと、そのプランニングしたドキュメントを元に設計と実装を繰り返しています。

ただ、このやり方では、進捗が悪かったり、実際にはちゃんと直ってない、なんならクソコードやクソ設計が増殖するという問題が頻発していました。まぁ基本的には人間が張り付かないので、別に大変でもなんでもないんですが、それがゆえに「まぁいいか」で時間が過ぎて、金が溶けていたとも言えます。

ちなみにこの期間、Rooに対してめっちゃ口が悪くなりました。人間相手なら絶対言わないような言葉も投げつけております。

旗色が変わったプロンプト

そこでやり方を変えました。

最初に「このプロジェクトの背景情報を一切見ずに、ソースコードだけを読んだうえで、ソースコードや設計を批判してほしい」を投げて、次に人間が発言するタイミングになったら、次のプロンプトで方向性を与えます。

このプロジェクトはAIが作り上げた。現在、このプロジェクトの利用者は存在しない

なお、このプロジェクトの目的は、依存性を完全に廃したAIエージェントのコアを作ることである。想定用途は、プログラムの設計と実装、テストなどを半自動で行うコーディングエージェントなどである。コアは、CLI/VSCode拡張/ウェブアプリなどから使用される

あなたには、コードの一貫性のなさや重複などを削除し技術的負債を軽減してほしい。ただし、過去の失敗を見るに、一気にやろうとする、あるいは中途半端な進め方をすると同じように失敗し、さらに一貫性のなさ・乱立が進むだけだろうと懸念している。そこで、そうならないための方法を考えてほしい

* **開発者は一人であり、API利用者はまだ存在しない。移行期間とか互換性維持は不要**
* **互換性を残すな。すべて消せ**
* すべてのdeprecatedのコードを削除しろ
* **新しい仕組みへの中間状態を作るな**
* anyを使用しないこと。型安全を努力しろ
* classを極力使用せず、関数で実装しろ。その関数のユニットテストをしろ
* 不要なコメントを削除しろ、食い違いのあるコメントは修正しろ
* 性能は二の次、シンプルにしろ

計画が大規模すぎると失敗する。現実的な粒度で解決してほしい。また、今後も設計・実装を行うのはAIである。それ故にAIに可能な手段で考えろ。今回のあなたの提案はそれ一つで全問題を解決することを考えるな。AIだから無限に働ける。何度もリトライできる。

技術的負債解消は今回だけでは終わらない。一段目の取り組みとして何をやるべきか考えろ

**技術的負債を根本解決するたった一つだけを考えろ。それ以外の余計なことを考えるな。排除しろ。提案するな。たった一つだけをやれ**

繰り返しをやらず、批判分析、設計、実装は、それぞれ独立したタスクであり、一回限りのものとしました。

このやり方は見事にうまくいきました。

結局「これとこれとこれをやれば理想的なプロダクトに生まれ変わります!!!!!」ってAIが言うのは信用してはいけなくて、「たった一つ」に集中させないといけなかったのです。

たった一つで完結するシンプルなリファクタリングをプランさせて、必ず最後までやり遂げさせるようにしています。失敗したらもちろんそのタスクは破棄します。

一期一会の精神です。

コンテキストを複雑にしない方がいい、というの自体は、これまでの2年間のLLMプロダクト開発経験および、今回の実験でも改めて実感してたところなので、一回のサイクルでは作業はシンプルにさせてたつもりなんですが、どうやら、リファクタリングプランの全体像すらノイズになってたようです。

このやり方にしてからはそれまでが嘘のように明瞭に技術的負債が減少していきました。

  • 「懸念点があるなら、関係するすべてのソースコードを読め」
  • 「その4つの選択肢のメリデメを挙げて。関係するすべてのソースコードを読んで」
  • 「3番と4番はこうこうこういう理由でいらない。選択肢1,2のメリデメを挙げて。関係するすべてのソースコードを読んで」
  • さっきのプロンプトか、コーディングガイドを貼り付ける

基本的にはこの設計のフェーズで投げる言葉はこれだけです。とにかく、考えさせる、コードを読ませる。コンテキストは増大しますが対象ファイルの知識がどんどんぶちこまれるので、技術的負債の解消をするための設計段階では、かなり重要な鍵になります。

また、実装段階で、エラーが残っている場合は

bun tsc --noEmit でエラーが出まくってるので全部改修してほしい。もし一つでもエラーが残るなら、あなたの今回の仕事は採用できません。すべてが無に帰します

という、圧の強いプロンプトを投げることもあります。

技術的負債が積み上がった理由

技術的負債がものすごいことになったのには、いくつか理由があります。

プロンプトやルールファイルの指示が効いたり効かなかったりする

ルールファイルでは、一応コーディングガイドラインを提示しているんですが、実際にはそれらに従うときと従わないときがありました。割とここらへん挙動が不安定です。

まぁCline/Roo自体プロンプトがやけくそにややこしく、かなり「無茶をしたプロダクト」なので、ユーザープロンプトの効きが悪いということがあります。そのため、基本的にはシンプルにしないとすぐ破綻するというのがあります。

LLMは矛盾があるとそれによって色々破綻しやすくなります。これはモデル自体の持つ賢さ(経験則ですが、ある程度はパラ数に比例する)によって破綻に対する耐性が大きく違います。シンプルにしないとだめというのはこれが理由です。

https://speakerdeck.com/erukiti/gemini-2-dot-0-flash-prompt-engineering?slide=10

それはそれとして、コードがぶれてたのは確認してたんですが、人間の感覚で言えば、クソコードがちょっと混じってる位なら、そうそうプロジェクトの破綻まで行かないため、そのまま進めてみよう!ってことで、進めてたら、実はそれが結構破綻要因につながっていた!という、まぁちゃんと考えれば「それはそう」って感じなんですが、AIは人間よりも割れ窓理論的な意味で危険なところがありますね。

じつはこれもモデルによるため、3.7 Sonnetではだめだけど、Gemini 2.5 Proならマシな気配を感じます。Claudeでも4.0 Sonnetくらいでは克服してるでしょう、きっと。

一度書かれたコードは増殖する

これはLLMが「今あるものを正とする」傾向が強いからです。GitHub Copilotなど、何かしらのAIを使っている人なら、既存コードを真似るのがうまいと感じることが多いと思いますが、それです。そういう風になるようにLLMが育てられています。

そのため技術的負債が生じると、無限増殖します。ちょっとクソコードが混じるだけで破滅に突き進むのはこれが原因です。

そう遠くない将来に、クソコードは真似ないようにする、技術的負債に対して強い心で立ち向かえるように進化するはずですが、3.7-Sonnetではまだまだそうなっていません。

互換性を設けたがる

これは、僕が前提条件を与えてなかったのが敗因なんですが、コアライブラリとして作っているため、既存のAPIを変更することに関してはとても慎重になって、互換性を設けたがるという傾向があります。これ自体はある意味当たり前であり、逆にそうじゃないと、既存のコードベースをいじれないです。

ところが、今回は条件として、そもそも数日間程度で生み出されたものであり、ユーザーもおらず、僕はなんとでも対応できるため、互換性なんて無視してほしかったです。

そこに気づくのに時間がかかってしまい、技術的負債が増大しました。

コンテキストウィンドウや、プランニングによって、中途半端な作業が積み重なる

コンテキストウィンドウを埋め続けると、作業を途中で切り挙げる傾向が増えます。あれこれ理由をつけてサボりたがるはLLMあるあるです。

また、プランニングで「ここからここまで」といった範囲を決めるんですが、自分のいじったコードによって他の部分が壊れた場合、壊れた他の部分に関しては知らんぷりをすることが3.7 Sonnetでは多いです。コンテキストに余裕があるときはやってくれることもあるんですが、余裕がなくなってくると特に、そういうときにひたすらサボりたがります。

これも1M contextを持つGemini 2.5 Proなら問題は激減します。

あれこれをやらなかった理由

意図的にやらなかったことがいくつかあります。

linter

じつはlinterを使っていません。素直にlinterを使えば、もう少しマシだったのでは?というのもあるんですが、何せ、ユニットテスト・型エラーチェックすらやってくれず問題がここまで拡大してたので、lintをしてても余計混乱してただけだったと思っています。

もちろん、毎回必ずlintをやるようにできるならlinterは絶対入れた方がいいですが、僕としてはLLM自体が、自然言語で指示を理解するlinterとして振る舞ってほしいというのがあります。ここらへんをなんとかする方法論は、次なる検証事項として考えています。

テストファースト

結果を観察するとわかると思いますが、人間よりは見えている予想図のモノがかなり大きいため、テストファーストで刻んでいくと逆にスペックを落としそうです。せいぜい一回のタスクでは必ずテストを成功させる、くらいの規則がちょうど良いです。毎回正しく実行してくれさえすればですが。

同じ理由でTDD(テスト駆動開発)も不要です。TDDのRed, Green, Refactorみたいなステップを必ずしも刻んでくれるわけではない。そこの制御に凝ったことをやるとその分、コンテキストが複雑になるだけであまり意味がありません。

そもそも、TDDは名前が「〜〜〜開発」で紛らわしいですが、設計論です。テストを最初に書くことで設計する技法なのでLLMの場合は不要です。

DDD, Clean Architecture

Eric EvansのDDDや、Bobおじさんのクリーンなアーキテクチャはありだと思いますが、特定の開発技法に依存した方法論は今回採用しませんでした。

ただしそうはいっても無軌道だと困るので、ルールファイルでSOLID原則意識してねとかは書いています。

今後は、選択的にクリーンなアーキテクチャや、DDDのエッセンスを取り入れるのは検証しようと思っていますが、コンテキストを複雑にせずうまく指示できるかは悩ましいかもしれません。本をまるごと学習していればいいですが、そうじゃなかったら、ネット上に溢れるオレオレ理論による影響もあるので、安定的にいけるとは限りません。

コンテキストの複雑化が問題に直結してる限りは、凝った手法はあまり良い結果を生み出しません。

MCP

元々ただでさえシステムプロンプトがものすごいことになっているので、意図的にMCPを使わないようにして、プロンプトを減らしました。

特定のモードだけMCPを使って、実装時はMCPを使わないとかができるようになれば、導入しようと思います。

まとめ

5日で技術的負債をおおよそ改善はできたのと、つい先日に登場したGemini 2.5 Proが技術的負債でものすごい強みを発揮しだしたので、このまま開発を継続できそうです。

つまり、AIコーディングエージェントは、技術的負債も、人間よりは遙かに早い期間で解消が可能ということです。

じつのところ、僕があれこれ試してたことも、モデルをClaude 3.7 Sonnetから Gemini 2.5 Proに切り替えるだけで解決するのでは?という気持ちもあるんですが、言うても、Geminiの正式な価格次第ですが3.7-Sonnetより安い価格にするとは思えませんし、1MコンテキストがいけてしまうGemini 2.5 Proではトークン数のせいで、おそらく目が飛び出るコストになるでしょう。せめて、Geminiも、OpenAI(か最悪でもAnthropic)と同じプロンプトキャッシュを提供してほしいものです。

ということで、Sonnetでもいける方法論を検証したいので、ヨシ!としています。

  • たったの4日で中規模なコードを生み出した
  • たったの5日で技術的負債を、開発を再開できそうなくらいには解消できた
  • 技術的負債を放置すると、どんどん解消しづらくなるので、定期的に技術的負債の解消が必要
  • 人間が張り付いて高速目grepをしなくても案外なんとかなる
  • 10日かからず、僕の手元には、中規模なコードベースと、技術的負債の存在していた履歴ができあがりました。これは後であれこれ検証できる宝の山です
ソースコードツリー
src
├── adapters
│   ├── api
│   │   ├── api-adapter-utils.test.ts
│   │   ├── api-adapter-utils.ts
│   │   ├── api-adapter.test.ts
│   │   ├── api-adapter.ts
│   │   ├── claude-adapter.test.ts
│   │   ├── claude-adapter.ts
│   │   ├── claude-stream-functions.ts
│   │   ├── claude-text-editor-api.test.ts
│   │   ├── claude-text-editor-api.ts
│   │   ├── common-adapter.ts
│   │   ├── factory.test.ts
│   │   ├── factory.ts
│   │   ├── openai-adapter.test.ts
│   │   ├── openai-adapter.ts
│   │   └── openai-stream-functions.ts
│   ├── node-file-system.ts
│   └── node-terminal.ts
├── api.ts
├── cli
│   ├── args.ts
│   ├── commands
│   │   ├── config.ts
│   │   ├── help.ts
│   │   ├── index.ts
│   │   ├── list.ts
│   │   ├── respond.ts
│   │   ├── run.ts
│   │   └── step.ts
│   ├── config.ts
│   ├── index.ts
│   ├── types.ts
│   └── utils.ts
├── core
│   ├── api-adapter.ts
│   ├── api-requester.ts
│   ├── context-manager.ts
│   ├── environment-updater.ts
│   ├── environment.ts
│   ├── file-system.ts
│   ├── interaction
│   │   ├── default-provider.ts
│   │   ├── index.ts
│   │   ├── manager.test.ts
│   │   ├── manager.ts
│   │   ├── mock-user-provider.test.ts
│   │   ├── mock-user-provider.ts
│   │   └── types.ts
│   ├── messages
│   │   ├── index.ts
│   │   ├── message-model.ts
│   │   └── message-operations.ts
│   ├── prompt-generator.ts
│   ├── prompts
│   │   └── system.ts
│   ├── state-management
│   │   ├── default-state-manager.ts
│   │   ├── error-codes.ts
│   │   ├── index.ts
│   │   ├── interfaces.ts
│   │   ├── mocks.ts
│   │   ├── tests
│   │   │   └── default-state-manager.test.ts
│   │   └── type-guards.ts
│   ├── state-management.test.ts
│   ├── state-management.ts
│   ├── task-loop.test.ts
│   ├── task-loop.ts
│   ├── task-runner.ts
│   ├── task-step-runner.ts
│   ├── terminal.ts
│   ├── token-counter.ts
│   ├── token-estimator.ts
│   ├── tool-executor-core.ts
│   ├── tool-executor-impl.ts
│   ├── tool-executor-interfaces.ts
│   ├── tool-executor.test.ts
│   ├── tool-executor.ts
│   ├── tool-factory.ts
│   ├── tool-formatter.ts
│   ├── tool-params.ts
│   ├── tool-request-processor.ts
│   ├── tool-validator.test.ts
│   ├── tool-validator.ts
│   ├── type-utils.ts
│   └── types.ts
├── index.ts
├── tools
│   ├── command-tools.test.ts
│   ├── command-tools.ts
│   ├── file-tools.test.ts
│   ├── file-tools.ts
│   ├── interaction-tools.ts
│   ├── text-editor-tools.test.ts
│   └── text-editor-tools.ts
├── types
│   ├── converters.ts
│   ├── errors.ts
│   ├── factories.ts
│   ├── guards.ts
│   ├── index.ts
│   ├── result.ts
│   └── tools
│       ├── command-tools.ts
│       ├── file-tools.ts
│       └── interaction-tools.ts
└── utils
    ├── cache-utils.ts
    ├── config-loader.ts
    ├── cost-calculator.ts
    ├── error-handling.ts
    ├── logger-config.ts
    ├── logger-core.ts
    ├── logger-types.ts
    ├── result-utils.ts
    ├── state-inspector.test.ts
    ├── state-inspector.ts
    ├── stream-utils.ts
    ├── structured-logger.test.ts
    ├── structured-logger.ts
    ├── task-diagnostics.test.ts
    ├── task-diagnostics.ts
    ├── test-logger.ts
    ├── token-usage-info.ts
    └── tool-validation.ts
test
├── command-tool-validation.test.ts
├── context-manager.test.ts
├── error-handling.test.ts
├── integration
│   ├── api-integration.test.ts
│   ├── basic-task.test.ts
│   ├── error-handling.test.ts
│   ├── multi-step.test.ts
│   ├── standard-file-tools-integration.test.ts
│   └── tool-execution.test.ts
├── simple.test.ts
├── test-data
│   ├── api-data.ts
│   ├── state-data.ts
│   └── tool-data.ts
├── test-helpers
│   ├── assertion-helpers.ts
│   ├── environment-helpers.ts
│   ├── error-helpers.ts
│   ├── integration-helpers.ts
│   ├── mock-helpers.ts
│   └── type-safe-helpers.ts
├── test-interfaces
│   ├── api-adapter.ts
│   └── tool-executor.ts
├── test-logger.test.ts
├── token-counter.test.ts
└── token-estimator.test.ts

20 directories, 136 files

ちなみにコストは、

  1. 最初の4日は$200程度
  2. 後の5日では$600程度

です。技術的負債は、金を溶かすことが証明されました。大きくなりすぎる前に、定期的な技術的負債の解消をしていれば、もっと安くついたのは間違いないです。

AIコーディングで圧倒的な速度でこれができるようになったのは、本当にすごいことだと、僕は思っています。あとはコストを下げられればいいんですが。

今後は

  1. 本来やりたかったこと、つまり僕の理想を詰め込んだコーディングエージェント開発に戻る
  2. 今回得たあれこれを元に最初から技術的負債をあまり増加させない方法論の確立を目指す
  3. 技術的負債の解消についての実験を別途やりなおす(コードベースがあるからgitの過去に履歴からリトライできます)

これら3つをそれぞれ進めようと思っています。今回の記事が好評なら、2や3に関して改めて記事を書くかもしれません。

技術的負債はある程度解消したものの、構造がぐちゃぐちゃなのは変わってないため、この続きはレギュレーションを一部解除して、作ることを優先しようと思っています。

たぶん、ここまで読んで、皆さんも想像がついていると思うんですが、僕が作っているコーディングエージェントに成果として組み込むために色々実験をしてきたという側面もあります。

今回作っているそれを、OSSとして公開したり、あるいはビジネスにするか?などはまだ未定です。まずは検証を進めて自分なりに答えを出してから考えようと思っています。興味ある人いますかね?

Discussion

firemiofiremio

出来上がったものを毎回alloy形式手法で評価させて修正させると、そこそこの結果になるのでは?
個人プロジェクトで完全放置なら、夜中のDeepSeek-R1は75%OFFなので、安くできるかもですね。
コンテキストが3.7-thinkingと比べるとアレですが・・・