2026年7月8日水曜日

Ubuntu glab にコマンドをインストールするスクリプト

Ubuntu glab にコマンドをインストールするスクリプト

概要

シェルスクリプトを紹介します

環境

  • Ubuntu 24.04
  • glab 1.106.0

スクリプト

  • vim install_glab_on_ubuntu.sh
set -euo pipefail

sudo apt-get update
sudo apt-get install -y curl tar jq

ARCH_RAW="$(uname -m)"
case "$ARCH_RAW" in
  x86_64) ARCH_SUFFIX="amd64" ;;
  aarch64|arm64) ARCH_SUFFIX="arm64" ;;
  *)
    echo "Unsupported architecture: $ARCH_RAW" >&2
    exit 1
    ;;
esac

API_URL="https://gitlab.com/api/v4/projects/gitlab-org%2Fcli/releases/permalink/latest"
RELEASE_JSON="$(curl -fsSL "$API_URL")"
TAG_NAME="$(echo "$RELEASE_JSON" | jq -r '.tag_name')"

# ここが重要: 現在の命名は glab_<ver>_linux_<arch>.tar.gz
DOWNLOAD_URL="$(echo "$RELEASE_JSON" | jq -r --arg arch "$ARCH_SUFFIX" '
  .assets.links[]
  | select((.name // "") | test("_linux_" + $arch + "\\.tar\\.gz$"))
  | (.direct_asset_url // .url)
' | head -n1)"

if [[ -z "$DOWNLOAD_URL" || "$DOWNLOAD_URL" == "null" ]]; then
  echo "No matching asset URL found for arch: $ARCH_SUFFIX" >&2
  echo "DEBUG: available asset names:" >&2
  echo "$RELEASE_JSON" | jq -r '.assets.links[].name' >&2
  exit 1
fi

TMP_DIR="/tmp/glab-install"
TARBALL_PATH="$TMP_DIR/glab.tar.gz"

echo "DEBUG: ARCH_RAW=$ARCH_RAW"
echo "DEBUG: ARCH_SUFFIX=$ARCH_SUFFIX"
echo "DEBUG: API_URL=$API_URL"
echo "DEBUG: TAG_NAME=$TAG_NAME"
echo "DEBUG: DOWNLOAD_URL=$DOWNLOAD_URL"
echo "DEBUG: TMP_DIR=$TMP_DIR"
echo "DEBUG: TARBALL_PATH=$TARBALL_PATH"

rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"

curl -fL "$DOWNLOAD_URL" -o "$TARBALL_PATH"
tar -xzf "$TARBALL_PATH" -C "$TMP_DIR"

GLAB_BIN="$(find "$TMP_DIR" -type f -name glab | head -n1)"
if [[ -z "$GLAB_BIN" ]]; then
  echo "glab binary not found in extracted archive" >&2
  exit 1
fi

sudo install -m 0755 "$GLAB_BIN" /usr/local/bin/glab
glab --version

解説

いろいろやっていますが https://gitlab.com/gitlab-org/cli/-/releases ここから tar をダウンロードし PATH 上に配置しているだけです

最後に

あとは glab auth でログインしましょう

export GITLAB_TOKEN='glpat-c-xxx'
glab auth login --hostname gitlab.devops.nifcloud.net --token <<< "$GITLAB_TOKEN"
glab auth status --hostname gitlab.devops.nifcloud.net

2026年7月7日火曜日

code-server でファイルを開く際に必ず新しいタブで開くようにする方法

code-server でファイルを開く際に必ず新しいタブで開くようにする方法

概要

タイトルの通り

環境

  • code-server 4.126.0

対策方法

"workbench.editor.enablePreview": false

2026年7月6日月曜日

Mac で Ctrl+g で勝手に Gemini が起動するのを止める方法

Mac で Ctrl+g で勝手に Gemini が起動するのを止める方法

概要

Chrome のショートカットキーで勝手に割り当てられるようになってしまったようです

環境

  • macOS 26.5.1
  • Chrome 149.0.7827.201

方法

  1. chrome://settings/ai/gemini を開く
  2. キーボードショートカットで Gemini を開きますのバツボタンを押す

これが

こうなれば OK です

最後に

たぶんそのうちデフォルトで無効になるはずです

参考サイト

2026年7月4日土曜日

codex を Ubuntu で動かす場合のサンドボックス設定

codex を Ubuntu で動かす場合のサンドボックス設定

概要

自動化する場合には書き込めるように codex がサンドボックスを作成できるようにしてあげる必要があります

環境

  • Ubuntu 24.04
  • codex 0.142.5

主なエラー

Unfortunately, I **cannot execute any commands** in this environment — the sandbox is rejecting all shell execution with:

bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted


This means I cannot:
- Read the actual file contents
- Apply patches
- Run tests

Could you check if there's a sandbox configuration issue? Once commands can run, I can implement the fix directly. Alternatively, if you can share the contents of the two files, I can produce the exact patch needed.
Codex's Linux sandbox uses bubblewrap and needs access to create user namespaces.

対処方法

  • sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0

以下で確認し 0 になっていれば OK です

  • sudo sysctl kernel.apparmor_restrict_unprivileged_userns
0

インスタンスの再起動などは不要です

最後に

danger-full-access は可能な限りやめましょう
名前的にもやばいオプション名なので

参考サイト

2026年7月3日金曜日

Codex + LiteLLM + カスタムOpenAIエンドポイントの設定方法

Codex + LiteLLM + カスタムOpenAIエンドポイントの設定方法

概要

素の OpenAI エンドポイントではなく特定の環境でラップされている URL の場合には LiteLLM を挟みましょう もしくは API が完全非互換でなかったり https プロトコルのみ提供されている場合なども LiteLLM を挟むと解決することがあります

環境

  • Ubuntu 24.04
  • codex 0.142.5
  • LiteLLM 1.90.0

LiteLLM 設定

api_base と api_key に自身の環境のカスタムOpenAIエンドポイントとカギを設定しましょう

  • vim litellm/litellm_config.yaml
model_list:
  - model_name: claude-chatAI
    litellm_params:
      model: anthropic/claude-sonnet-4-6
      api_base: https://your-api-endpoint
      api_key: xxx
      max_tokens: 4096
      temperature: 0.2

server_settings:
  port: 4000
  • vim litellm/compose.yaml
services:
  litellm:
    image: docker.litellm.ai/berriai/litellm:latest
    container_name: litellm
    ports:
      - "4000:4000"
    volumes:
      - ./litellm_config.yaml:/app/config.yaml
    restart: unless-stopped
    command: ["--config", "/app/config.yaml"]
  • docker compose up -d

codex 設定

base_url は LiteLLM が Listen しているアドレスで env_key は下記の SONNET_API_KEY を指定します
LiteLLM 側で認証情報を指定していますが一応 codex 側でも鍵情報を指定するためです

  • vim ~/.codex/litellm.config.toml
model_provider = "litellm"
model = "anthropic/claude-sonnet-4-6"
web_search = "disabled"

[model_providers.litellm]
name = "sonnet"
base_url = "http://localhost:4000"
env_key = "SONNET_API_KEY"
wire_api = "responses"

動作確認

  • export SONNET_API_KEY="xxx"
  • codex --profile litellm

これでインタラクティブモードで起動するので「test」など投げて応答がくれば OK です

最後に

たぶん OpenInterpreter も同じ方法でいけます
--full-auto オプションなどは廃止になっているの注意しましょう

参考サイト

https://docs.litellm.ai/docs/tutorials/openai_codex

2026年7月2日木曜日

OpenInterpreter や codex でカスタムエンドポイントURLを指定する方法

OpenInterpreter や codex でカスタムエンドポイントURLを指定する方法

概要

基本は config.toml に各方式になっています
環境変数 (OPENAI_BASE_URl)や --base_url は使いません

環境

  • OpenInterpreter 0.0.17
  • codex 0.142.5

~/.codex/mygpt.config.toml

model_provider = "mygpt"
model = "gpt-5.1"

[model_providers.mygpt]
name = "GPT5"
base_url = "https://your-api-endpoint"
env_key = "GPT5_API_KEY"
wire_api = "responses"

基本はプロファイルと後に作成します
config.toml は全体で共通の設定を記載するの個別のプロファイル別の情報は書きません

実行方法

env_key で指定した環境変数名に API キーを設定します

  • export GPT5_API_KEY="xxx"
  • codex --profile mygpt

最後に

codex の部分をそのまま openinterpreter に書き換えれば OpenInterpreter でも使えます

参考サイト

2026年7月1日水曜日

golang のテクニックとかイディオムとかメモ

golang のテクニックとかイディオムとかメモ

概要

忘れないようにメモです
気づいたことは随時追記します

基本的な使い方というよりかは実務で使えそうな中から上級者よりの内容を記載しています
基本的な文法というよりかは設計時に使えるテクニックなどを紹介しています

環境

  • macOS 26.5.1
  • golang 1.26.4

interface について

  • 使う目的は「差し替え可能」にするため
  • 簡単に言えばテスト用 -> 結果としてテストのためになっている
  • シンプルな interface にしなければならない
    • メソッドは 1 or 2 個くらい (必要最低限の原則)
  • 明示的な継承などは golang ではしない (できない)
    • 同じ振る舞いを持つ struct の代替になれる
    • golang が自動的に判断してくれる
type RedisClient interface {
	LRange(ctx context.Context, key string, start, stop int64) *redis.StringSliceCmd
	LPush(ctx context.Context, key string, values ...interface{}) *redis.IntCmd
	Del(ctx context.Context, keys ...string) *redis.IntCmd
}

type RedisRepository struct {
	client RedisClient
}

func NewRedisRepository(client RedisClient) *RedisRepository {
	return &RedisRepository{client: client}
}

interface の置き場所

  • 基本が使う側に定義する
    • これが不思議な感じがするが golang のルールでそうなっている
    • 使う側で振る舞いが柔軟に変更できるようになる
  • 共通インタフェースは「一番内側(ドメイン or アプリケーション層)」に置く
    • インタフェースの構成が変わっても影響しないのであればまとめて OK
    • この場合は使う側ではなく使われる側に置く

interfaceは「後から作る」

  • 最初からinterfaceを作らない
  • 使う側が必要になったときに作る
  • golang の哲学らしい

継承っぽいことをしたい場合は embedding

  • struct 内のメンバーに別の struct を値レシーバで定義すると勝手にそっちのメソッドを使えるようにしてくれる
    • structを埋め込むとメソッドが昇格(promotion)される
    • 値でもポインタでも挙動は変わる
type Controller struct {
	controller.BaseController
	memoService *service.MemoService
}

とすると Controller 側で BaseController 側のメソッドが c.CurrentUsername() という感じで使える

func (c *BaseController) CurrentUsername() string {
	if name := c.GetSession("user"); name != nil {
		if username, ok := name.(string); ok {
			return username
		}
	}
	return "anonymous"
}

New するメソッド (コンストラクタ) は基本的にポインタ型を使う

  • ポインタ型を使うとコピーではなく参照になるので具現化した大元の値まで書き換えされる
func NewController(svc *service.MemoService) *Controller {
	return &Controller{memoService: svc}
}

値レシーバとポインタレシーバ

  • 値レシーバとポインタレシーバでinterfaceの満たし方が変わる
  • どちらのレシーバを使ってメソッドを定義したかによって参照を渡すか値を渡すか決まる

以下のような場合は参照を渡さないとインタフェースを満たさないのでダメ

type I interface {
	Foo()
}

type S struct {}

func (s *S) Foo() {}

上だとエラーになる

var i I = S{}    // NG
var i I = &S{}   // OK

メソッドと関数は違う

  • 簡単に言えばメソッドは struct 配下
  • 関数は struct とは関係ない単独の関数
  • メソッドは状態(struct)に紐づく振る舞い
  • 関数は純粋な処理(副作用なしが理想)

メソッド

func (c *Controller) Login() {
	c.LogAccess("Login")
	c.RenderLayout("account/login.tpl")
}

関数
関数はレシーバの指定がない=特定の struct 配下にいない

func Replace(str string, from string, to string) string {
	return strings.Replace(str, from, to, -1)
}

lazy init はある

  • sync.OnceValue を使うのが基本
  • 使うケースはデータベースや外部リソース接続時
  • それ以外のケースでは golang では基本的には DI or DIP を使う
  • struct 内のメンバーを初期化する場合に lazy init はあまり使わない

以下のような golang では書き方はあまりしない

例: ListText が呼ばれたときに初めて textService が初期化される

type MemoService struct {
	textService  *textsvc.Service
}

func (s *MemoService) textSvc() *textsvc.Service {
	if s.textService == nil {
		s.textService = textsvc.NewService(s.repo.Text())
	}
	return s.textService
}

func (s *MemoService) ListText(ctx context.Context, username string) ([]string, error) {
	return s.textSvc().List(ctx, username)
}

generics について

  • 使うケースとしては同じ振る舞いで異なる型の引数や返り値を返す場合に使うと処理を1つにまとめられる
  • 可読性的には落ちる気がする
    • T が直感的になるまで大変
    • T が何の最終的に何の型になのか一見してわからない
  • 型安全な共通処理を作るため
  • interfaceでは表現できない「型の制約」を扱える

これを

func SumInt(a, b int) int {
	return a + b
}

func SumFloat(a, b float64) float64 {
	return a + b
}

こうできるのがジェネリクス化

func Sum[T int | float64](a, b T) T {
	return a + b
}

internal ディレクトリについて

  • モジュール外に公開されない機能
  • 同一モジュール内でのみimport可能
  • パッケージ境界を強制できるのがメリット
  • internal 配下にコードを置くと勝手にそうなってくれる
  • Python も __init__.py のスコープあり版のイメージ
  • Web アプリとか作成していると基本全部 internal 配下においても問題はないので internal が肥大化しないように注意しなければならない
    • 例えばデータベースに関する処理だけ置くとか
    • internal/database/database.go

DIP しやすい

  • golang は全体的に interface に依存させるほうがベストプラクティスになるケースが多い
  • そうなると自然と DIP となりクリーンアーキテクチャよりの設計に勝手になっていく印象
  • クリーンアーキテクチャの話になると下位から上位の意識がかなり大事になるので厳密には必ずなるわけではない
    • 書きやすいというレベル

// application(上位層)
type PaymentClient interface {
	Charge()
}

type PaymentService struct {
	client PaymentClient
}

// infrastructure(下位層)
type StripeClient struct {}

func (s *StripeClient) Charge() {}

error は特別な存在(例外がない)

  • Goには例外(try-catch)がない
  • errorは戻り値として扱う
  • 明示的に処理するのが前提
  • errors.Is / errors.As を使う
  • エラーをラップする (fmt.Errorf("%w", err))
v, err := DoSomething()
if err != nil {
    return err
}

最後に

golang は他の言語に比べてルールというかイディオム的なのが多い気がします

参考サイト