mcpField
P
psh.now

psh.now

リモート
psh.nowその他0今日更新
リポジトリ公式サイト

psh.now について

psh.nowは、AIエージェントの要求を一時停止し、人が承認、拒否、または返信するための承認サービスです。シェルコマンドまたはHTTPを使えるエージェントに対応し、セルフホストも可能です。

主な機能

  1. 01エージェント要求の人間による承認
  2. 02スマートフォンからの承認・拒否
  3. 03自由記述での要求への返信
  4. 04CLIとHTTP API
  5. 05Claude Codeのツール実行前フック
  6. 06セルフホストでの運用

活用シーン

  1. 01破壊的なコマンドの前に承認を求める
  2. 02スマートフォンから本番操作を確認する
  3. 03エージェントの実行中に質問へ回答する
  4. 04Claude CodeのBashコマンドを制御する

設定

リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。

エンドポイントhttps://psh.now/mcp
インストールコマンドをコピー
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。

すべてのエンドポイント
Streamable HTTPhttps://psh.now/mcp認証が必要

ツール

詳細

psh.now

AI エージェントに人間の承認を:ホスト1つ、キー1つ、ブール値1つ。

リクエストがノッチに届き、コメントを入力して送信すると、次のリクエストが届きます

skills.sh

判断が必要なエージェントは、短いタイトルとメッセージを psh.now に送信して待機します。 1つのページで承認または拒否をタップするか、自分の言葉で回答すると、エージェントは結果を受け取って処理を続けます。誰も見ていないターミナルでエージェントが停止してしまう問題を解決するために作られました。

  • シェルコマンドを実行できる、または HTTP リクエストを送信できるエージェントなら、どれでも使えます。SDK も MCP も不要です。
  • 接続できないサンドボックスも含め、あらゆるエージェントとマシンで使える1つのページ。
  • セルフホスト可能:MIT ライセンス、コンテナ2つ、環境変数3つ。
┌────────────┐   blocking POST /        ┌────────────────┐   WebSocket    ┌─────────┐
│ AI agent   │ ───────────────────────► │ psh.now gateway │ ─────────────► │  phone  │
│ (terminal) │                          │  (Elysia +     │                │  (PWA)  │
│            │ ◄─────────────────────── │  Postgres)     │ ◄───────────── │         │
└────────────┘   { approved: true }     └────────────────┘  decision       └─────────┘

リクエストはタイトルとメッセージで構成され、シェルコマンドだけではありません。実行するコマンド、実行するアクション、または回答する質問を指定できます。

次に読む

目的読む
インストールして最初のリクエストに回答するクイックスタート
自分のサーバーで実行するdocs/self-hosting.md または任意のインスタンスの /self-hosting
処理の流れを最初から最後まで理解するdocs/how-it-works.md
API を直接呼び出すHTTP API
エージェントにプロンプトを貼り付けるdocs/prompt-templates.md
脆弱性を報告するSECURITY.md
貢献するCONTRIBUTING.md

技術スタック

レイヤー採用技術
ランタイムBun
HTTP / WSElysia
データベースPostgreSQL + Drizzle ORM
リアルタイムWebSockets + Postgres LISTEN/NOTIFY(マルチノードへの配信)
フロントエンドビルド不要の PWA(バニラ ES モジュール + サービスワーカー)

クイックスタート

# 1. install
bun install

# 2. configure
cp .env.example .env          # then set DATABASE_URL / PUBLIC_BASE_URL
createdb psh.now                 # if it doesn't exist

# 3. migrate
bun run migrate

# 4. run the gateway
bun run dev                   # http://localhost:3000

次に、保護したいプロジェクトで以下を実行します。

bun /path/to/psh/cli/psh.ts init

これによりワークスペースが作成され、API キーが表示され、ペアリング用 QR コードが生成され、./agents.md に管理対象のルールブロックが書き込まれます。スマートフォンで QR コードをスキャンして PWA を開き、このデバイスをペアリングをタップすると、すぐに使えます。

またはブラウザーでチャンネルを作成する

/setup(例:http://localhost:3000/setup)を開きます。ワークスペースが作成され、API キーが一度だけ表示され、ペアリング用 QR コードが生成されます。デバイスをペアリングするとダッシュボードが開き、すぐに承認テストが送信されます。これにより、ターミナルを使わずに通知と承認・拒否の一連の流れを確認できます。ダッシュボードの承認テストを送信ボタンでいつでも再実行でき、招待から、すでにペアリング済みの任意のデバイスで新しいペアリングコードを発行できます。

手動で確認する
# commands, actions, and questions all use the same call
psh ask "Drop the users table and reseed?" --title "Database reset"
Claude Code フック

.claude/settings.json にフックを一度登録します。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "psh hook" }]
      }
    ]
  }
}

psh hook は Claude の PreToolUse JSON を標準入力から読み込み、判断の契約を標準出力に書き込みます(permissionDecision: "allow" | "deny")。すべての Bash コマンドはスマートフォンでの承認を待ちます。Bash 以外のツールはそのまま通過します。読み取り専用コマンドを自動的に許可するには、PSH_SKIP_PATTERN に正規表現を設定します。

PSH_SKIP_PATTERN='^(ls|cat|git status|rg)\b' psh hook

独自のキーを使ってホスト型インスタンスを利用する

サインアップすると、ワークスペースとキーが1つ付与されます。このキーはエージェントの認証情報です。これにより、質問が他の人ではなく、あなたのアカウントに表示されます。

  1. キーを取得します。 ホスト型ダッシュボードを開き、ワークスペースを作成して、キーをコピーします。 キーは一度だけ表示されます。同じページに、スマートフォン用のペアリングQRコードも表示されます。
  2. シェルのプロファイルではなく、プロジェクトに設定します。 エージェントに作業させたいプロジェクト内にスキルをインストールします。これにより、<project>/.psh/keys.json (およびマシンの記録ファイル ~/.psh/keys.json)が作成されます。キーは意図的にプロジェクトごとに分けられているため、2つのプロジェクトを別々のワークスペースに所属させることができ、このファイルをバージョン管理に含める必要もありません。
  3. 質問します。 <project>/.psh/keys.json は、CLIとスキルの psh shimが読み込むファイルです。作業ディレクトリから上の階層を検索します。グローバルに設定する必要はありません。
  4. ノッチまたはスマートフォンから承認します。 ノッチではエージェントキーを一切使用しません。デバイスをペアリングし(ダッシュボードの「Devices」から「Connect a device」を選択)、デバイスごとのトークンを ~/.config/psh-notch/device.json にパーミッションモード0600で保存します。このトークンでは承認と読み取りができますが、キーのローテーションはできません。また、デバイスごとに取り消せます。

このように、2つの認証情報は意図的に分けられています。キーでエージェントが質問し、デバイストークンで人間が回答します。キーをマシン間でコピーするとエージェントが移り、デバイストークンをコピーすると承認画面が移ります。

ホスティングとセルフホスティング

ホスト型のpsh.nowもセルフホスト版も、同じ単一プロセスです。デプロイを「公開」にするのは PUBLIC_BASE_URL だけです。

PUBLIC_BASE_URL=https://psh.now

これを設定すると、生成されるすべてのペアリングリンクが https://psh.now/pair/<code> になり、どこにいても、どのスマートフォンからでも開けるようになります。 エージェントのエンドポイントも同じオリジンです。

curl -s -X POST https://psh.now \
  -H "x-psh-key: psh_live_…" \
  -H "Content-Type: application/json" \
  -d '{"title":"Reinstall deps","message":"rm -rf node_modules && npm install --force"}'

PWAは location.host からWebSocket URLを導出するため、HTTPSで配信すれば再ビルドなしで自動的に wss://… が使われます。1つのインスタンスで、互いに隔離された複数のワークスペース/テナントを提供できます。

最もシンプルなデプロイ(Dockerもリバースプロキシも不要)

実行環境はBunだけです。Postgresを指定して実行します。

cp .env.example .env          # set DATABASE_URL + PUBLIC_BASE_URL
bun src/db/migrate.ts
bun src/index.ts

これで完了です。systemd(または tmux/pm2)の下で動かせば、ホストノードとして利用できます。

Caddyを使わないHTTPS/WSS

Bun自体がTLSを終端するため、Caddyもnginxも不要です。証明書(例:Let's Encryptで取得)を用意し、psh.nowの接続先を設定します。

export TLS_CERT_FILE=/etc/letsencrypt/live/psh.now/fullchain.pem
export TLS_KEY_FILE=/etc/letsencrypt/live/psh.now/privkey.pem
export PUBLIC_BASE_URL=https://psh.now
bun src/index.ts

サーバーには https://… とログ出力され、PWAは自動的に wss://… を使用します。TLS_CERT_FILE/TLS_KEY_FILE が未設定の場合は、プレーンなHTTPで配信され(起動時にその旨が表示されます)。更新には、デプロイフックを使った certbot certonly を使用するか、すでに管理している証明書を使用してください。

リバースプロキシが役立つのは、すでに運用している場合、1つのIPアドレスで複数のサービスをホストしたい場合、またはpshに手を加えずに証明書を自動更新したい場合だけです。 deploy/Caddyfile はその場合に備えて用意されていますが、必須ではありません。

ブロッキング処理とプロキシのタイムアウト。 POST / は人間が回答するまで接続を維持します。Cloudflareや多くのプロキシでは、オリジンからの応答が約100秒で打ち切られます(Cloudflareは524を返します)。DEFAULT_TIMEOUT_MS をプロキシの制限時間(デフォルトは90秒)より短くするか、psh.nowを直接実行するか、CDNを介さずにセルフホストしてください。エージェントは524/タイムアウトを未承認として扱う必要があります(スキルにもそのように記載されています)。

Docker(任意)

コンテナの利用を希望する場合は、Dockerfileとdocker-compose.ymlでPostgresとゲートウェイをまとめて起動できます。必須ではなく、標準の方法でもありません。

cp .env.example .env
# edit PUBLIC_BASE_URL (or keep http://localhost:3000 for local)
docker compose up -d --build

マイグレーションは冪等なので、起動のたびに実行しても安全です。


agents.md(またはスキル)にキーを設定する

連携に必要なのは、ホスト、キー、1つの指示だけです。psh init を実行すると、実際のホストとキーを使って以下のブロックが ./agents.md に書き込まれます (templates/agents-snippet.md を参照してください)。

## Ask before you act

Before any destructive, irreversible, or production action, ask first:

curl -s -X POST https://psh.now \
  -H "x-psh-key: psh_live_…" \
  -H "Content-Type: application/json" \
  -d '{"title":"<short label>","message":"<what you are about to do>"}'

Proceed only if the response is {"approved":true}. Otherwise do not act.

スキルに対応しているハーネスでは、代わりに(または併せて) skills/psh-now/SKILL.md を読み込めます。これは Anthropic Agent Skills / Hermes 形式で、metadata.hermes ブロックを含み、同じ契約をあらゆる LLM に教えます。また、いつ確認を求めるべきか、いつ求めるべきでないかについてもガイダンスを追加します。

スキルをインストールします(here.now と同じ形式です)。

# if you have npm/npx: one command, so the harness asks for approval once.
# It installs machine-wide and mints in the same run.
npx skills add passy-ai/psh-now-skill -g -y

# no npm? the hosted installer (works in a sandbox too, no credentials needed)
curl -fsSL https://psh.now/install.sh | sh

次に、エージェントにホストとキーを渡します(環境変数または agents.md)。

export PSH_BASE_URL="https://psh.now"
export PSH_API_KEY="psh_live_..."

サーバーはスキルとインストーラー自体もホストします。/skill.md、/install.sh、 /llms.txt、/llms-full.txt、および /.well-known/* マニフェストです。

任意のエージェントとの連携に必要なものは、これだけです。

  • 確認:モデルは agents.md / スキルに従い、ホストを呼び出します。シェルまたは HTTP ツールにアクセスできる LLM なら、どれでも実行できます。
  • ゲート:psh hook をハーネスのツール実行前フックに接続します。このフックはスキップできません。オプションであり、ハーネスが対応している場合にのみ利用できます。

agents.md 内の API キーは秘密情報です。そのファイルをコミットする場合は gitignore に追加するか、キーを PSH_API_KEY に格納して、代わりに環境変数を参照してください。


ブロックの仕組み

  1. エージェント → ゲートウェイ。 エージェントは x-psh-key ヘッダーを付けて { title, message, kind?, cwd?, agent? } を POST /(または /api/v1/hook)に送信します。(旧形式の command も引き続き message のエイリアスとして受け付けます。)
  2. リスクスキャン。 タイトルとメッセージをルールセット(rm -rf、--force、sudo、curl | sh、DROP TABLE、強制プッシュなど)と照合し、人間が読める理由とともに low → critical のリスク区分に分類します。
  3. 保留。 リクエストの Promise は、タイムアウト付きでプロセス内の待機レジストリに保留されます。HTTP 接続は開いたままで、ターミナルはフリーズします。 非同期オプション: wait:false を送信すると、呼び出しはすぐに pollUrl を返すため、処理はブロックされず、プロキシや CDN のタイムアウトで中断されることもありません。GET /api/v1/prompts/:id?wait=30 でポーリングします。
  4. 通知。 プロンプトは、そのテナントにペアリングされたすべてのデバイスにブロードキャストされます。
  5. 決定。 スマートフォンは WebSocket 経由で { type: "decision", promptId, approved } を送信します(フォールバックとして POST /api/v1/prompts/:id/decision も使用できます)。決定はアトミックに永続化され(pending → approved/denied)、NOTIFY psh_decisions 経由で配信され、待機中の処理が再開されます。
  6. 再開。 エージェントは { approved: true|false } を受け取り、処理を実行します。

タイムアウトやエージェント接続の切断が発生すると、自動的に拒否されます(status: "expired")。そのため、スマートフォンが失われても、ビルドが永久に停止することはありません。回答期限を過ぎた保留中のプロンプトは expired に変更されます(非同期リクエストにはタイムアウト対象の待機処理がありません)。


HTTP API

メソッドパス認証用途
POST/ · /api/v1/hookx-psh-key承認リクエスト(ブロッキング、または wait:false)
POST/mcpx-psh-keyMCP:1 つのツール、psh_ask(ストリーム可能な HTTP、JSON)
GET/.well-known/mcp.json-クライアントおよびスキャナー向け MCP ディスクリプター
POST/api/v1/channels-ワークスペースをプロビジョニング(ペアリングリンクの場合は pair:true)
POST/api/v1/claimskey / device匿名ワークスペースのクレームコードをリクエスト
POST/api/v1/claims/:id/verify-コードを検証し、ワークスペースを恒久化
POST/api/v1/pairingkey / deviceペアリングリンク/QR コードを作成
GET/api/v1/qr-任意の文字列を SVG QR コードとして描画
GET/api/v1/pairing/:token-ペアリングトークンを検証
POST/api/v1/pairing/:token/claim-トークンをデバイストークンと交換
GET/api/v1/mex-psh-keyワークスペースの概要
GET/api/v1/promptskey / deviceプロンプトの一覧(?status=、?limit=)
GET/api/v1/prompts/:idkey / deviceプロンプトを取得。?wait=<s> でロングポーリング
POST/api/v1/prompts/:id/cancelkey / device保留中のリクエストをキャンセル
POST/api/v1/connectionskey / device接続を登録(エージェント/プロジェクト)
GET/api/v1/connectionskey / device接続の一覧(1 つのアカウント → 複数の接続)
GET/api/v1/connections/:idkey / device接続とそのリクエスト
DELETE/api/v1/connections/:idkey / device接続を削除
POST/api/v1/testkey / deviceブロッキングしないテスト承認を送信
POST/api/v1/prompts/:id/decisionkey / deviceHTTP 経由で決定(WS フォールバック)
GET/api/v1/deviceskey / deviceペアリング済みデバイスの一覧
DELETE/api/v1/devices/:idkey / deviceデバイスを失効
GET/api/v1/keyskey / deviceエージェントキーの一覧
POST/api/v1/keyskey / device復元可能なエージェントキーを作成
GET/api/v1/keys/:id/revealkey / deviceオペレーターにキーの生の値を表示
DELETE/api/v1/keys/:idkey / deviceエージェントキーを失効
GET/api/v1/health-ヘルスチェック
WS/ws?token=<deviceToken>device tokenライブプロンプトストリームと決定

インタラクティブなドキュメントは /docs にあります(Swagger)。

MCP

HTTP 呼び出しが契約です。MCP は、スキルをインストールできないクライアント(ホステッドビルダー、コネクター UI、プロトコルだけを扱うアプリ)向けの第 2 の窓口です。エンドポイントは 1 つ、ツールは 1 つ、OAuth なし、サーバー起点のストリームなし。同じハンドラーを薄い JSON-RPC でラップするため、計測、期限切れ、判断経路が両方のインターフェース間で食い違うことはありません。

claude mcp add --transport http psh https://psh.now/mcp --header "x-psh-key: psh_agent_..."
{ "mcpServers": { "psh": { "url": "https://psh.now/mcp",
    "headers": { "x-psh-key": "psh_agent_..." } } } }

psh_ask は {title?, message, timeoutSec?} を受け取り、処理が完了するまで待機して、{"approved":bool,"status":"approved|denied|answered|expired","answer":string|null,"promptId":"..."} を返します。approved: true だけが承認を意味します。denied、expired、エラーはいずれも、実行してはいけないことを意味します。MCP はスキルと同様に協調的に動作するため、呼び出さないエージェントを止めることはできません。ゲートの役割を担うのはフックです。

プロトコルの詳細、エラーコード、インターフェースを小さくした理由については、docs/mcp.md をご覧ください。

WebSocket フレーム

サーバー → 電話:

{ "type": "hello",         "workspace": {…}, "device": {…}, "pending": [...] }
{ "type": "prompt.created", "prompt": { "id": "pr8x1k…", "title": "Reinstall deps", "message": "rm -rf node_modules", "kind": "command", "risk": "critical", "riskReasons": [...] } }
{ "type": "prompt.decided", "promptId": "…", "approved": true }

電話 → サーバー:

{ "type": "decision", "promptId": "pr8x1k…", "approved": true, "reason": "ok" }
{ "type": "ping" }

セキュリティモデル

  • API キーは一度だけ表示され、SHA-256 ハッシュとしてのみ保存されます。
  • デバイストークンはランダムに生成され、ハッシュ化して保存されます。デバイスごとに取り消し可能です。
  • ペアリングトークンは 1 回限り使用でき、有効期限があります(デフォルトは 10 分)。
  • 短い ID。 すべての公開識別子は base62 で、長さは最大 32 文字です。そのため、すべての URL は YouTube の短縮 URL と同じくらい短くなります(/pair/UpDbWPKjQjoAqVtLdehnwQ)。
  • 有効期間の短い認証情報のみを通信経路で送信します。ペアリング後、エージェントに秘密情報が送信されたり、URL に埋め込まれたりすることはありません。
  • すべての判断は追記専用の audit_log に記録されます。

マルチノード/スケーリング

ブロックされた Promise はエージェントのリクエストを受け付けたノード上に保持されますが、電話は別のノードに接続されている場合があります。NOTIFY psh_decisions がすべての判断を全ノードにブロードキャストし、各ノードが一致するローカルの待機処理を解決します。スティッキーセッションは不要で、Redis も必要ありません。調整用プリミティブは Postgres のみです。


プロジェクト構成

src/
  index.ts            Elysia app + graceful shutdown
  env.ts              Validated configuration
  db/
    schema.ts         Drizzle tables (tenants, devices, prompts, …)
    index.ts          postgres.js pool + Drizzle client
    migrate.ts        Migration runner
  lib/
    ids.ts            Short base62 ID generator
    crypto.ts         API key generation, SHA-256, header parsing
    risk.ts           Command risk scanner
    waiters.ts        In-process blocked-request registry
    realtime.ts       WebSocket per-tenant hub
    pubsub.ts         Postgres LISTEN/NOTIFY fan-out
    tenant-auth.ts    Request authentication
    http.ts           Typed HTTP errors
  services/           Business logic (tenants, devices, prompts, decisions)
  routes/             auth · hook · prompts · ws
public/               PWA (index/pair HTML, app.js, sw.js, manifest)
cli/psh.ts           init · pair · ask · hook · status · doctor
tests/e2e.ts          Full approval-loop integration test
drizzle/              Generated SQL migrations

テスト

bun tests/e2e.ts      # boots the gateway, pairs a fake phone, exercises approve/deny/timeout
bunx tsc --noEmit     # type check

CLI

psh init        Create a workspace + pairing QR
psh pair        Mint a new pairing link
psh ask "cmd"   Block until a human approves/denies  [--timeout <seconds>]
psh hook        Agent hook (reads JSON on stdin)
psh status      Workspace + pending requests
psh doctor      Connectivity + credential check

ライセンス

MIT、Copyright (c) 2026 Absolum。LICENSE をご覧ください。psh.now のホステッドインスタンスはサービスであり、このライセンスの対象ではありません。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。