sasacodeドキュメント

sasacode ドキュメント

README では書ききれない、画面の見方、権限の判定の流れ、設定と同梱プラグインの全項目、プラグインの共有、ヘッドレス実行、困ったときの対処をまとめた。v0.9.9 時点の内容。

目次

    01はじめに

    インストール

    curl -fsSL https://sasanokusa.com/sasacode/install.sh | sh

    macOS(Apple Silicon / Intel)と Linux(x64 / arm64、glibc / musl、AVX2 のない CPU 向けの baseline 版)の単一バイナリが ~/.local/bin/sasacode に入る。Bun も Node.js も要らない。Windows は WSL から使う。

    • インストーラーとバイナリは GitHub Releases の最新版から取り、SHA256 を確かめてから置く。
    • 版を固定する:SASACODE_VERSION=v0.9.9。置き場所を変える:SASACODE_INSTALL_DIR=/usr/local/bin。
    • 更新は sasacode update(インストーラーと同じ検証つき。--check で確かめるだけ)か、同じインストールコマンドをもう一度実行する。新しい版が出ると起動時に一度だけ知らせる(設定の "updateCheck": false で止まる)。削除は ~/.local/bin/sasacode と ~/.sasacode(設定・セッション・プラグイン)を消す。

    最初の設定

    sasacode --version          # 初回起動で ~/.sasacode/.env ができる
    $EDITOR ~/.sasacode/.env    # 使うプロバイダーのキーだけ埋める
    sasacode                    # 対話モードで始める

    .env には対応するプロバイダーのキーが空欄で並んでいる。空欄は「未設定」として扱うので、使うものだけ埋めればよい。キーの代わりに OS のキーチェーンに入れることもできる(キーの探し方)。

    どのモデルで始まるか

    -m provider/model を付けたそれを使う。
    設定の model~/.sasacode/config.json(信頼したプロジェクトならプロジェクトの設定も)。
    キーのある最初のプロバイダーの既定モデル.env の上から順に見る。
    キーがなく ChatGPT にログインしているopenai-codex/gpt-5.5。

    起動してからは /model で一覧から選び直せる。

    02TUI(対話モード)

    画面の構成

    全画面で動く。会話は上でスクロールし、状態・入力欄・フッターは下に固定される。
    • 会話:あなたの入力(背景色つき)、推論(∴、既定では最後の2行だけ)、ツール呼び出し(● の色:灰=待ち、黄=実行中、緑=完了、赤=エラー)、応答。ctrl+o で推論とツール出力の全文を開く。
    • 状態:実行中の表示と、実行中に送った(次のターンに届く)メッセージ。
    • フッター:左から、モデル、推論の深さ、権限モード、コンテキストの使用量(使用量/上限と割合)、セッション ID、料金(分かるときだけ)。2行目はプラグインの状態(TODO、ゴール、MCP の接続数、バックグラウンドジョブ、要約中など)。

    キー操作

    キー動作
    enter / shift+enter・alt+enter送信 / 改行
    ↑ ↓入力履歴(~/.sasacode/history.jsonl、直近 200 件)
    tab補完:スラッシュコマンド、その引数(/model のモデル名など)、ファイルパス
    esc生成・ツール実行を中断。中断したことは次の入力でモデルに伝わる
    実行中に enterメッセージを予約し、次のターンで届ける
    ctrl+oツール出力と推論の折りたたみを切り替え
    shift+tab権限モードを順に切り替え
    pageup pagedown・ホイール会話をスクロール。上に戻っている間は右端にスクロールバーと「最新へ」
    ctrl+↑ / ctrl+↓前 / 次の自分の入力へ
    ctrl+home / ctrl+end会話の先頭 / 最新へ
    ctrl+shift+f会話の中を検索(enter で次、shift+enter で前、esc で閉じる)
    ドラッグ選択し、離すとクリップボードへコピー。ダブルクリックで単語、トリプルクリックで行
    /exit・ctrl+c 2回・ctrl+d終了。使用量と再開コマンドの要約が端末に残る
    コピー全画面ではマウスを sasacode が受け取るので、端末の標準の選択は option(macOS)/ alt を押しながらドラッグする。sasacode の選択は pbcopy / wl-copy / xclip で直接クリップボードに入れ、SSH の先では端末経由(OSC 52)で送る。/copy は直前の応答全体をコピーする。

    コマンド

    コマンド内容提供元
    /modelプロバイダーから取った一覧から選ぶ。文字を打つと絞り込む。/model <provider/model> で直接、/model --refresh で取り直しコア
    /effort推論の深さ(詳細)コア
    /resume /clear /fork /session過去のセッション / 新しいセッション / 過去のメッセージから分岐 / ID と保存先コア
    /copy /permission /help /exit直前の応答をコピー / 権限モード / ヘルプ / 終了コア
    /usage使用量、プランの残り、日別グラフ(詳細)usage
    /goalセッションのゴールgoal
    /bgバックグラウンドジョブの一覧・詳細・停止background-sessions
    /reconnect接続の復旧を待って再開(status で確認だけ)auto-reconnect
    /compact会話を要約してコンテキストを空けるcompaction
    /undowrite / edit によるファイルの変更を1件戻す(list で一覧)checkpoints
    /image画像を次のメッセージに添付(引数なしでクリップボード、clear で取り消し)。@パス やドラッグ&ドロップでも付けられるimage-attach
    /taskサブエージェントの一覧・詳細、send <id> <内容> で指示、stop <id> で停止subagent
    /presets /jev権限プリセットの一覧 / Jev の状態と直近の判定(/jev on・/jev off で切り替え。jev-guard を入れたとき)permission-presets / jev-guard
    /mcp /skills /skill:<name> /browsrMCP の接続状態(/mcp reconnect [name] で再接続。落ちたときは数回まで自動で再接続する) / Skills の一覧 / Skill を明示して使う / browsr の状態mcp / skills / browsr

    TUI の設定

    設定既定内容
    tui.altScreentruefalse で従来の表示(会話を端末のスクロールバックに残す)
    tui.belltrue30 秒以上かかった実行が終わったら端末のベルを鳴らす
    SASACODE_AMBIGUOUS_WIDTH自動①のような幅の曖昧な文字を何マスで数えるか(1 / 2)。起動時に端末に問い合わせて合わせる

    03モデルとプロバイダー

    providerAPI 形式キー
    anthropicAnthropic MessagesANTHROPIC_API_KEY(空なら SDK の ant auth login)
    openai / openai-chatOpenAI Responses / Chat CompletionsOPENAI_API_KEY
    openrouterChat CompletionsOPENROUTER_API_KEY
    commandcode(-responses / -anthropic)Command Code の各形式CMD_API_KEY
    ollamaChat Completions(localhost:11434)不要
    openai-codexChatGPT プランの Codex バックエンド不要(sasacode login)

    キーの探し方

    シェルの環境変数export ANTHROPIC_API_KEY=…
    ~/.sasacode/.env空欄は無視。
    OS のキーチェーンmacOS:security add-generic-password -s sasacode -a <provider> -w
    Linux:secret-tool store --label sasacode service sasacode account <provider>
    読まないもの作業ディレクトリの .env と bunfig.toml。リポジトリが接続先(ANTHROPIC_BASE_URL など)を差し替えたり、起動時にコードを実行させたりできないようにするため。セッションのログには、使っているキーを [REDACTED] に置き換えてから書く。

    自前のサーバー

    sasacode endpoint add pgx http://gpu-box:8000/v1          # 形式を判別して保存
    sasacode endpoint add mygw https://llm.example.com/v1 --key-env MYGW_KEY
    sasacode endpoint list
    sasacode -m pgx/<モデル名>

    GET /v1/models の応答から、OpenAI 形式か Anthropic 形式かを判別し、URL も SDK に合わせて整える。llama.cpp は /props、Ollama は /api/show から実際のコンテキスト長も取る。判別の結果は ~/.sasacode/endpoints.json にキャッシュする。表にないモデルのコンテキスト長が違うときは modelOverrides で直す。

    { "modelOverrides": { "pgx/qwen3.8-flash-next": { "contextWindow": 262144, "maxOutput": 32000 } } }

    ChatGPT プラン

    sasacode login でブラウザが開き、ChatGPT アカウントでログインすると openai-codex/… のモデルが API キーなしで使える。利用分はプランの Codex の枠から引かれ、残りは /usage plan で見られる。SSH の先などブラウザがこのマシンに戻れないときは、ログイン後にブラウザが表示した URL を貼り付ける。認証情報は ~/.sasacode/codex-auth.json(本人だけが読める)に置き、期限が近づけば自動で更新する。

    非公式OpenAI の Codex CLI と同じ仕組み(公開クライアントと PKCE)を使う。OpenAI の都合で使えなくなることがある。

    推論の深さ(/effort・--thinking)

    off / low / medium / high / xhigh / max の6段階。既定は high。送り方は API 形式ごとに違う。

    API 形式送るもの
    Anthropic Messagesadaptive thinking と effort。off なら thinking を付けない
    OpenAI Chat Completions(OpenAI 互換の自前サーバーを含む)reasoning_effort。off も none として送る(vLLM などは送らないと推論する)
    OpenAI Responses・ChatGPT プランreasoning.effort

    OpenAI 形式のサーバーは受け付ける値がまちまちなので、断られたら次の候補で送り直し、通った値を覚えて次からはそれを使う(サーバーとモデルごと)。

    段階試す順番(→ は断られたら次)
    offnone → minimal → low → 送らない
    lowlow → minimal → 送らない
    mediummedium → 送らない
    highhigh → xhigh → medium → 送らない
    xhighxhigh → high → 送らない
    maxmax → xhigh → high → 送らない
    確かめたサーバー結果
    vLLM(Qwen 3.8)off で推論が止まる。high は受け付けず(ストリームの最初のイベントで断る)、xhigh になる
    Command Code(DeepSeek V4.1)none を受け付けない。推論は止められないので、off は low になる
    Ollama推論に対応しないモデルは断るので、送らずにやり直す
    ChatGPT プランoff で推論が止まる

    04権限

    ツールを実行する前に、ルール・権限モード・プラグインの順に判定する。判定は実行前の確認であって、隔離(サンドボックス)ではない。

    判定の流れ

    tool_call フック(プラグイン)引数の書き換えや判定。ここで deny なら終わり。
    deny次へ
    deny ルール当てはまれば拒否。プラグインでも緩められない。
    拒否
    softDeny ルール拒否。ただし permission フックが「確認」まで下げられる。
    拒否(下げられる)
    ask ルールユーザーに確認。
    確認
    allow ルール&& ; | でつないだ全部が許可されているときだけ通す。$(…)・バッククォート・> を含むものは通さない。
    許可
    権限モードの既定下の表。
    許可確認
    permission フック(プラグイン)ここまでの判定を変える。厳しくするのは自由、緩めるのは下限まで(モードの既定は許可まで、softDeny は確認まで、ルールは緩められない)。jev-guard はここで働く。
    agent モードの判定どのプラグインも判定しなかった「確認」を、現在のモデルが安全か判定する。
    許可確認
    ユーザーに確認許可 / 常に許可(ルールに追加) / 拒否(理由を添えられる)。ヘッドレスでは確認できないので実行せず、理由をモデルに返す。
    実線はコア、点線の丸はプラグインが関われる段階。

    権限モード

    モード作業ディレクトリ内の read内の write / editbash・外への操作・その他
    edits(既定)許可許可確認
    ask確認確認確認
    agent許可モデルが判定(安全なら許可、それ以外は確認)
    auto許可許可許可(deny ルールと ask ルールは効く)

    agent モードで判定するのは呼び出しを作ったのと同じモデルで、呼び出しの引数も読むため、モデルを誘導する文が判定も誘導しうる。利便のための機能で、プロンプトインジェクションへの防御ではない(それには deny / ask ルールと guard プリセットを使う)。

    切り替えは shift+tab、/permission <mode>、--permission、設定の permissions.mode。

    ルールの書き方

    ルール当てはまるもの
    bashbash の呼び出しすべて
    bash(git status*)git status で始まるコマンド(* はワイルドカード)
    edit(**/.env) write(src/**)パスの glob(シンボリックリンクをたどった先で照合)
    mcp__github__*MCP サーバー github のツール全部
    bg_start(make*)プラグインのツールも同じ書き方。bg_start は permissionsAs: "bash" なので、bash のルールも当たる
    {
      "permissions": {
        "allow": ["bash(bun test*)", "bash(git diff*)"],
        "ask": ["bash(git push*)"],
        "deny": ["read(**/.env)", "edit(**/.env)", "write(**/.env)", "bash(curl * | sh)"],
        "softDeny": ["bash(git reset --hard*)"]
      }
    }

    パスのルールは書いたツールにだけ効くので、.env を守るなら read / edit / write を並べ、サブディレクトリも含めるには **/ を付ける。コマンドのルールはコマンドの文字列に合わせるだけなので、オプションの順を変えたり絶対パスで呼んだりすれば当たらない。間違いを防ぐ柵であって、完全な防御ではない。

    プリセット

    plugins.settings["permission-presets"].presets で選ぶ(既定 ["guard"])。/presets で一覧。

    プリセット中身
    guarddeny:sudo *、rm -rf /・/*、mkfs*、dd *of=/dev/*、パイプ先の sh・bash・zsh、chmod -R 777 /*
    softDeny:rm -rf ~*・$HOME*、git push --force*・-f*
    ask(auto でも確認):ssh、scp、sftp、リモートへの rsync
    read-only-shell読み取りだけのコマンドを許可:ls、cat、head、tail、wc、rg、grep、tree、file、which、git status/diff/log/show/branch/rev-parse。ファイルを書き出すオプションやコマンドを実行させるオプション(rg --pre、git diff --output、tree -o など)を含むものは確認に回す
    testsテストと型チェックを許可:bun/npm/pnpm/yarn test、cargo test、go test、pytest、tsc --noEmit、bun run typecheck

    できないこと

    • 許可した bash コマンドの中身(スクリプトが何をするか)までは見ない。
    • 判定から実行までの間にリンクを差し替えるような競合は防げない。
    • 信頼できないコードを扱うときは、コンテナなど OS の側で隔離する。
    • 中断(esc)した後は、承認済みでもまだ始まっていないツールは実行しない。

    Jev による判定(配布プラグイン jev-guard)

    判断専用モデル Jev に、呼び出しが安全かを確率で答えさせ、上の permission フックで判定を変えるプラグイン。0.9.5 までは同梱していたが、既定で無効でキーも要るので、配布プラグインに分けた。入れた後は TUI で /jev on と打てばそのセッションで有効になり(/jev off で無効。/resume 後も保たれる)、いつも使うなら設定に書く。0.9.5 までの設定はそのまま使え、設定があるのにプラグインが入っていなければ起動時に入れ方を知らせる。

    sasacode plugin install sasacode-plugin-jev-guard
    { "plugins": { "settings": { "jev-guard": { "enabled": true } } } }
    元の判定Jev が「安全」Jev が「要確認」Jev が「危険」
    許可(allow ルール・auto モード)許可確認拒否
    確認(agent モード)許可確認確認
    softDeny確認拒否拒否
    確認(それ以外)変えない(確認ダイアログに Jev の判定を添える)

    送るのは、ハーネスが集めた事実(コマンド、変更されうるパスとその git の状態、作業ディレクトリの内か外か)と、ユーザー自身の直近の依頼だけ。ツールの出力やファイルの中身は送らない。キーやトークンらしい文字列は伏せる。設定の全項目は 下の表。

    05プロジェクトの信頼

    クローンしたリポジトリの .sasacode/ は、そのままでは「制限を強める」ことしかできない。コードを実行するか、データの送り先を変えうるものは、最初に一覧を出して信頼するかを尋ねる(ヘッドレスは --trust-project)。

    プロジェクトの設定信頼なしで使う
    model(全体の設定にあるプロバイダー)、models、thinking、instructions使う
    deny / ask ルールの追加、ツールの無効化、より厳しい権限モード、小さい maxTurns・maxRetries、toolSearch、tui使う
    .sasacode/plugins のプラグイン信頼が必要
    providers(エンドポイント)、modelOverrides、mcpServers信頼が必要
    plugins(無効化と設定)、allow ルール、緩い権限モード、大きい上限、プロジェクトにしかないプロバイダーを指す model信頼が必要
    trustedProjects全体の設定でしか読まない

    答えは ~/.sasacode/trust.json に保存し、上の設定かプラグインのコードが変わったら、また尋ねる。全体の設定の trustedProjects に入れたプロジェクトは尋ねずに信頼する。

    06設定リファレンス

    ~/.sasacode/config.json(全体)と <project>/.sasacode/config.json(プロジェクト)を合わせ、プロジェクトが優先する。権限ルールと disabled の配列は両方を合わせるので、全体の deny や無効化をプロジェクトから消すことはできない。型の合わない値と未知のキーは、警告を出して無視する。

    キー型・既定内容
    model文字列起動時のモデル(provider/model)
    models文字列の配列/model の一覧の先頭に出すモデル
    thinkinghigh推論の深さ
    langロケールで決まる画面の言語(ja / en)。TUI・CLI・同梱プラグインの表示がそろう。環境変数 SASACODE_LANG が優先。モデルに渡す文は訳さない
    providers.<name>オブジェクトapi(openai-chat / openai-responses / anthropic、省略で判別)、baseUrl、apiKeyEnv、headers、defaultModel
    modelOverrides.<provider/model>オブジェクトcontextWindow、maxOutput、price(100 万トークンあたりの USD:input・output・cacheRead・cacheWrite)、reasoning、images
    permissionsオブジェクトmode、allow、ask、deny、softDeny
    instructions文字列システムプロンプトに足す文
    maxTurns2001回の依頼でモデルに送るリクエストの上限(0 で無制限)
    maxRetries8API エラー(429・5xx)の再試行の回数(最大 20)
    plugins.disabled配列読み込まないプラグイン(同梱も含む)
    plugins.settings.<name>オブジェクトプラグインに渡す設定(同梱プラグインの設定)
    tools.disabled配列使わないツール(組み込みも含む)
    mcpServers.<name>オブジェクトstdio:command、args、env、cwd / HTTP:url、headers。共通:disabled、alwaysLoad。${VAR} は環境変数から展開
    toolSearch{"mode":"auto","percent":10,"count":30}MCP とプラグインのツール定義が、コンテキストの percent% 以上か count 個以上で遅延ロードにする。mode は auto / always / never
    tui.altScreen / tui.belltrue / true全画面 / 長い実行の後のベル
    trustedProjects配列(全体の設定のみ)尋ねずに信頼するプロジェクト
    updateChecktrue起動時に新しい版を1日1回確かめ、あれば知らせる

    環境変数

    変数内容
    SASACODE_HOME~/.sasacode の代わりに使う場所
    SASACODE_VERSION / SASACODE_INSTALL_DIRインストーラー:版の固定 / 置き場所
    SASACODE_AMBIGUOUS_WIDTH幅の曖昧な文字を 1 か 2 マスとして数える
    SASACODE_PLUGIN_INDEX / SASACODE_NPM_REGISTRYplugin search のおすすめ一覧の URL / npm のレジストリ
    各プロバイダーのキーANTHROPIC_API_KEY、OPENAI_API_KEY、OPENROUTER_API_KEY、CMD_API_KEY など

    ファイルの置き場所

    ~/.sasacode/ ├── .env # API キー(空欄は未設定) ├── config.json # 全体の設定 ├── AGENTS.md # すべてのプロジェクトで読む指示(任意) ├── trust.json # 信頼したプロジェクトの記録 ├── endpoints.json # 自前サーバーの判別結果のキャッシュ ├── codex-auth.json # ChatGPT プランの認証情報(本人だけが読める) ├── history.jsonl # 入力履歴 ├── sessions/<dir>-<hash>/<日時>_<id>.jsonl # セッション ├── plugins/ # プラグイン(.ts 1ファイル、フォルダ、npm で入れたもの) ├── skills/<name>/SKILL.md # Skills ├── background-sessions/ # バックグラウンドジョブの出力と状態 └── publish/ # plugin publish が組み立てたパッケージ <project>/.sasacode/ ├── config.json # プロジェクトの設定 ├── plugins/ # プロジェクトのプラグイン(信頼が必要) └── skills/

    07同梱プラグインと設定

    設定は plugins.settings.<名前> に書く。どれも plugins.disabled で外せ、~/.sasacode/plugins やプロジェクトに同じ名前のプラグインがあれば、同梱版の代わりにそちらを読み込む。

    { "plugins": { "settings": { "compaction": { "threshold": 0.7 }, "loop-guard": { "noProgressTurns": 0 } } } }

    小型モデル向けの修復と抑止

    プラグイン設定既定内容
    tool-repairjsontrue壊れた JSON(末尾カンマ、閉じ括弧、クォートのないキー、True/None、コードフェンス、二重エンコード)を直す
    schematrueキー名(file → path)と型("20" → 20)を直す
    namestrueツール名の typo を直す(候補が1つのときだけ)
    loop-guardnoteAt3同じ呼び出し(か3手までの周期)が同じ結果で続いたら、この回で注意を添える
    blockAt5この回から、その周期の呼び出しを止める(ファイルの変更か次の依頼で解除)
    noProgressTurns5ツールが1件も実行されないターンがこの回数続いたら実行を止める(0 で無効)
    repetition-guardminRepeats4同じ文がこの回数以上続いたら止める
    minSpan / minUnit200 / 10繰り返し全体の最小の長さ / 1単位の最小の長さ(文字)
    shortMinSpan400「なるほど。」のような短い単位を止めるのに要る長さ
    maxStopsPerRun21回の実行で止める回数の上限(ツール引数用に toolcall… の同名の設定もある)

    文脈とエージェント

    プラグイン設定既定内容
    compactionthreshold0.8コンテキストがこの割合に達したら古い履歴を要約する(上限に来たときも)。/compact [指示] で手動
    agents-md—~/.sasacode/AGENTS.md と、リポジトリのルートから作業ディレクトリまでの AGENTS.md を読む(CLAUDE.md は読まない)
    subagent—task ツール。別の履歴で作業させ、報告だけを受け取る。background: true で待たずに続行し(メインを Esc で止めると一緒に止まる)、task_status・task_send・task_stop で見る・指示する・止める。ユーザーは /task で同じことができる
    todo—todo_write ツール。進捗をフッターに出す
    checkpointsmaxFileKB1024write / edit が変える直前の内容をセッションに控え、/undo で1回の呼び出しの分ずつ戻す(/undo list、/undo <path>)。bash の変更と、大きいファイル・テキストでないファイルは対象外
    goal—/goal <目的>、done / pause / resume / clear。「これをゴールにして」と頼めばモデルが set_goal で設定する

    バックグラウンド実行(background-sessions)

    モデルが bg_start で長いコマンドを裏で動かし、終わったら終了コードと出力の末尾が会話に届く(待機中なら続きを自動で始める)。bash と同じ権限ルールで判定する。sasacode を終了してもジョブは続き、次の起動で結果を知らせる。/bg で一覧、/bg <id> で詳細、/bg kill <id> で停止。POSIX のみ。

    設定既定内容
    dir~/.sasacode/background-sessions出力と状態の置き場所
    pollMs1500終了を確かめる間隔
    tailLines30終了通知に付ける出力の行数
    keep40残す終了済みジョブの数
    autoNotifytruefalse なら通知だけで、エージェントを起こさない
    foreignGraceMs10000別のセッションで始めたジョブの通知を、元のセッションに譲る時間

    接続の復旧待ち(auto-reconnect)

    実行がエラーで終わり、使っているモデルの接続先に届かないとき、復旧を待ってから「中断した作業を再開して」と送る。オンラインで別の理由(キーの誤りなど)のエラーなら何もしない。

    設定既定内容
    checkUrl使用中モデルの接続先疎通を確かめる URL(応答が返ればオンライン)
    checkIntervalMs / checkTimeoutMs5000 / 3000確かめる間隔 / 1回のタイムアウト
    maxWaitMs600000(10分)待つ最大時間
    retryMessage(再開の指示)復旧後に送る文
    quietfalse通知を出さない

    使用量(usage)

    コマンド内容
    /usageこの起動の使用量、今日・7日・30日・全期間の合計、ChatGPT プランの残り
    /usage graph日ごとの使用量を GitHub の Contributions Graph のように(端末の幅に入るだけの週)
    /usage history [日数]日別の棒グラフと数値(既定 14 日)
    /usage modelsモデル別の合計、割合、最終使用日
    /usage planChatGPT プランの 5 時間・週の枠と、リセットまでの時間

    記録は ~/.sasacode/sessions のセッションログから読む。/compact の要約とサブエージェントの分はログに残らないので含まない。プランの残りは ChatGPT にログインしているときだけ出る。

    Web

    プラグイン設定内容
    web-fetch—web_fetch ツール。URL を取ってテキストにする
    browsrcommand、mode、configbrowsr-4-agent で検索(search)と本文の閲覧(open)。browsr-agent が PATH にあれば自動で起動。別の場所なら command で指定

    Jev(配布プラグイン jev-guard)の設定

    設定既定内容
    enabledfalse有効にする
    backendキーのある方commandcode(CMD_API_KEY)、typesafe(TYPESAFE_API_KEY)、openrouter、vercel、chat(sasacode の任意のモデル)。OpenRouter と Vercel は名前を指定したときだけ使う
    model / endpoint / apiKeyEnv接続先ごとモデル名 / URL / キーの変数を変える(プロキシなど)
    timeoutMs5000(chat は 60000)これを超えたら Jev なしの判定で続ける
    skip["todo_write","task"]判定しないツール(読み取りと作業ディレクトリ内の編集は元から判定しない)
    thresholdsallow 0.8、headlessAllow 0.9、deny 0.85、confidence 0.6、risk 0.6、flag 0.7、clear 0.3判定の閾値

    08プラグイン

    探す・入れる・公開する

    公開する人
    • sasacode plugin publish my-tool.ts --license MIT
    • package.json・README を組み立てて npm publish
    • キーワード sasacode-plugin が付く
    置き場所
    • npm:プラグインの本体
    • GitHub:git で配るもの
    • sasanokusa.com/sasacode/plugins.json:おすすめの一覧だけ(数 KB)
    使う人
    • sasacode plugin search 語:一覧(★)と npm から
    • sasacode plugin install 名前:中身を見て確認してから
    • sasacode plugin update:最新へ
    サーバーを通るのは一覧の JSON だけ。本体は npm や GitHub から直接取る。
    sasacode plugin search                      # 全部
    sasacode plugin search 天気                  # 語で絞る
    sasacode plugin install sasacode-plugin-foo  # npm
    sasacode plugin install https://github.com/you/plugin   # git
    sasacode plugin install ./my-plugin          # 手元のパッケージ(公開前の確認)
    sasacode plugin install foo --project        # このプロジェクトの .sasacode/plugins へ
    sasacode plugin update [名前]
    sasacode plugin list
    sasacode plugin remove <名前>

    入れる前に見せるもの

    • npm:版、説明、公開者と公開日、ファイル数と大きさ、依存パッケージ、install スクリプトの有無(実行はしない)、sasacode フィールドの有無、ソースのリポジトリ。
    • git:URL。入れた後にコミットを出す。update では新しいコミットの一覧と変更の規模を見せてから更新する。
    • 端末がない(スクリプトから実行する)ときは --yes が要る。
    注意プラグインは sasacode と同じ権限で動く。コードを読むか、信頼できる作者のものだけを入れる。

    公開する

    sasacode plugin publish my-tool.ts --license MIT --dry-run   # 中身の確認
    sasacode plugin publish my-tool.ts --license MIT             # 公開(npm へのログインが必要)
    オプション既定内容
    --namesasacode-plugin-<ファイル名>パッケージ名(@you/my-tool も可)
    --versionnpm の最新版の次のパッチ(初回 0.1.0)版
    --api使っている機能から対応するプラグイン API(permission フックなら ^1.7.0 など)
    --descriptionファイル先頭のコメント説明文
    --licenseなし付けないと、ほかの人は再利用できない
    --otpその場で聞かれるnpm の2段階認証のコード

    ほかのファイルを import しているプラグインは、package.json に sasacode フィールドを書いたフォルダごと sasacode plugin publish <フォルダ> で出す。おすすめ一覧に載せたいときは、site/plugins.json に1件足す pull request を送る。

    { "name": "my-tool", "source": "sasacode-plugin-my-tool", "description": "何をするか", "author": "you" }

    書く

    ~/.sasacode/plugins/hello.ts に置くだけで読み込む(ビルド不要)。@sasacode/plugin-api は入れなくても import できる(型補完が欲しければ npm i -D @sasacode/plugin-api)。

    import { text, type Plugin } from "@sasacode/plugin-api";
    
    export default ((api) => {
      api.registerTool({
        name: "hello",
        description: "Greet someone by name.",
        parameters: { type: "object", properties: { name: { type: "string" } }, required: ["name"] },
        kind: "read",
        execute: async ({ name }) => ({ content: [text(`Hello, ${name}!`)] }),
      });
      api.registerCommand({ name: "hello", description: "挨拶する", run: ({ args }) => api.ui.notify(`こんにちは ${args}`) });
    }) satisfies Plugin;

    組み込みの Skill を使えば、モデルに書かせることもできる:/skill:tool-authoring 天気を返すツールを作って。

    フックの順序

    user_prompt入力の変換、または消費(モデルに渡さない)
    system_prompt → before_requestシステムプロンプトへの追記 / 送るメッセージとサンプリングの変更
    stream_delta生成中の差分ごと(同期のみ)。途中で止められる
    assistant_message確定した応答の書き換え・再生成・継続の指示
    tool_call_raw → 検証 → tool_call壊れた呼び出しの修復 / 引数の変更と判定
    permissionルールとモードの判定の後で判定を変える(判定の流れ)
    実行 → tool_result結果の変更・追記(実行されなかった呼び出しでも呼ばれる)
    turn_end → agent_end継続の指示(inject)や停止(stop)
    ほかに session_start / session_end、context_limit。サブエージェントは system_prompt〜tool_result を共有し、セッション系のフックは呼ばれない。

    API の版

    版追加されたもの
    1.0ツール、コマンド、プロバイダー、基本のフック、ui / session / agent
    1.1ready(promise)
    1.2stream_delta、assistant_message、tool_call_raw、サンプリングの変更
    1.3コマンドの引数の補完
    1.4実行されなかった呼び出しの tool_result、turn_end の stop。ここで締め切り、以後 1.x は追加だけ
    1.5Provider.listModels、Request.fetch
    1.6ツールの permissionsAs
    1.7permission フック、softDeny

    マニフェスト、API の全項目、互換性の約束は docs/plugins.md。

    MCP と Skills

    {
      "mcpServers": {
        "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" } },
        "remote": { "url": "https://example.com/mcp", "headers": { "Authorization": "Bearer ${REMOTE_TOKEN}" } }
      }
    }
    • stdio と Streamable HTTP に対応。ツール名は mcp__<server>__<tool>、prompts はスラッシュコマンドになる。接続はバックグラウンドで行うので、起動を待たせない。
    • Skills は ~/.sasacode/skills/<name>/SKILL.md、.sasacode/skills/、プラグインの skills から読む。システムプロンプトには名前と説明だけを載せ、本文はモデルが必要なときに読む。
    • ツールが多いとき(定義がコンテキストの 10% 以上か 30 個以上)は、tool_search で必要なものだけ読み込ませる。

    09セッション

    会話は ~/.sasacode/sessions/<作業ディレクトリ>-<ハッシュ>/<日時>_<id>.jsonl に、1件ずつ追記して保存する。途中で強制終了しても、最後に保存したところから再開できる。

    やりたいこと方法
    このディレクトリの直近の会話を続けるsasacode -c
    ID を指定して続けるsasacode -r <id>、TUI なら /resume
    1回ずつ続ける(tmux なしで会話する)sasacode -r <id> -p "続き"
    過去の時点から分岐する/fork
    保存しない--no-session
    コンテキストを空ける/compact(自動でも 80% で要約する)
    • 結果が保存される前に止まったツール呼び出しは、「実行されたか分からない」としてモデルに伝え、状態を確かめてからやり直させる。
    • 書きかけの最終行は <ファイル>.torn に退避する。
    • セッション ID は、フッター、/session、終了時の要約、ヘッドレスの出力に出る。

    10ヘッドレスと自動化

    sasacode -p "テストを直して"                         # 答えは stdout、進捗は stderr
    sasacode -p "…" --output jsonl                      # 全イベントを1行ずつ JSON で
    git diff | sasacode -p "このdiffをレビューして"          # パイプした入力は -p の後ろに付く
    sasacode -p "…" --permission auto --trust-project   # CI など確認できない環境で
    • 終了コード:最後まで終われば 0、それ以外(中断、エラー、上限、プラグインによる停止)は 1。止まった理由は stderr に [stopped: …] で出る。
    • 確認が必要な呼び出しは実行せず、理由をモデルに返す。何を許すかはルールで決めておく(--permission auto でも deny と ask のルールは効く)。
    • MCP サーバーなどの起動処理は、最初のリクエストの前に待つ。
    • テキストモードでは最後に session <id> · continue: sasacode -r <id> -p "…" が stderr に出る。

    JSONL のイベント

    最初の行は {"type":"session","id":…,"path":…}。そのあとはイベントが1行ずつ出る。

    type内容
    agent_start / agent_end実行の始まりと終わり(cause:done、aborted、error、refusal、context_limit、max_turns、stopped)
    turn_start / turn_endモデルへの1リクエストごと
    message_start / message_update / message_end応答の開始 / 差分(テキスト・推論・ツール引数) / 確定したメッセージ(使用量を含む)
    tool_start / tool_update / tool_endツールの開始 / 途中の出力(bash の stdout など) / 結果
    tool_repaired壊れた呼び出しを直した(元の形と直した内容)
    message_discardedプラグインが再生成させた応答(捨ててよい)
    messages_replaced履歴が差し替えられた(要約など)
    context_limit / error / plugin_errorコンテキストの上限 / エラー / プラグインのエラー

    11困ったとき

    推論(thinking)を off にしても推論が返ってくる

    サーバーによっては推論を止められない。Command Code の DeepSeek は none を受け付けず、推論が必ず返るので、off は一番軽い low として送る。自前の vLLM などは off で止まる(0.9.3 以降)。推論の深さを参照。

    文章がコピーできない・端末で選択できない

    全画面では sasacode がマウスを受け取る。ドラッグして離すと sasacode がコピーする(0.9.1 以降)。端末の標準の選択を使いたいときは option / alt を押しながらドラッグするか、"tui": { "altScreen": false } にする。直前の応答全体は /copy。

    表示が崩れる・罫線に文字が重なる

    ①や※のような幅の曖昧な文字の数え方が、端末とずれている可能性がある。SASACODE_AMBIGUOUS_WIDTH=2(CJK 向けの端末設定のとき)か 1 を付けて起動してみる。改行を含むコマンドで崩れる問題は 0.9.2 で直した。

    /compact が何も言わない

    要約はモデルへの1回の長い呼び出しで、画面には流れない。フッターに「履歴を要約中」と出ている間は待つ(0.9.2 以降)。ローカルのサーバーで履歴が長いと数分かかる。サーバーの同時処理数が埋まっていると、順番待ちになる。

    自前サーバーのモデルでコンテキストの割合がおかしい

    コンテキスト長が取れないモデルは 128k として扱う。modelOverrides で contextWindow を指定する(自前のサーバー)。

    plugin install がスクリプトから動かない

    入れる前の確認に答える端末がないため。--yes を付ける。

    plugin publish が 404 や EOTP で失敗する

    404:npm のログインが切れている。npm whoami で確かめ、npm login し直す(npm は権限のない相手に 404 を返す)。
    EOTP:2段階認証のコードが要る。その場で聞かれるので入力するか、--otp <コード> を付ける(0.9.4 以降)。

    プロジェクトのプラグインや設定が効かない

    プロジェクトを信頼していない可能性がある。起動時の確認で信頼するか、ヘッドレスなら --trust-project、いつも使うなら全体の設定の trustedProjects に入れる(プロジェクトの信頼)。

    同梱プラグインを自分で改造したい

    同じ名前のプラグインを ~/.sasacode/plugins に置くと、同梱版の代わりにそちらを読み込む。同梱版のソースは packages/bundled/src。

    ネットワークが切れて止まった

    同梱の auto-reconnect が、接続先の復旧を待って自動で再開する(最大 10 分)。待ちきれないときや手動で再開するときは /reconnect。