Macのふたを閉じても、senteは止まらない
「mac 閉じても sente 止まらないようにして」——この依頼に真正面から答えようとすると、すぐに壁に当たります。
macOS はふたを閉じるとハードウェアレベルで強制スリープします。
caffeinate はアイドルスリープしか防げず、蓋閉じは別の経路です。
そこで方針を変えました。sente を Mac からサーバーに移す——常駐 VM の上で tmux に入れ、ジョブの実行先を切り替える。
この記事は、その実装と、実際にファイルを作らせてレポートを書かせた記録です。
なぜ「頑張ってスリープさせない」は失敗するのか
先に詰まりを潰しました。ここを飛ばすと数時間を溶かします。
最初に調べた状態では、caffeinate -dims が 321時間動いていて、PreventSystemSleep も有効でした。
つまりアイドルスリープはすでに抑止できていたのに、蓋を閉じれば終わりです。
macOS の lid close は pmset や caffeinate の外側で強制されます。
| 手段 | アイドル | 蓋閉じ | 備考 |
|---|---|---|---|
caffeinate -dims | 防げる | 不可 | すでに321時間稼働していたが無効 |
pmset disablesleep | 防げる | 不可 | Apple Silicon では lid close に効かない報告が多い |
| クラムシェル(AC + 外部ディスプレイ) | 防げる | 防げる | 確実だが、Mac を動かせない |
| サーバーで動かす | 無関係 | 無関係 | PC の状態に依存しない |
クラムシェルは確実ですが、Mac をどこにも持って行けません。 ノートを閉じて移動したい、という元の動機に合わない。なのでサーバー側に移すのが根本解だと判断しました。
構成:VM が主役、Mac は依頼者
sente は tmux の中で動くので、SSH を切っても生き残ります。
役割をはっきり分けました。実行するのは常駐 VM、依頼するのは Mac(またはスマホ)です。
- Fly.io
sente-cloud(東京リージョン・shared-cpu-2x 2GB・volume 10GB)— sente が tmux セッションsenteで常駐。ジョブを拾う worker がflyworkerで待機 - sente-cloud(Cloudflare Worker) —
POST /jobsに実行先flyを追加。VM が/jobs/fly/nextをポーリングして拾う - 結果 — volume に残るので、VM を作り直しても作業は消えない
fly status -a sente-cloud — machine 891e035c676598 が started。volume sente_data(10GB)が /home/yuki/workspace に接続済み。
Mac を閉じても止まらない理由は単純です。sente は tmux の中で動き、sshd がコンテナの主プロセス。
さらに auto_stop_machines = false と min_machines_running = 1 で、アイドルによる自動停止も無効化しています。
実際に使ってみる
「動きました」ではなく、ファイルを作らせました。
ジョブは target: "fly" を付けて投げるだけです。Mac は依頼を出したら、あとは何もしません。
$ curl -X POST https://sente.teai.io/jobs \
-H 'content-type: application/json' \
-d '{"target":"fly",
"prompt":"/home/yuki/workspace に hello-fly.md を作って
「Fly VM で動きました」と1行書いて。
その後 cat で内容を確認して報告して。"}'
status: done・rc: 0。VM が自分でファイルを書き、cat で確認して報告している。次はもう少し実務寄りの依頼です。システム情報を調べて Markdown の表にまとめさせました。
"prompt": "/home/yuki/workspace に report.md を作って。
今日の日付・ホスト名・CPUコア数・メモリ量・ディスク使用量を
uname/hostname/nproc/free/df で調べて、Markdown の表にまとめて。
最後に cat で中身を見せて。"
uname / hostname / nproc / free / df を実行し、自分で Markdown の表にまとめた結果。
hello-fly.md と report.md が volume 上に残る。VM を作り直しても消えない。修正完了後、すべて rc=0
ファイル作成+確認まで
既存の teai 残高をそのまま使用
踏んだ罠:7つすべて本番で実測
「動くはず」で書いて、ことごとく本番で転びました。
実装自体は半日でしたが、本番で動かして初めて分かる問題が7つありました。 どれもログだけでは「成功」に見えるのが厄介です。
罠の一覧(7件)
- worker トークンが 403 —
WORKER_PATHSに/jobs/fly/*を入れ忘れ - output 報告が 403 —
canReportJobがtarget !== 'mac'で拒否。heartbeat だけ通るので「動いているように見える」 - 全ジョブが「こちらはデモです」 — worker が
TEAI_API_KEYを export できていない。rc=0 なので成功に見える最悪のパターン ProviderNoProvidersError— 生の sente は~/.config/sente/config.jsonを読む。teランチャー経由だと動くので気づかない- agent "sente" not found — VM に実在するのは
build(primary)。スマホ側の名前は VM に無い sente run -pは password — prompt ではない。prompt は positional で渡す- volume が root 所有 — 初回作成時に root 所有になり、workspace に書き込めない。sente が「権限がない」と判断して作業を止めた
rc=0 status=done と出ていました。
中身は「こちらはデモです」です。API キーが空でも sente は正常終了するため、出力の中身を見るまで分かりません。
今はキーが空なら worker が起動を止めるようにしています。
Mac からどう使うか
2つの入口があります。
1. 直接入って操作する——Mac の代わりに VM の sente を触りたい場合。
fly ssh console -a sente-cloud # 入る(root)
su - yuki # sente のユーザに切替
tmux attach -t sente # sente の画面に入る
Ctrl+B → D で離脱しても、sente は動き続けます。
これが「Mac を閉じても止まらない」の実体です。
2. ジョブとして投げる——スマホやブラウザから依頼する場合。target: "fly" を付けるだけです。
従来の "mac"(Mac が拾う)や "cloud"(サンドボックスで実行)と並んで選べます。
iPhone からも投げられる
実行先は Mac・クラウド・常駐 VM の3つから選べます。
sente の iPhone アプリは、依頼の内容からどこで実行するかを自分で選びます。
これまで mac(Mac で実行)と cloud(クラウドの作業箱)の2択だったところに、
3つ目の fly(常駐 VM)を足しました。
使い分けは「Mac がそこにいないかもしれないかどうか」です。エージェントへの指示にも明記してあります。
fly— Mac が閉じていても寝ていても進めたい仕事。VM は自分のワークスペース/home/yuki/workspaceを持ち、再起動しても残りますmac— Mac そのものが要る仕事。AppleScript、手元のファイル、Blender、カレンダー/メールcloud— GitHub のリポジトリ、長時間・並列のタスク
fly にできないことも明示しています。Mac の ~/workspace には触れません。
ここを曖昧にすると、エージェントが「Mac のファイルを読む」依頼を VM に回して失敗するためです。
ただし、これは「ローカル実行は要らない」という話ではありません。
Mac でしかできない仕事(実ブラウザの操作、手元のファイル、キーチェーン)は今までどおり target: "mac" です。
変えたのは「PC の電源状態に依存させたくない仕事」の置き場所だけです。
未検証の点も残しています。長時間ジョブ(タイムアウト 3600 秒)の実走はまだで、今回は 20〜25 秒のジョブしか試していません。 worker トークンにも有効期限があり、失効したら再発行が必要です。