CLAUDE LABEN
PRICING — 本日9月1日は Sonnet 5 の値上げ予定日でしたが、引き上げは実施されませんでした。導入価格の $2/$10 per MTok がそのまま標準価格として確定していますPARTNER — Salesforce と Anthropic が拡張提携「Claudeforce」を発表しました。Salesforce in Claude プラグインは商談準備やパイプライン管理など37のセールススキルを同梱しますTRUST — Claudeforce の推論は Amazon Bedrock 経由で Salesforce Trust Boundary の内側に留まります。データが境界の外へ出ない構成が、規制業種への回答になっていますBETA — Salesforce in Claude は現在は選抜パイロット顧客向けです。9月中のオープンベータ移行が予告されていますLIMITS — 週次上限の50%増は9月13日までです。9月14日からはプロモ前比+25%が恒久水準になります。今日の水準と比べると約17%の削減にあたりますRELEASE — Claude Code は v2.1.251(8月28日)から新しいリリースが出ていません。約0.8日に1本というペースからすると、4日の間隔は最長クラスですPRICING — 本日9月1日は Sonnet 5 の値上げ予定日でしたが、引き上げは実施されませんでした。導入価格の $2/$10 per MTok がそのまま標準価格として確定していますPARTNER — Salesforce と Anthropic が拡張提携「Claudeforce」を発表しました。Salesforce in Claude プラグインは商談準備やパイプライン管理など37のセールススキルを同梱しますTRUST — Claudeforce の推論は Amazon Bedrock 経由で Salesforce Trust Boundary の内側に留まります。データが境界の外へ出ない構成が、規制業種への回答になっていますBETA — Salesforce in Claude は現在は選抜パイロット顧客向けです。9月中のオープンベータ移行が予告されていますLIMITS — 週次上限の50%増は9月13日までです。9月14日からはプロモ前比+25%が恒久水準になります。今日の水準と比べると約17%の削減にあたりますRELEASE — Claude Code は v2.1.251(8月28日)から新しいリリースが出ていません。約0.8日に1本というペースからすると、4日の間隔は最長クラスです
記事一覧/Cowork
Cowork/2026-05-15中級

Cowork スケジュールタスクで git clone が失敗するとき — /tmp 権限とディスク不足を素早く診断する

Cowork の自動タスクで git clone が Permission denied や No space left on device で失敗する原因と、/tmp の所有者確認・$HOME フォールバック・掃除コードの安全化を、VM 上で実測しながら整理します。

Cowork36troubleshooting61git17VM2ディスク管理スケジュールタスク20

深夜に動くはずのスケジュールタスクが、朝になっても記事を1本も出していない。ログを開くと、原因はこの1行だけでした。

fatal: could not create work tree dir '/tmp/repos/claudelab.net': Permission denied

/tmp は誰でも書き込める一時領域のはずです。ディスク残量も 1,600 MB 以上ありました。それでも弾かれる。調べてみると、/tmp/repos/ というサブディレクトリそのものが nobody:nogroup 所有になっており、そのときのセッションユーザーには書き込み権限がなかったのです。

私はこの症状に何度か出会っていて、そのたびに「前回書いたはずの回避コードが、なぜか効いていない」という同じ落胆を味わってきました。個人開発で自動化を組んでいると、この種の環境依存の失敗はいつも静かに起きます。以下では原因だけでなく、回避コードのほうに潜んでいた欠陥まで含めて書きます。掲載しているシェルの挙動は、症状が再発したときに私自身が Cowork の VM 上で走らせ直して確認したものです。


なぜ /tmp/repos が nobody 所有になるのか

Cowork の VM では、/tmp/ 以下のサブディレクトリが前のセッション由来の所有者のまま残ることがあります。前のセッションが nobody:nogroup として /tmp/repos/ を作っていた場合、次のセッションは別のユーザーコンテキストで動くため、そのディレクトリには書き込めません。

鍵になるのは、スティッキービットが効く範囲です。/tmp/ 直下は drwxrwxrwt で全ユーザーが書き込めますが、その下に作られた /tmp/repos/ は通常の rwxr-xr-x で作成されます。書き込めるのは所有者だけです。

実際に再発したときの VM を覗くと、こうなっていました。

$ ls -ld /tmp /tmp/repos
drwxrwxrwt 31 nobody nogroup 4096 /tmp
drwxr-xr-x  3 nobody nogroup 4096 /tmp/repos

$ id
uid=1296(trusting-keen-edison) gid=1296(trusting-keen-edison)

/tmp は誰でも書ける。/tmp/reposnobody だけが書ける。そして自分は nobody ではない。3行並べると当たり前の話ですが、エラーメッセージが指しているのは /tmp/repos/claudelab.net のほうなので、視線が一段深いところに引っ張られて気づきにくいのだと思います。


mkdir -p が通ってしまうから、気づくのが遅れる

この問題が厄介なのは、手前の処理が静かに成功してしまう点にあります。

$ mkdir -p /tmp/repos
$ echo $?
0

mkdir -p は対象がすでに存在すれば何もせず終了コード 0 を返します。その既存ディレクトリに書き込めるかどうかは見ていません。 ですから次のような書き方は、安全弁のように見えて実際にはまったく作動しません。

# ❌ 効かない書き方
mkdir -p /tmp/repos 2>/dev/null || WORK="$HOME/repos/claudelab.net"

/tmp/reposnobody 所有で存在している状況では mkdir -p が 0 を返すため、|| の右辺は永久に実行されません。そのまま git clone に進んで、そこで初めて Permission denied を受け取ります。私が「回避コードを入れたはずなのに効いていない」と感じていた原因は、まさにこれでした。

判定は作成の成否ではなく、書き込み可否そのもので行う必要があります。

# ✅ 実際に判定できる書き方
[ -d /tmp/repos ] && [ ! -w /tmp/repos ] && echo "書き込み不可"

先ほどの VM でこの2条件を評価すると、期待どおり「書き込み不可」と表示され、フォールバックが発火しました。-w はディレクトリに対しても機能するので、追加のツールは要りません。

この問題が起きやすいのは、経験上つぎの3つの場面です。Cowork の更新やセッション再起動で内部ユーザーコンテキストが切り替わった直後。複数のスケジュールタスクが同じ /tmp/repos/ を共有していて、先に走ったタスクが nobody として作ってしまったとき。そして前回のタスクが git 操作の途中で異常終了し、中途半端なディレクトリを残したとき。共通しているのは「前回の実行状態が今回に影響する」という点です。スケジュールタスクは毎回まっさらな環境で起動しているように見えて、/tmp/ 以下はセッションをまたいで共有されています。


対処法:$HOME/repos へのフォールバック

最も確実なのは、/tmp/repos/ が使えないときに $HOME/repos/ へ自動的に切り替えることです。

# /tmp/repos の「書き込み可否」を見てフォールバックする
if [ -d /tmp/repos ] && [ ! -w /tmp/repos ]; then
  echo "⚠️ /tmp/repos が書き込み不可(nobody 所有の可能性)— $HOME/repos に切り替え"
  WORK="$HOME/repos/claudelab.net"
elif mkdir -p /tmp/repos 2>/dev/null && [ -w /tmp/repos ]; then
  WORK="/tmp/repos/claudelab.net"
else
  WORK="$HOME/repos/claudelab.net"
fi
 
mkdir -p "$(dirname "$WORK")" || { echo "⛔ 作業ディレクトリを作成できません"; exit 1; }
echo "📁 作業ディレクトリ: $WORK"

ポイントは elif の側でも mkdir -p の成否だけで判断せず、続けて [ -w /tmp/repos ] を確認していることです。作れたことと書けることは別物だ、という一点さえ押さえておけば、この分岐は素直に読めます。

$HOME は Cowork の VM では /sessions/セッション名/ 以下に展開され、現在のセッションが所有しているため確実に書き込めます。


掃除コードが作業ディレクトリごと消してしまう

ディスク不足に備えて「古いリポジトリを自動削除する」処理を入れている方は多いと思います。私も入れていました。よく見かけるのは、こういう書き方です。

# ❌ 危険:作業ディレクトリごと消える
find "$(dirname "$WORK")" -maxdepth 1 -type d \
  -not -name "$(basename $WORK)" \
  -exec rm -rf {} + 2>/dev/null

意図は「/tmp/repos/ の中から、いま使うリポジトリ以外を消す」です。ところが find探索の起点そのものも結果に含めます/tmp/repos の basename は repos であって claudelab.net ではないため、-not -name の除外をすり抜け、親ディレクトリごと rm -rf の対象になります。

実際に検証用のディレクトリを作って走らせました。

# 実行前
/tmp/t1/repos/claudelab.net/KEEPME
/tmp/t1/repos/gemilab.net
/tmp/t1/repos/rorklab.net

# 上記コマンドを実行

# 実行後
ls: cannot access '/tmp/t1/repos': No such file or directory
残すはずだった KEEPME → 消失

守ろうとしたディレクトリごと消えました。しかもこの処理は「残量が閾値を下回ったとき」にしか走らないため、通常のテストではまず再現しません。ディスクが逼迫した日にだけ、静かに作業場所を破壊します。

修正は1語です。-mindepth 1 を足して、起点そのものを結果から外します。

# ✅ 安全:起点を除外する
find "$(dirname "$WORK")" -mindepth 1 -maxdepth 1 -type d \
  -not -name "$(basename "$WORK")" \
  -exec rm -rf {} + 2>/dev/null

同じ検証を通すと、今度は claudelab.netKEEPME がそのまま残り、他のリポジトリだけが消えました。あわせて $WORK は必ずダブルクォートで囲んでください。パスに空白が入ったときに basename の引数が割れます。


ディスク不足(ENOSPC)を含めた診断ブロック

Permission denied と No space left on device はどちらも git clone を止めますが、対処は別物です。スケジュールタスクの冒頭で両方をまとめて診断する形にしておくと、朝のログを読む時間が短くなります。

もう一つ、残量チェックには落とし穴があります。df に存在しないディレクトリを渡すと出力が空になり、${FREE_MB:-0} が 0 と評価されて「残量ゼロ」と誤判定されます。手元で確認した挙動はこうでした。

$ FREE_MB=$(df /tmp/does-not-exist --output=avail -m 2>/dev/null | tail -1 | tr -d ' ')
$ echo "[${FREE_MB}] -> ${FREE_MB:-0}"
[] -> 0

初回実行時はまだ作業ディレクトリが無いのが普通ですから、df を呼ぶ前にディレクトリを作っておくか、空判定を挟む必要があります。以上を織り込んだブロックが次のものです。

WS="$(ls -d /sessions/*/mnt/Dolice\ Labs 2>/dev/null | head -1)"
GITHUB_TOKEN=$(grep -A1 "Claude Lab" "${WS}/_documents/_github_tokens/github_tokens.txt" \
  | tail -1 | tr -d '[:space:]')
REPO_URL="https://${GITHUB_TOKEN}@github.com/masakihirokawa/claudelab.net.git"
 
# --- 1. 書き込み可否で作業先を決める ---
if [ -d /tmp/repos ] && [ ! -w /tmp/repos ]; then
  WORK="$HOME/repos/claudelab.net"
elif mkdir -p /tmp/repos 2>/dev/null && [ -w /tmp/repos ]; then
  WORK="/tmp/repos/claudelab.net"
else
  WORK="$HOME/repos/claudelab.net"
fi
BASE="$(dirname "$WORK")"
mkdir -p "$BASE" || { echo "⛔ $BASE を作成できません"; exit 1; }
 
# --- 2. 残量チェック(空文字を「不明」として扱う) ---
FREE_MB=$(df "$BASE" --output=avail -m 2>/dev/null | tail -1 | tr -d ' ')
if [ -z "$FREE_MB" ]; then
  echo "⚠️ 残量を取得できませんでした($BASE)— 掃除はスキップします"
else
  echo "📊 残量: ${FREE_MB}MB(作業先: $WORK)"
  if [ "$FREE_MB" -lt 300 ]; then
    echo "⚠️ 残量不足 — 他のリポジトリを削除します"
    find "$BASE" -mindepth 1 -maxdepth 1 -type d \
      -not -name "$(basename "$WORK")" \
      -exec rm -rf {} + 2>/dev/null
    FREE_MB=$(df "$BASE" --output=avail -m 2>/dev/null | tail -1 | tr -d ' ')
    echo "📊 削除後残量: ${FREE_MB:-不明}MB"
  fi
  if [ "${FREE_MB:-0}" -lt 200 ]; then
    echo "⛔ それでも残量不足 — タスクを中止します"
    exit 1
  fi
fi
 
# --- 3. clone または pull ---
if [ -d "$WORK/.git" ]; then
  cd "$WORK" || exit 1
  git remote set-url origin "$REPO_URL"
  git pull --rebase origin main || {
    cd "$BASE" || exit 1
    rm -rf "$WORK"
    git clone --depth 1 "$REPO_URL" "$WORK" || exit 1
    cd "$WORK" || exit 1
  }
else
  git clone --depth 1 "$REPO_URL" "$WORK" || exit 1
  cd "$WORK" || exit 1
fi
 
git config user.email "masakihirokawa@gmail.com"
git config user.name "Masaki Hirokawa"
echo "✅ リポジトリ準備完了"

git pull が失敗したときの再 clone で、rm -rf "$WORK" の前に cd "$BASE" を挟んでいるのは、削除済みのディレクトリに居座ったまま git clone を呼ぶと環境によっては失敗するためです。細かい話ですが、リカバリ経路こそ落ち着いて書いておきたいところです。


/tmp と $HOME をどう使い分けるか

議論より実測が早いので、実際に計測しました。対象は Claude Lab のリポジトリ 1 本です。

操作所要時間備考
git clone --depth 1(新規)約 3.8 秒作業ツリー込みで 45 MB
git pull --rebase(差分なし)約 0.8 秒既存の shallow クローンに対して

1 回あたりの差は 3 秒ほどです。単発なら誤差の範囲でしょう。ただ 4 サイト分を 1 日に何度も回すと、この 3 秒はタスクごとに積み上がっていきます。それ以上に効いてくるのは、clone は毎回ネットワークに依存するという点です。差分更新なら、通信が不安定な時間帯でも失敗しにくくなります。

なお --depth 1 の shallow クローンに対して git pull --rebase origin main が使えるかは、迷いやすいところだと思います。手元で確認した限りでは問題なく動作し、git rev-parse --is-shallow-repositorytrue のまま、ローカルのコミット数も 1 のままでした。履歴を掘る必要がないタスクなら、shallow のまま差分更新を続けて構いません。

判断の目安としては、単発スクリプトや履歴を残したくない処理は /tmp、1 日に複数回動くスケジュールタスクは $HOME/repos/ の永続リポジトリ方式、という分け方に落ち着いています。/tmp を使う場合でも、書き込み可否チェックだけは必ず入れてください。


よくある関連エラーとその見分け方

同じ git clone の失敗でも、メッセージを見れば原因はほぼ確定します。

エラーメッセージ原因最初にやること
Permission denied親ディレクトリの所有者問題ls -ld で所有者を確認し、$HOME/repos/ へ切り替える
No space left on deviceディスク不足df -h で確認し、他のリポジトリと .next/ を削除する
Could not resolve hostネットワーク未接続VM のインターネットアクセス設定を確認する
Repository not foundトークン期限切れ/リポジトリ名変更PAT を再生成し、SKILL.md 側も更新する
index.lock: File exists前回の git プロセスが異常終了.git/index.lock を削除するか、再 clone する

Repository not found については一点だけ補足させてください。トークンが無効なときも同じ文言が返ることがあります。リポジトリ名の打ち間違いを疑う前に、まずトークンの有効期限を確認したほうが早く着地します。


SKILL.md への組み込み方

スケジュールタスクを SKILL.md で管理している場合は、Step 0 のリポジトリ準備の冒頭に次を置いておくと、nobody 問題が再発しても自動で迂回できます。

# Step 0 の冒頭(書き込み可否で判定する)
_BASE="/tmp/repos"
if [ -d "$_BASE" ] && [ ! -w "$_BASE" ]; then
  _BASE="$HOME/repos"
elif ! mkdir -p "$_BASE" 2>/dev/null || [ ! -w "$_BASE" ]; then
  _BASE="$HOME/repos"
fi
mkdir -p "$_BASE" || exit 1
WORK="${_BASE}/claudelab.net"

SKILL.md を直したら、スケジュールタスク本体のプロンプトにも同じ変更を反映してください。両者は別の文書として読み込まれるため、片方だけ直しても次回の実行で古い挙動に戻ります。手動実行では気づきにくく、私はこれで一度、直したはずの不具合を翌朝もう一度見ることになりました。


次にとるべきアクション

まず ls -ld /tmp/repos を実行してください。所有者に nobody nogroup が見えたら、Step 0 の判定を mkdir -p の成否から -w に置き換えます。ここが今回いちばん効く一手です。

次に、掃除コードの find を開いて -mindepth 1 があるか確かめてください。無ければ足してください。ディスクが逼迫した日にだけ発火して作業場所を消す処理は、静かなぶん厄介です。

どちらの修正も数分で終わります。自動化は何も起きていないときではなく、何かが起きたときに真価を問われます。同じ症状で朝を無駄にしている方の役に立てば嬉しいです。お読みいただきありがとうございました。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Cowork2026-06-30
3日前のローカルミラーで判断していた — 無人タスクが古い作業コピーを信じて二重作業する事故を止める
速度のために使い回す永続クローンは、いつの間にかリモートとずれます。同期を確かめないまま「この記事はもう直したか」を読みに行くと、無人タスクは古い木を信じて二重編集や空振り成功を起こします。HEAD 突き合わせと書き込み可否のプリフライト、自己修復の再クローンをbashで実装します。
Cowork2026-08-29
連携フォルダに置いたロックが、二度目の無人実行を締め出すまで
クラウド同期の連携フォルダでは作成も改名も通るのに、削除だけが拒まれます。そこへ二重起動防止のロックを置いた結果、二度目以降の無人実行が永久に見送られました。三方式の実測と、ロックの置き場所を分ける実装をまとめます。
Cowork2026-07-11
夜間に回すMCPコネクタの健康状態を自前で見える化する — 個人運用のための軽量ヘルス台帳
Enterprise 向けのコネクタ可観測性がなくても、1回のツール呼び出しにつき1行を書き足すだけでMCPコネクタのエラー率とレイテンシは見えるようになります。個人でスケジュールタスクを回す立場のための、動くヘルス台帳の作り方。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →