keelson.yaml
keelson.yaml はプロジェクトルートに置くデプロイ設定ファイルです。ランタイム、起動コマンド、環境変数、データベース、定期実行ジョブ、静的アセットなどを定義します。
デプロイ時に Keelson はこのファイルを読み、ビルドと実行環境を決めます。入門は keelson.yaml の設定を参照してください。
slug: my-appruntime: python-slimcommand: "python app.py"db: mode: noneトップレベルフィールド
Section titled “トップレベルフィールド”| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
slug | string | はい | — | アプリの識別子。アプリ作成時に使われる |
workspace | string | — | null | プロジェクト単位の CLI 操作で使う既定ワークスペース。ワークスペースの slug を推奨。所属が 1 つだけなら CLI が自動選択するため書かなくてよい。明示した --workspace はこの値より優先し、apps list の一覧は絞り込まない |
description | string | — | null | アプリの説明(300 文字以内) |
icon | string | — | null | コンソールでアプリのアイコンとして表示する画像。keelson.yaml のあるフォルダからの相対パス。icon を参照 |
type | string | 条件付き | null | アプリ種別。web のみ。起動コマンドのない静的サイト・SPA では必須 |
runtime | string | はい | — | 実行環境。対応ランタイムを参照 |
command | string | list | 条件付き | — | 起動コマンド。定期実行ジョブのみ、または type: web と assets を指定した静的サイトでは省略可 |
env | map | — | {} | 秘密でない環境変数 |
db | object | はい | — | データベースとローカル SQLite の方針 |
crons | list | 条件付き | [] | 定期実行ジョブ。command がなく、静的サイト(type: web と assets)でもない場合は必須 |
tasks | list | — | [] | アプリが SDK で投入するバックグラウンドタスク。tasks を参照 |
mcp | object | — | null | AI クライアントから MCP で使うツールの宣言。mcp を参照 |
assets | object | — | null | 静的アセット配信 |
health | object | — | null | デプロイ時ヘルスチェックのパス |
secrets | object | — | {} | シークレットの宣言と必須条件 |
auth | object | — | null | 対話ログインを通さない外部向けエンドポイント |
verify | string | list | — | [] | デプロイ後に追加で検証するパス |
region | string | — | null | 新規アプリの配置リージョン |
storage | object | — | {} | 廃止された disk_id だけを受理する互換ブロック |
廃止されたトップレベルキー databases と workers は、値が null や空リストでも拒否されます。継続して保存する業務データは db.mode: libsql、リクエストの後に実行する処理は tasks、決まった時刻に実行する処理は crons で表現してください。
旧名のトップレベル tenant も workspace の互換用別名として受け付けます。撤去時期は
未定です。両方を書く場合、前後の空白や大文字小文字も含めて、値が完全に一致している必要があります。
上の表にないトップレベルキー(build、port、scaling など)や、各オブジェクトの中の未知のキーは拒否されます。独自のキーを足せる拡張可能な形式ではありません。crons / secrets / storage に null を書くと省略と同じにはならず拒否されます。省略したいときはキーごと書かないでください。
文字列の書き方
Section titled “文字列の書き方”迷ったら、文字列の値は引用符で囲んでください。 CLI と API で同じ文字列として読み取れるようにするためです。
次のような文字列は、引用符で囲むか、ブロックスカラー(| / >)で書く必要があります。引用符なしで書くと、string_value_not_portable で拒否されます。
- 数字で始まる値(
slug: "123-app") - 日本語などの非 ASCII 文字で始まる値(
description: "営業向けアプリ") -で始まる値。コマンドの引数も対象です(command: [python, app.py, "--port", "8080"])- YAML が真偽値や null と解釈する語(
yes/no/on/off/true/false/nullと、env のキーの制約に列挙した大文字小文字の表記) :で始まる値(":memory:")など、下記の例外に当てはまらない記号で始まる値
引用符を省略できるのは、次の場合です。ただし、上に挙げた真偽値・null と解釈される語は除きます。
| 値の種類 | 引用符を省略できる書き方 | 例 |
|---|---|---|
slug、runtime、シークレット名などの識別子 | 半角英字か _ で始まる | my-app、python-slim、OPENAI_API_KEY |
| コマンド、説明文、パスなどの文字列 | 半角英字か _、または /、./、../ で始まる | python app.py、/health、./app |
: を含むだけで引用符が必須になるわけではありません。たとえば description: https://example.com は引用符なしで書けます。ただし、: (コロンと空白)を含む文字列など、YAML 自体の構文上、引用符が必要な場合もあります。引用符を付けても、各フィールドのパス形式や文字数などの制約は変わりません。
env の値は例外で、先頭の文字にかかわらず、すべて引用符かブロックスカラーで書く必要があります(env を参照)。
アプリの識別子です。アプリ作成時の公開 URL(https://<ワークスペース slug>--<slug>.keelson.run)の一部になります。
slug: my-appルール:
- 小文字英数字とハイフン(
a-z、0-9、-)のみ - 1〜63 文字
- 先頭と末尾は英数字
- ハイフンの連続(
--)は不可 - 予約語:
adminapiassetsauthconsolehealthstaticwww
public_slug は廃止された互換フィールドで、無視されます。
description
Section titled “description”アプリが誰向けで何をするかを示す 1〜2 文です。
description: "営業チーム向けの日報・週報作成アプリ。週次サマリーを自動集計します"前後の空白を除いて 300 文字(Unicode コードポイント)以内。超えるとデプロイが失敗します。コンソールのアプリ説明欄に表示され、説明がまだ空のときだけ適用されます。コンソールで編集した説明がデプロイで上書きされることはありません。
コンソールのアプリ一覧・アプリ詳細でアプリのアイコンとして表示する画像です。省略できます。指定しないアプリは名前の頭文字で表示され、テンプレートから作ったアプリはテンプレートのアイコンで表示されます。
icon: ./assets/app-icon.png- パスは
keelson.yamlのあるフォルダからの相対パスです。コマンドを実行したフォルダは関係ありません。プロジェクトの外を指すパス(絶対パス、..で外に出るパス)、\を含むパス、シンボリックリンクは使えません。 - 画像はソースと一緒にアップロードされるため、アーカイブから除外される場所には置けません(アーカイブに含まれるものを参照)。
commandのない静的サイトではassets.dirの中に置いてください。 - 使える画像は PNG・JPEG・WebP で、256KB 以下、縦横とも 32〜2048 ピクセルです。形式は拡張子ではなくファイルの中身で判定します。SVG は使えません。
keelson deploy(--checkを含む)は、アプリを作成・アップロードする前に画像を確かめ、問題があればパスと原因を表示して止まります。原因はicon.path(見つからない・読めない・シンボリックリンク・アップロードされない)、icon.format、icon.size、icon.dimensions、icon.corrupt(画像のヘッダーが読めない)のいずれかです。
アイコンはデプロイが成功した時点で反映され、CLI は完了時に Icon: の行を 1 行表示します(--ndjson では icon_outcome)。
icon_outcome | 意味 |
|---|---|
applied | keelson.yaml の画像をアプリのアイコンにした |
unchanged | すでに同じ画像がアイコンになっている |
kept_console_icon | コンソールでアップロードしたアイコンを残した(keelson.yaml では置き換えない) |
kept_cleared | コンソールでアイコンが削除されているため、デプロイでは戻さない |
コンソールで設定・削除したアイコンは、常に keelson.yaml より優先されます。その後で keelson.yaml の画像を使いたい場合は、コンソールのアプリの「設定」でその画像をアップロードしてください。keelson.yaml から icon を消しても、アプリのアイコンは消えません。
アプリアイコンは順次提供中です。デプロイが icon is not available yet で拒否された場合は、keelson.yaml から icon を消して再度デプロイしてください。
アプリ種別です。起動コマンドのない静的サイト・SPA では type: web が必須です。それ以外では省略できます。
type: web指定できる値は web だけです。type: web を指定すると、assets だけで command なしのデプロイができます。
制約:
type: webとcronsは併用できません- Web アプリと定期実行ジョブを両方持つアプリでは
typeを省略します
runtime
Section titled “runtime”実行環境です。静的サイトだけのデプロイでも必須ですが、静的サイトではビルドに使われません。静的サイトは手元や CI でビルド済みの assets.dir をそのまま配信します。
対応ランタイム
Section titled “対応ランタイム”| ランタイム | 言語 | 用途 |
|---|---|---|
python-slim | Python | 軽量。API、テキスト処理など |
python-media | Python | 画像・動画処理(Pillow、opencv、ffmpeg 関連など) |
node-slim | Node.js | 軽量 |
node-media | Node.js | 画像処理(sharp など) |
go-slim | Go | 軽量 |
go-media | Go | メディア処理 |
迷ったら -slim から始め、メディア処理系ライブラリが必要になったら -media に切り替えます。
依存関係のインストール
Section titled “依存関係のインストール”コンテナ型とハイブリッド型では、依存パッケージはビルド時に Keelson が自動でインストールします。静的サイト(type: web と assets を指定し、command なし)ではこの処理は行われません。既定でアップロードされるのは assets.dir 配下のファイルと keelson.yaml だけです(アーカイブに含まれるもの)。command には起動コマンドだけを書いてください。command に pip install / npm install / go build を含めると、CLI の事前チェックが command_installs_dependencies でデプロイを止めます。
| ランタイム | 検出するファイル | ビルド時に実行される処理 |
|---|---|---|
python-* | requirements.txt | python -m pip install --user -r requirements.txt |
python-* | pyproject.toml([project] または [build-system] あり)。requirements.txt がない場合のみ | python -m pip install --user . |
node-* | package-lock.json / package.json | npm ci(ロックファイルあり)または npm install、続けて npm run build --if-present |
go-* | go.mod / go.sum | go mod download、go build -o /workspace/app .(command: "./app" で起動) |
ビルドの制約:
requirements.txtとpyproject.tomlが両方あるときはrequirements.txtだけを使います。pyproject.toml側だけに書いた依存や自作パッケージのインストールは行われないので、必要なものはrequirements.txtに含めてください- インストール可能な Python の
pyproject.tomlには、対応するロックファイル(requirements.txt/poetry.lock/uv.lock/Pipfile.lock)のいずれかが必要です - Node.js のビルドは npm のみを使います。外部パッケージへの依存を宣言するアプリには
package-lock.jsonが必要です。開発用・任意・peer 依存も対象です。外部依存の宣言がなければ、ロックファイルは省略できます。ロックファイルがなく、package.jsonがある場合はnpm installが実行されます。pnpm-lock.yaml/yarn.lockだけの場合は事前チェックがlockfile_unsupportedでデプロイを止めます。package-lock.jsonと併存している場合はそのまま残してかまいません - サードパーティ依存を宣言する Go モジュールには
go.sumが必要です。標準ライブラリだけを使うモジュールには必要ありません - 公開レジストリからのみ取得できます。private registry、
git+ssh依存、認証が必要なインストールは失敗します - Go は
CGO_ENABLED=0でビルドされます - ビルド対象は
linux/amd64のみ - ビルド時にシークレットは渡りません
- ビルドの上限時間は 600 秒
command
Section titled “command”アプリ起動時に実行するコマンドです。文字列(シェル経由)またはリスト(直接実行)で指定します。
# 文字列形式(/bin/sh -c で実行)command: "python app.py"
# リスト形式(exec で直接実行)command: - python - app.pyルール:
- 起動コマンド(
command)、定期実行ジョブ(crons)、静的サイト(type: webとassets)のいずれかが必要です - 定期実行ジョブだけのアプリに
commandは不要です type: webでassetsがある静的サイトにcommandは不要です- 空文字列・空リストは「起動コマンドなし」として扱われます。通常の Web アプリでは指定が必要です。
crons[].commandは空にできません - 依存関係のインストールは含めません(依存関係のインストールを参照)
秘密でない環境変数をキーと値で定義します。値はすべて文字列です。
PORT は Keelson が実行時に設定します。env に書いても無視されます。
値は必ず引用符で囲むか、ブロックスカラー(| / >)で書いてください。 引用符のない値は env_value_not_string で拒否され、デプロイは開始されません。数値・真偽値も同様です。
env: NODE_ENV: "production" DEBUG: "false" LOG_LEVEL: "info"引用符が必須なのは、keelson.yaml を CLI(YAML 1.2)と API(YAML 1.1)の 2 つの実装が解析しており、引用符のないスカラーの型解決が食い違うためです。たとえば K: 0o123 は経路によって "83" にも "0o123" にもなります。引用符で囲めば両方で同じ文字列になります。
引用符を付けないキーは、英字か _ で始まり、英数字と _ だけで構成される必要があります。NODE_ENV や DB_POOL のような通常の環境変数名はそのまま書けます。
次の語は YAML 1.1 で真偽値・null と解釈されるため、引用符なしでは使えません:
yes Yes YES no No NO true True TRUE false False FALSE on On ON off Off OFF null Null NULL
ハイフンを含む名前や予約語は、キーを引用符で囲みます。
env: NODE_ENV: "production" "MY-VAR": "x" "yes": "x"KEELSON_ で始まるキー(大文字小文字を区別しない)はプラットフォーム予約で、env には設定できません。env の重複宣言、env 内のキー重複、YAML の merge key(<<)も拒否されます。
秘密の値は env ではなく secrets で宣言し、値はコンソールまたは CLI で設定します。env と同じ名前のシークレットが設定されている場合はシークレットの値が優先され、env の変更は反映されません。
データベースの扱いを選びます。db と db.mode は必須です。
db: mode: libsql| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
mode | string | はい | — | libsql または none。旧名 turso は libsql に正規化 |
migrate | string | — | null | デプロイ時に実行するマイグレーションコマンド。libsql のときのみ有効 |
auto_adopt | boolean | — | false | 旧設定との互換のため受理されるが、現在は何もしない。DB を引き継ぐ機能ではない |
local_sqlite | object | — | null | 再生成可能な一時 SQLite ファイルの明示宣言 |
mode | 意味 |
|---|---|
libsql | Keelson がアプリ専用の Managed SQLite を用意し、KEELSON_DB_URL / KEELSON_DB_AUTH_TOKEN(別名 TURSO_DATABASE_URL / TURSO_AUTH_TOKEN)を注入する |
none | Keelson は DB を管理しない。DB 不要のアプリ、または外部 DB を使うアプリ |
mode: libsql は契約も接続設定も不要で、scale-to-zero に対応します。継続して保存する業務データにはこれを推奨します。
PostgreSQL、MySQL、自前の libSQL を使う場合は mode: none にし、接続情報をシークレットで渡します。外部 DB の接続情報を Keelson が注入することはありません。
ファイル SQLite を永続化するモードはありません(/data は存在せず、アプリからも作成できません)。ファイル SQLite を使うコード(sqlite3、better-sqlite3 など)はデプロイ時に検出され、local_sqlite の宣言がなければ拒否されます。
マイグレーション
Section titled “マイグレーション”db.migrate は、新しいイメージでトラフィックを切り替える前に 1 回だけ実行されるコマンドです。
db: mode: libsql migrate: "python migrate.py"mode: libsqlのときのみ有効。文字列で指定します- コンテナ型・ハイブリッド型でのみ実行されます。静的サイトにはコンテナがないため、宣言しても実行されません
- 候補リビジョンがヘルスチェックを通った後、トラフィック切り替えの前に、デプロイ対象のイメージ上で実行されます。アプリの起動コードは移行前のスキーマで動く必要があります
- 終了コードが 0 以外ならデプロイは
deploy.runtime.migration_failedで失敗し、旧リビジョンが維持されます - 毎回のデプロイで実行されるため、冪等に書きます(
CREATE TABLE IF NOT EXISTS、ON CONFLICT DO NOTHING)
一時的なローカル SQLite
Section titled “一時的なローカル SQLite”再生成できるキャッシュ用途のファイルだけを db.local_sqlite で宣言します。宣言してもファイルは永続化されません。
db: mode: none local_sqlite: policy: ephemeral paths: - /tmp/cache.db reason: "外部 API から再構築できる派生キャッシュ"| フィールド | 型 | 必須 | 制約 |
|---|---|---|---|
policy | string | はい | ephemeral のみ |
paths | list | はい | 空でないこと。各パスは /tmp/ 配下か :memory: |
reason | string | はい | 消えても問題ない理由 |
廃止された databases ブロックは常に拒否されます。
定期実行ジョブを定義します。各ジョブは Web サービスとは別のインスタンスで実行されます。
crons: - name: cleanup description: "期限切れのセッションを削除する" schedule: "0 3 * * *" command: "python cleanup.py" timeout: 60 enabled: true| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
name | string | はい | — | ジョブ名。小文字英数字とハイフン、1〜63 文字、重複不可 |
schedule | string | はい | — | 5 フィールドの cron 式 |
command | string | list | はい | — | 実行コマンド |
timeout | integer | — | 300 | タイムアウト秒。1〜600 |
enabled | boolean | — | true | false にするとスケジュールされない |
description | string | — | — | ジョブの 1 行説明。コンソールの定期実行タブに表示する。下の crons[].description を参照 |
ルール:
- 1 アプリ最大 10 本。プランによりさらに少ない上限があります
crons[].descriptionは表示専用です。前後の空白を除き、空なら未指定と同じです。除いた後で 100 文字を超えるとcron_description_too_longで拒否されます(切り詰めはしません)。書き換えても実行内容は変わりませんtype: webと併用できません- 別インスタンスで実行されるため、ローカルファイル(
/tmpを含む)は Web と共有されません。共有する状態はdb.mode: libsqlに置きます - 前回の実行が継続中なら、その回はスキップされます
- スケジュールはワークスペースのタイムゾーンで評価されます
timeoutの絶対上限は 600 秒。省略時は 300 秒ですが、プランの上限がそれより低ければプラン上限に切り詰められます
本数・最小間隔・timeout 上限のプラン別の値はプランと制限を参照してください。
cron 式の例
Section titled “cron 式の例”| 式 | 意味 |
|---|---|
0 * * * * | 毎時 0 分 |
*/15 * * * * | 15 分ごと |
0 3 * * * | 毎日 3:00 |
0 9 * * 1-5 | 平日 9:00 |
0 0 1 * * | 毎月 1 日 0:00 |
* * * * *(毎分)は全プランの最小間隔より短いため拒否されます。実行の挙動と設計は定期実行ジョブを参照してください。
バックグラウンドタスクを宣言します。アプリのコードが SDK で名前を指定して投入すると、Keelson は宣言したコマンドを Web サービスとは別のインスタンスで 1 回起動し、失敗した試行は自動で再試行します。crons と違い、時刻では起動しません。投入の仕方・コマンドの書き方・2 回走っても壊れない書き方はバックグラウンドタスクを参照してください。
command: "python app.py"tasks: - name: generate-pdf description: "注文の請求書 PDF を作る" command: "python generate_pdf.py" timeout: 180 max_attempts: 5| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
name | string | はい | — | タスク名。小文字英数字とハイフン、1〜63 文字(crons[].name と同じ規則)。前後の空白を除いて小文字化して扱うため、Foo は foo として受け付ける |
command | string | list | はい | — | 実行コマンド。文字列は /bin/sh -c、リストは直接実行 |
timeout | integer | — | 300 | 1 回の試行の制限時間(秒)。1〜600 |
max_attempts | integer | — | 3 | 初回を含む試行の最大回数。1〜5 |
description | string | — | — | タスクの 1 行説明。コンソールのバックグラウンドタスクタブに表示する。下の tasks[].description を参照 |
ルール:
- 1 アプリ最大 10 本(全プラン共通)
- タスク名は重複できず、
cronsのジョブと同じ名前も使えません(task_name_conflicts_with_cron)。名前は前後の空白を除いて小文字化した後で比べます tasksがあるのにcommandもcronsも無い設定は、タスクを投入するコードが無いためtasks_require_command_or_cronsで拒否されます。type: webとassetsだけでcommandの無い静的サイトもこれに当たりますtype: webと併用できますtasks[].descriptionは表示専用です。前後の空白を除き、空なら未指定と同じです。除いた後で 100 文字を超えるとtask_description_too_longで拒否されます(切り詰めはしません)。書き換えても実行内容は変わりません- 未知のキーは拒否されます。同時実行数は宣言できません(プランの値を Keelson がかけます)
timeoutの絶対上限は 600 秒。明示した値がプランの上限を超えるとplan_task_timeoutで拒否されます。省略時の 300 秒がプランの上限より大きければ、プランの上限に切り下げます- 各試行の標準入力に、
attempt_no・payload・schema_version・task_id・task_nameを持つ JSON が 1 行で渡されます。終了コード 0 が成功です。別インスタンスで実行されるため、ローカルファイルは Web と共有されません
timeout 上限のプラン別の値はプランと制限を参照してください。
アプリのツールを宣言し、Claude や ChatGPT などの AI クライアントから MCP で使えるようにします。ツールが呼ばれると、Keelson がアプリの POST /api/mcp/<name> を呼びます。ログイン・同意画面・AI クライアントとのやり取りは Keelson が受け持ちます。ハンドラの書き方・接続・上限は AI クライアントから使う(MCP)を参照してください。
command: "python app.py"mcp: enabled: true instructions: "Look up stock levels and record incoming deliveries." tools: - name: search_items description: "Search stock by item name." access: read input: type: object properties: query: type: string required: [query] - name: create_arrival description: "Record one incoming delivery." access: write permission: manage input: type: object properties: item_id: type: string quantity: type: integer minimum: 1 required: [item_id, quantity]| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
enabled | boolean | はい | — | true でツールを公開する。false は宣言を残したまま呼び出しを止める(既存の接続は失効しない) |
instructions | string | — | null | AI クライアントに渡す、ツール全体の説明。4096 文字以内 |
tools | list | 条件付き | — | ツールの一覧。enabled: true なら必須。書いた場合は enabled にかかわらず 1〜40 本 |
file | string | — | — | instructions と tools を置く別ファイル。mcp.file を参照。新しい Keelson CLI が必要 |
tools[].name | string | はい | — | ツール名。^[a-z][a-z0-9_]{0,63}$(英小文字で始まり、英小文字・数字・_ だけ。小文字化などの正規化はしない)。重複不可。ハンドラのパスは POST /api/mcp/<name> |
tools[].description | string | はい | — | AI クライアントに見せるツールの説明。1〜1024 文字。空白だけは不可 |
tools[].access | string | はい | — | read か write。write は同意画面で別に表示され、利用者は読み取りだけを承認できる |
tools[].permission | string | — | view | view か manage。manage のツールはアプリの管理権限を持つ人だけが使える |
tools[].input | object | はい | — | 引数の JSON Schema(2020-12)。最上位は type: object |
ルール:
- 宣言できるのは、サーバー側のプログラムが動くアプリ(
commandがありassetsがない)だけです。静的サイト・SPA・ハイブリッドではmcp is only supported for container appsで拒否されます mcpとtools[]の未知のキーは拒否されます。ハンドラのパスは固定なので、tools[].endpointは書けませんinputは JSON として表せる値だけで書きます。入れ子は 32 段まで、JSON にして 64 KB まで。日付や、引用符なしでは文字列以外に読まれるキー(yes・on・数値など)は引用符で囲みますinputの中で$ref・$dynamicRef・$recursiveRef・x-mcp-headerは使わないでください。$refとx-mcp-headerはデプロイで拒否され、$dynamicRefと$recursiveRefはデプロイを通っても呼び出しがすべて失敗しますmcpの中では YAML のアンカー・エイリアス・マージキー(<<)は使えませんmcp:を書いていなくても、サーバー側のプログラムが動くアプリでは/api/mcpと/api/mcp/で始まるパスは MCP 専用です(予約 URL パス)
mcp.file
Section titled “mcp.file”ツールが多いときは、instructions と tools を別の YAML ファイルに置けます。keelson.yaml には enabled と file だけを書きます。
command: "python app.py"mcp: enabled: true file: mcp.yaml# mcp.yaml(keelson.yaml と同じフォルダ)instructions: "Look up stock levels and record incoming deliveries."tools: - name: search_items description: "Search stock by item name." access: read input: type: object properties: query: type: string required: [query]- デプロイ時に Keelson CLI が別ファイルの中身を
keelson.yamlのmcpに差し込んでから検査・送信します。手元のkeelson.yamlは書き換えません - 別ファイルのトップレベルに書けるのは
instructionsとtoolsだけです(どちらも省略可)。mcp.fileとmcp.instructions/mcp.toolsは同時に書けません - パスは
keelson.yamlのあるフォルダからの相対パスで、そのフォルダの外(..やシンボリックリンクで外に出る場合を含む)は指せません。拡張子は.yamlか.yml、大きさは 4 MiB まで - 別ファイルの中の誤りは、
mcp.yaml: tools[3].input ...のように別ファイル名と位置で示されます mcp.fileを読めるのは新しい Keelson CLI だけです。古い CLI はmcp contains unsupported field(s): fileでデプロイを拒否します。keelson upgradeで CLI を最新版にしてください。CLI を通さない経路では使えません
workers(廃止)
Section titled “workers(廃止)”workers(バックグラウンドワーカー)は廃止されました。トップレベルに workers があると、値が空リストや null でも workers_not_supported で拒否されます。
リクエストを受けて走らせる処理は tasks に宣言し、SDK で投入します(バックグラウンドタスク)。未処理データを定期的に処理する場合は、crons に定期実行ジョブを定義します。プランで許可される間隔で実行し、1 回ごとに未処理分を処理して終了する形にします。
# NG — デプロイが拒否されるworkers: - name: drain command: "python worker.py" every: 10m
# OK — crons で書くcrons: - name: drain schedule: "*/5 * * * *" command: "python drain.py" timeout: 120assets
Section titled “assets”静的サイト、SPA、静的ファイル + バックエンド API(ハイブリッド)の配信設定です。
assets: dir: dist fallback: index.html api: /api| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
dir | string | はい | — | アセットディレクトリ(プロジェクトルートからの相対パス) |
static_dir | string | — | null | dir の廃止された別名。両方ある場合は一致が必要 |
fallback | string | 条件付き | null | SPA 用フォールバック(例: index.html)。dir 配下の相対パス。type: web を指定したハイブリッドでは必須 |
api | string | — | null(ハイブリッドでは実効値 /api) | バックエンドへ転送するパスプレフィックス。command と assets の両方があるハイブリッドで省略すると /api が使われる |
ハイブリッドでは api のパス配下がバックエンドへ転送され、それ以外は静的アセットとして配信されます。省略時のプレフィックスは /api です。別のパスにしたいときだけ指定します。
ルール:
dirに..は使えませんapiは/で始まり、/そのものではなく、/__keelson配下でないことapiはトップレベルのcommandがある場合のみ有効type: webを指定し、assetsとcommandの両方があるハイブリッドではfallbackが必須です。typeを省略した場合、設定検証ではfallbackの省略が認められます。SPA の画面を配信する場合はindex.htmlなどを指定してください
アーカイブに含まれるもの
Section titled “アーカイブに含まれるもの”静的サイト(type: web と assets を指定し、command なし)では、既定で assets.dir 配下のファイルと keelson.yaml だけをアップロードします。コンテナ型・ハイブリッド型では、ビルドに必要なソースも含めます。どちらも、以下の除外ルールが適用されます。
assets.dir: . や同じ意味の ./ は避けてください。プロジェクト直下が公開対象となり、アーカイブに含まれる全ファイルが配信される可能性があります。CLI はデプロイ前に警告しますが、この設定は禁止しません。
自動で除外されるファイル
Section titled “自動で除外されるファイル”- パスの構成要素が
.git、.venv、__pycache__、.pytest_cache、node_modules、dist、build、.idea、.vscode、.DS_Storeに一致するファイルやディレクトリ - ファイル名が
.envで始まるか終わるファイル(.env、.env.production、.envrc、.secrets.envなど)。assets.dirの中でも除外されます - シンボリックリンク、通常ファイル以外、
--secrets-from-env-fileで指定したファイル
宣言した assets.dir と、そこに至るまでのディレクトリは、名前による除外の対象外です。そのため、assets.dir: dist なら dist のビルド出力を含められます。ただし、その中の dist/node_modules/** などは除外されます。.git はこの例外の対象になりません。
.keelsonignore で変更できること
Section titled “.keelsonignore で変更できること”プロジェクト固有の除外は、プロジェクト直下の .keelsonignore に書きます。.gitignore は読みません。
| 書き方 | 意味 |
|---|---|
| 1 行 1 パターン | 一致するファイルやディレクトリを除外する。最後に一致した行が優先される |
# で始まる行 | コメント |
/、末尾 /、*、?、**、[abc]、[a-z] | gitignore に似たパス・パターン指定 |
先頭 ! | 一致するファイルやディレクトリを再び含める |
!.env.production で env ファイルを意図的に含めることもできます。ただし、.git などの組み込み除外、.keelsonignore 自身、--secrets-from-env-file で指定したファイルは戻せません。
静的サイトで assets.dir の外側にあるファイルを含めたい場合も、先頭 ! を使います。ディレクトリとその中身を含めるには、!keep/ と !keep/** の両方が必要です。
アップロード前の確認
Section titled “アップロード前の確認”keelson deploy --check --json を実行し、除外されたファイルと、秘密情報を含む可能性があるファイルを確認してください。
- プレビュー用の認証情報やアプリ用トークンがファイル内で検出された場合は、アップロードを停止します
- Webhook 署名鍵だけが検出された場合は、警告を表示して続行します
- ファイル名などから秘密情報を含む可能性があると判断した場合も、警告を表示します。警告だけでは除外されないため、必要に応じて
.keelsonignoreに追加します
--check は主要な設定も手元で検証します。ただし、assets / crons / auth / secrets 内の未知のキー、cron 式の妥当性、verify のパス形式などは API 側で検証します。--check が通っても、デプロイ時に deploy.config.invalid で止まる場合があります。
確認結果の項目と検査範囲
Section titled “確認結果の項目と検査範囲”| JSON の項目 | 確認できる内容 |
|---|---|
archive.excluded | 除外されたファイル |
archive.excluded_env_files | 除外された env ファイル |
archive.secret_like_files | 名前などから秘密情報を含む可能性があると判断されたファイル |
archive.embedded_credentials | ファイル内で検出された認証情報のパスと種別。値は表示しない |
archive.unscanned_files | サイズ上限などにより本文を検査しなかったファイル |
archive.unscanned_binary_count | バイナリと判定され、本文を検査しなかったファイルの数 |
16 MiB を超えるファイルと、バイナリと判定されたファイルは本文を検査しません。アーカイブから除外されたファイルも検査対象外です。
secret_like_files には、credentials.json や *.pem のような名前のほか、過去に --secrets-from-env-file で指定したものの、今回は除外されていない実在ファイルも含まれます。prod-secrets.txt のように env ファイルの命名規則に当てはまらない名前も対象です。
過去に指定したファイルを判定するため、CLI はそのプロジェクト相対パスを .keelson-config/previous-secrets-files.json に保存します。この記録には秘密の値は含まれず、記録ファイル自体もアップロードから自動で除外されます。
ブラウザキャッシュ
Section titled “ブラウザキャッシュ”ファイル名にコンテンツハッシュが入った JavaScript / CSS(例: index-B7hK2mQ1.js)は 1 年間キャッシュされます。Keelson は、ASCII 英数字と _ からなり英字と数字の両方を含む 8〜64 文字の末尾セグメントをハッシュと認識します。HTML、style.css や app.js のようなハッシュなしのファイル、画像などは、アクセスのたびに ETag で更新を確認します。
静的サイト(edge-static / edge-spa)の再デプロイは、新しいファイルがエッジに反映されるまで最大 60 秒ほどかかります(実測 1〜57 秒、中央値は 30 秒前後)。60 秒待ってからファイルの有無を判断してください。
health
Section titled “health”デプロイ時のヘルスチェックに使うパスです。/ が重い、DB に依存する、などの場合に軽量なエンドポイントを指定します。
health: path: /health- 省略時は
/を確認します /で始まり、..を含まず、/__keelsonで始まらない 2048 文字以内のパス- HTTP 2xx / 3xx / 404 で合格、それ以外の 4xx と 5xx で不合格。404 が通るため、合格は「起動した」ことの確認であり、そのパスが実装されていることの証明ではありません
- 候補リビジョンの内部 URL へ直接送られ、公開ホストや認証は経由しません。公開パスの検証は
verifyで行います
secrets
Section titled “secrets”アプリが必要とするシークレットと、必須の組み合わせを宣言します。値はここには書かず、コンソール、CLI、またはデプロイ時の env ファイルで設定します。
secrets: items: - name: OPENAI_API_KEY description: "OpenAI API key" - name: ANTHROPIC_API_KEY description: "Anthropic API key" required: - any_of: [OPENAI_API_KEY, ANTHROPIC_API_KEY] message: "AI プロバイダのキーを少なくとも 1 つ設定してください"| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
items | list | — | [] | シークレットの定義 |
items[].name | string | はい | — | 名前。環境変数の形式(大文字英字か _ で始まり、A-Z0-9_ のみ、255 文字以内)で書く。KEELSON_ で始まる名前は予約 |
items[].description | string | — | "" | 用途の説明。コンソールに表示される |
required | list | — | [] | 設定済みシークレットに対して検証するルール |
required[].any_of | list | 条件付き | null | いずれか 1 つが設定されていればよい名前の空でないリスト |
required[].all_of | list | 条件付き | null | すべて設定されている必要がある名前の空でないリスト |
required[].message | string | — | "" | 未設定時に表示する案内 |
required の各エントリは any_of または all_of のどちらか一方だけを持ちます。参照できるのは items で宣言した名前だけです。
名前は値を設定するときに大文字に正規化され、required の照合は大文字小文字を区別します。name: api_key と書くと値は API_KEY として保存され、required の条件が満たされません。最初から大文字で書いてください。MY-KEY のようにハイフンを含む名前は宣言できても値を設定できません。
新しいアプリでは keelson deploy --new --secrets-from-env-file <path> で、アプリ作成・シークレット設定・初回デプロイを 1 回で行えます。既存アプリのシークレット変更は次のデプロイで反映されます。
Webhook の受信など、対話ログインを通さずに外部システムから呼ばれるエンドポイントを宣言します。
auth: endpoints: - /api/webhooks/stripe - path: /api/external/status methods: [GET]authがある場合、endpointsは空でないリストが必須です- 各エントリはパス文字列、または
pathと省略可能なmethodsを持つオブジェクト - パスは
/api/external/または/api/webhooks/で始まり、重複しないこと。/__keelson配下は不可 - パスは前方一致です。
/api/external/statusは/api/external/status-extraにも一致します methodsを指定する場合は空でないリスト。省略時は全メソッドを許可。大文字小文字は区別しませんmethodsが効くのは/api/external/だけです。/api/webhooks/には適用されず、メソッドを絞りたければアプリ側で判定します
「対話ログインを通さない」は「Keelson の認証が不要」という意味ではありません。宣言しただけでは外部から届かず、呼び出し側は Keelson が発行する資格情報を付ける必要があります。
| パス | 必要な資格情報 |
|---|---|
/api/external/... | api スコープのアプリトークンを Authorization: Bearer で送る |
/api/webhooks/... | webhook スコープのアプリトークンを X-Webhook-Secret ヘッダーで送るか、/api/webhooks/<secret>/... の形の URL を外部サービスに登録する |
トークンの発行は keelson apps tokens create、URL の組み立ては外部連携を参照してください。Stripe の署名だけを送る通常の Webhook や、アプリ独自の API キーだけを送るクライアントは、アプリに届く前に拒否されます。
これらのパスへのリクエストでは X-Keelson-User-Id は空文字になります(ヘッダー自体は常に付き、対話ユーザーがいなければ空)。空を「ユーザーなし」として扱ってください。Keelson の資格情報に加えて、アプリ側でも Webhook 署名や API キーによる検証を行ってください。
verify
Section titled “verify”デプロイ後の検証で追加で確認するパスです。既定では / だけを確認します。
verify: - /dashboard - /settings- 単一のパスは文字列でも 1 要素のリストでも指定できます
- 最大 20 パス(前後の空白を除き、重複を除いた数)。各パスは
/で始まり、//で始まらず、パス要素としての..と制御文字を含まないこと - コンテナ型・ハイブリッド型では公開ホスト経由で候補リビジョンから取得し、静的サイト・SPA では公開前にリリースマニフェスト上で解決します
- どちらの種類でも、宣言したパスが 2xx / 3xx 以外(404 / 401 / 403 / 405 など)なら
verification_declared_path_unreachableでデプロイに失敗します verify:にはアプリ自身のログインを必要としないパスを書いてください。検証リクエストにはアプリのユーザー情報が付かないため、アプリが返す 401 / 403 も不合格です/はverify:にも書かれていても従来どおり寛容です。API だけのアプリが/で 404 を返しても合格します
クライアント側ルーティングでしか到達できない画面など、/ から辿れないエントリを確認したいときに使います。
これは health.path とは別の判定です。health.path は候補リビジョンを内部 URL で直接確認し、プロセスが起動した証拠として 404 でも合格します。verify は宣言した公開パスが実際に配信できるかを確認するため、404 では不合格です。
region
Section titled “region”新規アプリを作るときの配置リージョンを任意で指定します。
region: jp-tokyoクラウド事業者のリージョン名ではなく、Keelson の論理キーを指定します。
| 論理キー | 表示名 | 新規作成 |
|---|---|---|
jp-tokyo | 日本 | 可(既定) |
us-oregon | 米国西海岸 | 未提供(指定すると拒否) |
新規アプリでは CLI の --region、keelson.yaml の region、ワークスペースの既定リージョンの順で優先されます。明示したリージョンが未定義または新規作成に未開放の場合は、別リージョンへ切り替えずに拒否されます。
アプリのリージョンは作成時に確定し、後から変更できません。既存アプリと異なる region を指定したデプロイは拒否されます。別リージョンへ移す場合は、新しいアプリとして作り直してください。
storage
Section titled “storage”storage は廃止された disk_id だけを受理します。値は無視され、永続ストレージや /data の同期を有効にしません。残っていたら削除してください。
| フィールド | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
disk_id | string | — | null | 無視される旧識別子。小文字英数字とハイフン、1〜32 文字 |
デプロイモード
Section titled “デプロイモード”デプロイモードは command、assets、assets.fallback の有無から自動的に決まります。keelson status --json などの出力では、下表の値が deploy_mode に返されます。静的サイト・SPA の設定には type: web も必要です。
| 呼称 | deploy_mode | command | assets | fallback | 説明 |
|---|---|---|---|---|---|
| Web アプリ | container | あり | なし | — | 通常のアプリ |
| 静的サイト | edge-static | なし | あり | なし | 静的ファイルのみ |
| SPA | edge-spa | なし | あり | あり | フォールバック付き静的ファイル |
| ハイブリッド | hybrid | あり | あり | type: web を指定した場合は必須 | 静的ファイル + バックエンド API |
フィールド間の制約
Section titled “フィールド間の制約”| ルール | 内容 |
|---|---|
| 起動コマンド・定期実行ジョブ・静的サイトのいずれかが必要 | command、crons、または type: web と assets の組み合わせを指定する |
| タスクには投入するコードが必要 | tasks がある場合は command か crons を指定する(tasks_require_command_or_crons) |
| タスクとジョブの名前は別にする | tasks[].name は crons[].name と同じにできない(task_name_conflicts_with_cron) |
| 静的サイトと定期実行ジョブは併用不可 | 静的サイトに必要な type: web と crons を併記すると、設定検証で拒否される。定期実行ジョブを使う場合は type を省略する |
| 静的サイトにはコンテナがない | 静的サイト・SPA では db.migrate を宣言しても実行されない。マイグレーションを使う場合はコンテナ型かハイブリッド型にする |
workers は廃止 | リクエストの後に実行する処理は tasks、決まった時刻に実行する処理は crons で書き直す |
db.migrate は libsql のみ | db.mode: libsql が必要 |
| ローカル SQLite は一時領域のみ | db.local_sqlite.paths は /tmp/ 配下か :memory: |
mcp はサーバー側のプログラムが動くアプリだけ | command があり assets がないアプリにだけ書ける(mcp is only supported for container apps) |
assets.api にはバックエンドが必要 | トップレベルの command を設定する |
type: web を指定したハイブリッドには fallback が必要 | type: web、assets、command を併記する場合は assets.fallback を設定する。type を省略した場合は、この必須チェックの対象外 |
Web アプリ + Managed SQLite
Section titled “Web アプリ + Managed SQLite”slug: crud-appdescription: "顧客と案件を管理する社内 CRM"runtime: python-slimcommand: "python app.py"db: mode: libsql migrate: "python migrate.py"env: PYTHONUNBUFFERED: "1"静的 SPA
Section titled “静的 SPA”手元で npm run build などを実行して dist を作ってからデプロイします。Keelson 側ではビルドしません。
slug: marketing-sitetype: webruntime: node-slimdb: mode: noneassets: dir: dist fallback: index.html定期実行のみ
Section titled “定期実行のみ”slug: daily-reportruntime: python-slimdb: mode: libsqlenv: PYTHONUNBUFFERED: "1"crons: - name: generate schedule: "0 9 * * *" command: "python report.py" timeout: 120Web アプリ + バックグラウンドタスク
Section titled “Web アプリ + バックグラウンドタスク”Web アプリがリクエストを受けて SDK で generate-pdf を投入し、Keelson が Web アプリとは別のインスタンスでタスクのコマンドを実行します。詳しくはバックグラウンドタスクを参照してください。
slug: pdf-reportsruntime: python-slimcommand: "python app.py"db: mode: libsqlenv: PYTHONUNBUFFERED: "1"tasks: - name: generate-pdf command: "python generate_pdf.py" timeout: 180 max_attempts: 3Web アプリ + 未処理データを定期的に処理するジョブ
Section titled “Web アプリ + 未処理データを定期的に処理するジョブ”タスクを使わずにリクエストの後の処理を組む場合は、未処理のデータを DB に保存して定期実行ジョブで処理します。処理は次の実行まで待ちます。リクエストの後すぐに始めたい処理には、バックグラウンドタスクを使ってください。
Web アプリが未処理のデータを Managed SQLite に保存し、定期実行ジョブが別のインスタンスで処理します。両者で共有するデータは db.mode: libsql に保存します。
slug: task-drainerruntime: python-slimcommand: "python app.py"db: mode: libsqlenv: PYTHONUNBUFFERED: "1"crons: - name: drain schedule: "*/5 * * * *" command: "python drain.py" timeout: 120ハイブリッド(静的ファイル + バックエンド API)
Section titled “ハイブリッド(静的ファイル + バックエンド API)”slug: photo-galleriesruntime: node-slimcommand: "node server.js"db: mode: libsqlenv: NODE_ENV: "production"assets: dir: dist fallback: index.html api: /apiWebhook を受ける API
Section titled “Webhook を受ける API”slug: payment-hooksruntime: node-slimcommand: "npm start"db: mode: libsqlenv: NODE_ENV: "production"secrets: items: - name: STRIPE_WEBHOOK_SECRET description: "Stripe の Webhook 署名シークレット" required: - all_of: [STRIPE_WEBHOOK_SECRET]auth: endpoints: - path: /api/webhooks/stripe methods: [POST]Stripe に登録する URL には webhook スコープのアプリトークンを含めます(https://<host>/api/webhooks/<token>/stripe)。methods は Webhook には適用されないので、POST 以外を拒否したければアプリ側で判定します。
Go アプリ
Section titled “Go アプリ”slug: my-go-appruntime: go-slimcommand: "./app"db: mode: noneKeelson がデプロイ時に Linux 向けにビルドし、バイナリを ./app に置きます。
よくあるエラー
Section titled “よくあるエラー”| 原因 | 対処 |
|---|---|
db または db.mode がない | db.mode を libsql か none で宣言する |
廃止された databases がある | 削除する。永続データは Managed SQLite、一時 SQLite は db.local_sqlite で宣言 |
workers がある(workers_not_supported) | 削除する。リクエストを受けて走らせる処理は tasks、時刻で動く処理は crons で書く |
command に pip install / npm install がある(command_installs_dependencies) | 削除する。依存はビルド時に自動インストールされる |
依存マニフェストがない(missing_dependency_manifest) | Go ではプロジェクトルートに go.mod を置く。Python または Node.js では、外部ライブラリを使う場合に適切なマニフェストを置く。標準ライブラリだけなら不要 |
runtime と command の言語が合わない(runtime_command_mismatch) | ランタイムを合わせるか、起動コマンドを直す |
env の値が引用符なし(env_value_not_string) | すべての値を引用符で囲む(数値・真偽値も) |
環境変数名が KEELSON_ で始まる | 名前を変える。この名前空間はプラットフォーム予約 |
local_sqlite.paths が /tmp/ の外 | /tmp/、:memory:、または Managed SQLite を使う |
| 起動コマンド・定期実行ジョブ・静的サイトの設定がない | command、crons、または type: web と assets の組み合わせを追加する |
crons[].timeout が 600 を超える | 600 以下、かつプランの上限以下にする |
tasks があるのに command も crons も無い(tasks_require_command_or_crons) | タスクを投入する Web アプリの command、または crons のジョブを追加する |
タスクと定期実行ジョブの名前が同じ(task_name_conflicts_with_cron) | どちらかの名前を変える |
tasks[].timeout が 600 を超える(TASK_TIMEOUT_EXCEEDS_STANDARD_LIMIT) | 600 以下、かつプランの上限以下(plan_task_timeout)にするか、処理を小さなタスクに分ける |
mcp.enabled が true なのに mcp.tools がない | ツールを 1 本以上宣言するか、mcp.file で別ファイルに置く |
静的サイト・SPA・ハイブリッドに mcp がある(mcp is only supported for container apps) | mcp を削除するか、command だけのアプリにする |
mcp.tools[].input に $ref や x-mcp-header がある | スキーマを展開して書く。$dynamicRef と $recursiveRef も使わない |
mcp contains unsupported field(s): file | Keelson CLI が古い。keelson upgrade で最新版にする |
assets.api が / で始まらない | /api のような絶対パスにする |
type: web を指定したハイブリッドで assets.fallback がない | index.html などを設定する |
ビルドが reserved_path_conflict で失敗 | ビルド出力直下の __keelson ディレクトリを改名する |