Agent Codingのサンドボックスはどうするのがいいのか?
お仕事で長時間AI Agentを動かしたいことがほぼなかったから今まではyoloモードにあたるものは使ってなかった(プライベートでは少しつかっている)
最近ではClaude CodeにはAuto modeもあるのでallow permissionとhooksでの制限を整備すればそれほど困ることはなかった。
しかし、最近taktを使ってワークフローを組んで長時間タスクを実行するというのをやっていて、その中で裏でコマンドの承認を求められてて止まっててタイムアウトすることがまあまあ発生する。
寝てる間やっておいてもらいたいのに朝起きたら失敗していると残念な気持ちになる。
claudeの設定setting.jsonのallowリストに色々コマンドを追加していったが中々改善せず(変数とパイプでのコマンド連結駆使とかfor文使われるとかなると承認が発生する確率が上がる)
ということで、しびれを切らしてサンドボックス環境の整備に着手した。
サンドボックスといえばDockerかなと思ってちょっと最近の動向を調べていたら下記の記事辺りを見つけてなんとなくのトレンドみたいなのが分かった。
Claude自体でもサンドボックスが提供されているのはうっすら知っていたがそれがmicroVMというのにあたるのとか諸々勉強になった。
Claudeのサンドボックスは馴染みがないのでそれのセットアップを今試行錯誤するのはつらいので、一旦は慣れたDocker(Devcontainer)でサンドボックスを用意してみた。
この辺りも公式ドキュメントにあるので、それを参考にちょっとカスタマイズ(これももちろんClaude Codeにやってもらう)してすぐ使えるようになったので便利である。
devcontainer cliもあるのでそれでビルドや立ち上げ、execでコンテナに入れる。
まあ何かDockerfile変更したりで再ビルドすると諸々の自動化できてないセットアップを手動でやらないといけないのが面倒だけど、一旦はClaude Codeが暴れても少しは安心な環境ができたのでそちらで夜寝ている間だけ動かしつつ、昼間はallowリストの整備や他のサンドボックスの検証などをしていければなと。
久々の感覚
仕事のことで色々考えていたら、そう言えば今やってるこれって別のアレと同じような考えでいけるのでは?みたいな何かピースがうまくハマったような感覚があった。
この感覚が久々な感じがして、記憶を思い返すと20後半から30前半くらいはこの感覚がもっとあったような気がしたが、これは何か失われてしまったために少なくなったのかそれとも他にトリガーとなるようなことがあるのだろうか。
やる気ははじめから出るもんじゃなくてやってるうちに出てくるというのを実感してるという話
平日は毎朝仕事前にエニタイムで筋トレをすることが習慣化してしばらくたつが、今日はめっちゃ追い込むぞーみたいになる日なんて稀でむしろやりたくないなと思ってる。(特にスクワットの日)
でも、ジムに言ってダンベル持って何回かやってると物足りないからもう少しやるかーとやってるうちにどんどんやる気が出てきて、時間が足りないじゃないか!となって仕事に向かうみたいなことが多い。
はじめからこのやる気が出てたらなー、というのを思っていた時にちょうど下記のポストを見てまさにこれだなーと思った。
やる気がなくても、まずバーベルの前に立つ。ウォームアップセットをこなしているうちに、体が徐々に目覚めてくる。気づけば本気で追い込んでいる。その感覚は気のせいではないことを示したNature Human Behaviourの最新研究。 https://t.co/h8hPGqPBrj
— 庵野拓将 (Takumasa Anno) (@takumasa39) 2026年5月18日
ゆるーく再開
ブログ名とかも変えてみた。
役に立ちそうなテクニカルなブログネタにこだわって書かなくなってしまったので、あまりジャンルに拘らずにゆるく再開してみる。
Railsアプリを型チェックできるようにSteepに入門してみた
今年も残り少なくなってきて、そういえばRailsアプリに型チェックを導入してみたいなーと思っていたのを思い出したのでSteepに入門してみた。
RailsアプリへのSteep導入は神速さんのブログがすごく丁寧だったのでそれを参考にしてやった sinsoku.hatenablog.com
差分としては
- lib/tasks/rbs.rake を作成する
- 現在は
bin/rails g rbs_rails:installするとlib/tasks/rbs.rakeが生成される
- 現在は
- 不足してるrbsを用意する
- 自分は
ActionCable::Channel::BaseとActionCable::Connection::Baseだけでよかった
- 自分は
# sig/patch.rbs
module ActionCable
module Channel
class Base
end
end
module Connection
class Base
end
end
end
あと、神速さんのブログのscaffold を試すのところにあるようにコントローラーのエラーも確かに発生していて、自分は scaffold userをしたんだけどそのエラーが下記。
# Type checking files:
..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................F.....
app/controllers/users_controller.rb:7:4: [error] Cannot find the declaration of instance variable: `@users`
│ Diagnostic ID: Ruby::UnknownInstanceVariable
│
└ @users = User.all
~~~~~~
app/controllers/users_controller.rb:17:4: [error] Cannot find the declaration of instance variable: `@user`
│ Diagnostic ID: Ruby::UnknownInstanceVariable
│
└ @user = User.new
~~~~~
app/controllers/users_controller.rb:27:4: [error] Cannot find the declaration of instance variable: `@user`
│ Diagnostic ID: Ruby::UnknownInstanceVariable
│
└ @user = User.new(user_params)
~~~~~
app/controllers/users_controller.rb:31:34: [error] Type `::UsersController` does not have method `user_url`
│ Diagnostic ID: Ruby::NoMethod
│
└ format.html { redirect_to user_url(@user), notice: "User was successfully created." }
~~~~~~~~
app/controllers/users_controller.rb:45:34: [error] Type `::UsersController` does not have method `user_url`
│ Diagnostic ID: Ruby::NoMethod
│
└ format.html { redirect_to user_url(@user), notice: "User was successfully updated." }
~~~~~~~~
app/controllers/users_controller.rb:60:32: [error] Type `::UsersController` does not have method `users_url`
│ Diagnostic ID: Ruby::NoMethod
│
└ format.html { redirect_to users_url, notice: "User was successfully destroyed." }
~~~~~~~~~
app/controllers/users_controller.rb:69:4: [error] Cannot find the declaration of instance variable: `@user`
│ Diagnostic ID: Ruby::UnknownInstanceVariable
│
└ @user = User.find(params[:id])
~~~~~
Detected 7 problems from 1 file
path helperのやつとインスタンス変数の定義がないと怒られたので解決してみた。
path helper関連
これはrbs_rails:allをしたときにsig/rbs_rails/path_helpers.rbsが生成されているのになんでそれ見てくれないのかなと疑問だったんだけど、
# sig/rbs_rails/path_helpers.rbs interface _RbsRailsPathHelpers ・・・ def users_url: (*untyped) -> String def new_user_url: (*untyped) -> String def edit_user_url: (*untyped) -> String def user_url: (*untyped) -> String ・・・ end
このようにinterfaceで定義されているだけなので、これをコントローラーのrbsファイルでincludeしてやればよさそう。
(まだRBSが全く分かってないんだけど、RBS基礎文法最速マスター - pockestrap見つつこう使うのかなーみたいな感じでやってみたらエラーはでなくなった)
# sig/app/controllers/users_controller.rbs class UsersController < ApplicationController include _RbsRailsPathHelpers # GET /users or /users.json def index: () -> untyped # GET /users/1 or /users/1.json def show: () -> nil # GET /users/new def new: () -> untyped ・・・ end
インスタンス変数
Cannot find the declaration of instance variable: `@user` Cannot find the declaration of instance variable: `@users`
@userと@usersのRBS定義がないのでこれは手動で定義した。
# sig/app/controllers/users_controller.rbs class UsersController < ApplicationController @user: User @users: User::ActiveRecord_Relation include _RbsRailsPathHelpers # GET /users or /users.json def index: () -> untyped # GET /users/1 or /users/1.json def show: () -> nil # GET /users/new def new: () -> untyped ・・・ end
あと注意点としては rbs_rails:allしたときにmodelの定義も生成してくれるけど、それはdb:migrateを実行しておかないと生成されない。
rbs_rails/rake_task.rb at 227285bd04d526525331a9b05fe9ce5e78038946 · pocke/rbs_rails · GitHub
::ActiveRecord::Base.descendants.each do |klass|
next unless RbsRails::ActiveRecord.generatable?(klass)
ここの RbsRails::ActiveRecord.generatable?(klass)が
rbs_rails/active_record.rb at 227285bd04d526525331a9b05fe9ce5e78038946 · pocke/rbs_rails · GitHub
def self.generatable?(klass)
return false if klass.abstract_class?
klass.connection.table_exists?(klass.table_name)
end
とあるようにDBにテーブルが存在しているかを見てるので。
これでとりあえずはsteep checkが通るようになったので、なんとか入門までは行けた感じがする。
$ bundle exec steep check # Type checking files: ........................................................................................................................................................................................................................................ No type error detected. 🫖
ActiveJob::TestHelperでセットされるTestAdapterを無効にしたい場合
下記のように ActiveJob::TestHelperをincludeしているとqueue_adapterが強制的にTestAdapterになります。
[spec/rails_helper.rb] RSpec.configure do |config| config.include ActiveJob::TestHelper end
RSpecのJobのテストとかを書く分には便利なアサーションメソッドとかも使えて便利なのですが、本当にJobを実行したい場合もあります。 今回はActionCableのChannelでJob.perform_laterしてそのジョブで処理が完了したらbroadcastするようなものだったので、同期ではなく非同期でJobを実行したかったです。
初めは Rails.application.config.active_job.queue_adapter = :async としてqueue_adapterを切り替えようとしていたのですが、どうもTestAdapterから切り替わっていないようでした。(設定直後くらいでbinding.pryして止めても確かにAsyncAdapterにはなっている)
どうにかして部分的にAsyncAdapterに切り替えたいなと調べていると下記を見つけました。 github.com
disable_test_adapterというメソッドを呼ぶことでActiveJob::TestHelperでセットされるTestAdapterを無効にできるようです。 Rails6になった頃、config/environments/test.rbのqueue_adapter設定が無視されるのがあったんですね。
これでasyncアダプターに切り替えて非同期でJobを実行できるようになりました。
補足
同期実行で問題ない場合は下記で見つけた perform_enqueued_jobs を利用すると同期実行にできます。
qiita.com
RailsでPostgreSQLのVIEW定義を管理する
初めてちゃんとPostgreSQLのVIEWを使うので、Railsで使う場合の調査。
下記のgemを利用するのが定番みたい。
このgem使うと何が嬉しいのか
RailsガイドにもCREATE VIEWする方法が書かれてる。
gem利用しないとCREATE VIEWする生SQLをexecuteするだけなので
- migrationのdownを自分で定義する必要がある
- はじめのCREATE VIEWならdropすればいいけど以降の変更時はその前のやつに戻す必要がある
- レビュー時に以前のmigrationを参照しないと行けないので手間が増える
- はじめのCREATE VIEWならdropすればいいけど以降の変更時はその前のやつに戻す必要がある
マテリアライズドビューを利用するならrefreshの仕組みを用意してくれるのでさらに便利そう。
という感じかな。 あとはおまけとしてエディタでSQLのシンタックスハイライトが効くので見やすいくらいですかね。
update_viewとreplace_viewはどう使い分けるのか
コメントにちゃんと書いてくれてるの助かる。
scenic/postgres.rb at 3600a485797fe1dbf30d152cc60b6d2318f04c48 · scenic-views/scenic · GitHub
CREATE OR REPLACE VIEWは、既存のビュースキーマの最後に新しいカラムを追加する場合にのみ許可されています。既存のカラムは、順番を変えたり、削除したり、型を変更することはできません [DeepLでの翻訳より]
なので、基本的にはupdate_view使う感じですね。
あとはTechRachoも目を通しておくと良さげ