コンテンツにスキップ

Slack MCP Agent — Slack UI カード仕様書

v1.2 / 2026-04-20

Block Kit JSON レベルの詳細仕様。docs/mvp-spec.md Section 7 の実装ガイドとして使用する。


1. 設計原則

# 原則 詳細
P-1 1 タスク 4 メッセージ Task / Prompt / Process / Execution の 4 つだけ投稿
P-2 chat.update で書き換え 状態遷移ごとにブロック全体を再構築して chat.update。スレッド肥大化防止
P-3 rich_text 禁止 rich_text ブロックは ~13,200 文字制限 + section への置換不可。使わない
P-4 テキスト truncation section の mrkdwn は最大 3000 文字。超過時は末尾 ... で切り詰め
P-5 ブロック上限 1 メッセージ最大 50 ブロック。実際は最大 ~10 ブロックで収まる
P-6 actions 要素上限 1 actions ブロック最大 25 要素。実際は最大 3 ボタン
P-7 使用ブロック header / section / divider / context / actions のみ
P-8 attachment color で状態色 attachments[].color で左端カラーバーを表示し、カード状態を色で識別可能にする
P-9 card ブロック不使用 card ブロックは body 200 文字制限のため不採用。section ベースで構成する

2. 共通コンポーネント

2.1 テキスト truncation

_MRKDWN_MAX = 3000

def _truncate(text: str, limit: int = _MRKDWN_MAX) -> str:
    if len(text) <= limit:
        return text
    return text[:limit - 3] + "..."

2.2 Priority 絵文字マッピング

priority emoji 表示
low 🟢 Low
medium 🟡 Medium
high 🔴 High

2.3 ステップ進捗の絵文字

状態 emoji 意味
未実行 待機中
実行中 🔄 処理中
完了 成功
失敗 エラー

2.4 状態カラーマッピング(attachment color)

Block Kit にはカスタム背景色の概念がないが、attachments[].color パラメータで左端にカラーバーを表示できる。ブロックを attachments[].blocks に入れることで、状態を色で視覚的に識別可能にする。

状態 color Hex 用途
生成中 #f2c744 L1-L3 処理中
承認待ち #2196f3 ユーザーアクション要求
承認済み #36a64f 承認完了
却下 / 失敗 #e01e5a エラー・却下
実行中 #1264a3 Agent 処理中
完了 #36a64f 正常完了
中止 グレー #888888 キャンセル

attachment 構造テンプレート

ブロックをトップレベルの blocks ではなく attachments[].blocks に入れることで、色付きカードとして表示する。

STATUS_COLORS = {
    "generating": "#f2c744",
    "pending_approval": "#2196f3",
    "approved": "#36a64f",
    "rejected": "#e01e5a",
    "running": "#1264a3",
    "completed": "#36a64f",
    "failed": "#e01e5a",
    "cancelled": "#888888",
}

def wrap_in_attachment(blocks: list[dict], status: str) -> dict:
    """ブロック配列を色付き attachment でラップする。"""
    return {
        "attachments": [
            {
                "color": STATUS_COLORS.get(status, "#888888"),
                "blocks": blocks,
            }
        ]
    }

chat.postMessage / chat.update 時の使い方

# 投稿時
result = await client.chat_postMessage(
    channel=channel,
    thread_ts=thread_ts,
    text="実行方針を生成中...",  # fallback
    **wrap_in_attachment(
        blocks=build_prompt_card_generating(),
        status="generating",
    ),
)

# 更新時
await client.chat_update(
    channel=channel,
    ts=message_ts,
    text="実行方針の確認をお願いします",  # fallback
    **wrap_in_attachment(
        blocks=build_prompt_card_pending(prompt_content, task_id, prompt_id, version),
        status="pending_approval",
    ),
)

注意: attachments 使用時はトップレベルの blocks パラメータではなく attachments[].blocks にブロックを渡す。両方指定するとブロックが二重表示される。

section.fields による 2 列レイアウト

メタデータ表示(承認者・時刻等)は section.fields で 2 列キーバリュー配置にすると見やすくなる。

{
  "type": "section",
  "fields": [
    { "type": "mrkdwn", "text": "*承認者*\n<@U12345>" },
    { "type": "mrkdwn", "text": "*時刻*\n14:33:12" },
    { "type": "mrkdwn", "text": "*バージョン*\nv1" },
    { "type": "mrkdwn", "text": "*タスクID*\n`01JSGX...`" }
  ]
}

制約: fields は最大 10 項目、各項目最大 2000 文字。

2.5 Action ID 一覧

action_id 用途 value
approve_prompt Prompt 承認 prompt_id
reject_prompt Prompt 却下 → モーダル表示 prompt_id
approve_process Process 承認 process_id
reject_process Process 却下 → モーダル表示 process_id
cancel_execution 実行中止 execution_id
retry_execution 失敗時再実行 execution_id

3. Card #1: Task カード

3.1 状態: generating

投稿直後。L1 で Task を分析中。color: #f2c744(黄)

{
  "attachments": [{
    "color": "#f2c744",
    "blocks": [
      {
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": "受け付けました。タスクを分析中..."
        }
      }
    ]
  }]
}

関数: build_task_card_generating()

3.2 状態: complete

L1 完了。Task 情報で更新。color: #36a64f(緑)

{
  "attachments": [{
    "color": "#36a64f",
    "blocks": [
      {
        "type": "header",
        "text": { "type": "plain_text", "text": "{title}", "emoji": true }
      },
      { "type": "divider" },
      {
        "type": "section",
        "text": { "type": "mrkdwn", "text": "*説明*\n{description}" }
      },
      {
        "type": "section",
        "fields": [
          { "type": "mrkdwn", "text": "*優先度*\n{priority_emoji} {priority_label}" },
          { "type": "mrkdwn", "text": "*種別*\n{task_type}" }
        ]
      },
      { "type": "divider" },
      {
        "type": "context",
        "elements": [
          { "type": "mrkdwn", "text": "*タスクID:* `{task_id}`" }
        ]
      }
    ]
  }]
}

関数: build_task_card_complete(title, description, priority, task_type, task_id)


4. Card #2: Prompt カード

4.1 状態: generating

L2 で方針を生成中。

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "📝 実行方針", "emoji": true }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "実行方針を生成中..." }
  }
]

関数: build_prompt_card_generating()

4.2 状態: pending_approval

承認待ち。承認 / 却下ボタンを表示。color: #2196f3(青)

{
  "attachments": [{
    "color": "#2196f3",
    "blocks": [
      {
        "type": "header",
        "text": { "type": "plain_text", "text": "📝 実行方針", "emoji": true }
      },
      {
        "type": "section",
        "text": { "type": "mrkdwn", "text": "{prompt_content (truncated)}" }
      },
      { "type": "divider" },
      {
        "type": "actions",
        "elements": [
          {
            "type": "button",
            "text": { "type": "plain_text", "text": "✅ 承認", "emoji": true },
            "action_id": "approve_prompt",
            "value": "{prompt_id}",
            "style": "primary"
          },
          {
            "type": "button",
            "text": { "type": "plain_text", "text": "❌ 却下", "emoji": true },
            "action_id": "reject_prompt",
            "value": "{prompt_id}",
            "style": "danger"
          }
        ]
      },
      {
        "type": "context",
        "elements": [
          { "type": "mrkdwn", "text": "*タスクID:* `{task_id}` · *バージョン:* v{version}" }
        ]
      }
    ]
  }]
}

関数: build_prompt_card_pending(prompt_content, task_id, prompt_id, version)

4.3 状態: approved

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "📝 実行方針(承認済み)", "emoji": true }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "{prompt_content (truncated)}" }
  },
  { "type": "divider" },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "✅ 承認: <@{approved_by}> · {approved_at}" }
    ]
  }
]

関数: build_prompt_card_approved(prompt_content, approved_by, approved_at)

4.4 状態: rejected (→ 再生成あり)

却下されたカード。再生成版がある場合は「再生成済み」と表示。

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "📝 実行方針(却下 → 再生成済み)", "emoji": true }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "{prompt_content (truncated)}" }
  },
  { "type": "divider" },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "❌ 却下: <@{rejected_by}> · 理由: {rejection_reason}" },
      { "type": "mrkdwn", "text": "➡️ 新しいバージョン v{next_version} が生成されました" }
    ]
  }
]

関数: build_prompt_card_rejected(prompt_content, rejected_by, rejection_reason, next_version)

4.5 状態: rejected (→ 再生成なし、タスクキャンセル)

将来: 再生成上限に達した場合などのフォールバック。

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "📝 実行方針(キャンセル)", "emoji": true }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "タスクをキャンセルしました" }
  }
]

5. Card #3: Process カード

5.1 状態: generating

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "⚙️ 実行ステップ", "emoji": true }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "実行ステップを生成中..." }
  }
]

関数: build_process_card_generating()

5.2 状態: pending_approval

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "⚙️ 実行ステップ", "emoji": true }
  },
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "1. *従業員一覧を取得* — `list_employees`\n2. *勤怠データ取得* — `list_attendance`\n3. *残業時間計算* — `calculate_overtime`\n4. *Sheet 書き込み* — `write_rows_to_google_sheet`\n5. *完了通知* — `send_slack_dm`"
    }
  },
  { "type": "divider" },
  {
    "type": "actions",
    "elements": [
      {
        "type": "button",
        "text": { "type": "plain_text", "text": "✅ 承認", "emoji": true },
        "action_id": "approve_process",
        "value": "{process_id}",
        "style": "primary"
      },
      {
        "type": "button",
        "text": { "type": "plain_text", "text": "❌ 却下", "emoji": true },
        "action_id": "reject_process",
        "value": "{process_id}",
        "style": "danger"
      }
    ]
  },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "*タスクID:* `{task_id}` · *バージョン:* v{version}" }
    ]
  }
]

ステップテキスト生成関数: _format_steps_text(steps)

def _format_steps_text(steps: list[dict]) -> str:
    lines: list[str] = []
    for s in steps:
        order = s.get("order", "?")
        title = s.get("title", "")
        tool = s.get("tool", "")
        human = " 🔍" if s.get("requiresHumanCheck") else ""
        lines.append(f"{order}. *{title}* — `{tool}`{human}")
    return "\n".join(lines)

関数: build_process_card_pending(steps, task_id, process_id, version)

5.3 状態: approved

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "⚙️ 実行ステップ(承認済み)", "emoji": true }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "{steps_text}" }
  },
  { "type": "divider" },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "✅ 承認: <@{approved_by}> · {approved_at}" }
    ]
  }
]

関数: build_process_card_approved(steps, approved_by, approved_at)

5.4 状態: rejected (→ 再生成あり)

Prompt カードの rejected と同じパターン。

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "⚙️ 実行ステップ(却下 → 再生成済み)", "emoji": true }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "{steps_text}" }
  },
  { "type": "divider" },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "❌ 却下: <@{rejected_by}> · 理由: {rejection_reason}" },
      { "type": "mrkdwn", "text": "➡️ 新しいバージョン v{next_version} が生成されました" }
    ]
  }
]

関数: build_process_card_rejected(steps, rejected_by, rejection_reason, next_version)


6. Card #4: Execution カード

6.1 状態: running

進捗更新ごとに chat.update。[中止] ボタンを常時表示。color: #1264a3(紺)

MVP 実装では、Execution カードの更新タイミングは L4 セッション開始時と完了・失敗・中止時に限定される。ツール呼び出しごとの逐次更新(on_progress 経由の chat.update)は Post-MVP(docs/post-mvp-roadmap.md §4.8)。下記ブロックはサンプルだが、MVP では completed_tools / current_tool がすべて空の状態で表示される。

{
  "attachments": [{
    "color": "#1264a3",
    "blocks": [
      {
        "type": "header",
        "text": { "type": "plain_text", "text": "🚀 実行中", "emoji": true }
      },
      {
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": "✅ 1. *従業員一覧を取得* — `list_employees`\n🔄 2. *勤怠データ取得* — `list_attendance` 実行中...\n⬜ 3. *残業時間計算* — `calculate_overtime`\n⬜ 4. *Sheet 書き込み* — `write_rows_to_google_sheet`\n⬜ 5. *完了通知* — `send_slack_dm`"
        }
      },
      { "type": "divider" },
      {
        "type": "context",
        "elements": [
          { "type": "mrkdwn", "text": "進捗: 1/5 完了" }
        ]
      },
      {
        "type": "actions",
        "elements": [
          {
            "type": "button",
            "text": { "type": "plain_text", "text": "⏹️ 中止", "emoji": true },
            "action_id": "cancel_execution",
            "value": "{execution_id}",
            "style": "danger",
            "confirm": {
              "title": { "type": "plain_text", "text": "実行を中止しますか?" },
              "text": { "type": "plain_text", "text": "中止すると元に戻せません。新しいタスクとして再依頼が必要です。" },
              "confirm": { "type": "plain_text", "text": "中止する" },
              "deny": { "type": "plain_text", "text": "キャンセル" }
            }
          }
        ]
      }
    ]
  }]
}

ステップ進捗テキスト生成関数: _build_step_lines(steps, completed_tools, current_tool)

def _build_step_lines(
    steps: list[dict],
    completed_tools: list[str] | None = None,
    current_tool: str | None = None,
    failed_tool: str | None = None,
) -> str:
    completed = set(completed_tools or [])
    lines: list[str] = []
    for s in steps:
        tool = s.get("tool", "")
        title = s.get("title", "")
        order = s.get("order", "?")
        if tool == failed_tool:
            lines.append(f"❌ {order}. *{title}* — `{tool}`")
        elif tool == current_tool:
            lines.append(f"🔄 {order}. *{title}* — `{tool}` 実行中...")
        elif tool in completed:
            lines.append(f"✅ {order}. *{title}* — `{tool}`")
        else:
            lines.append(f"⬜ {order}. *{title}* — `{tool}`")
    return "\n".join(lines)

関数: build_execution_card_running(steps, current_tool, completed_tools, execution_id)

6.2 状態: completed

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "✅ 実行完了", "emoji": true }
  },
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "✅ 1. *従業員一覧を取得* — `list_employees`\n✅ 2. *勤怠データ取得* — `list_attendance`\n✅ 3. *残業時間計算* — `calculate_overtime`\n✅ 4. *Sheet 書き込み* — `write_rows_to_google_sheet`\n✅ 5. *完了通知* — `send_slack_dm`"
    }
  },
  { "type": "divider" },
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "*サマリー*\n{summary}"
    }
  },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "⏱️ 実行時間: {elapsed}秒 · 完了: {completed_at}" }
    ]
  }
]

関数: build_execution_card_completed(steps, completed_tools, summary, elapsed, completed_at)

6.3 状態: failed

[再実行] ボタンを表示。

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "❌ 実行失敗", "emoji": true }
  },
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "✅ 1. *従業員一覧を取得* — `list_employees`\n✅ 2. *勤怠データ取得* — `list_attendance`\n❌ 3. *残業時間計算* — `calculate_overtime`\n⬜ 4. *Sheet 書き込み* — `write_rows_to_google_sheet`\n⬜ 5. *完了通知* — `send_slack_dm`"
    }
  },
  { "type": "divider" },
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "*エラー*\n{error_message}"
    }
  },
  {
    "type": "actions",
    "elements": [
      {
        "type": "button",
        "text": { "type": "plain_text", "text": "🔄 再実行", "emoji": true },
        "action_id": "retry_execution",
        "value": "{execution_id}",
        "style": "primary"
      }
    ]
  },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "⏱️ 実行時間: {elapsed}秒 · 失敗: {failed_at}" }
    ]
  }
]

関数: build_execution_card_failed(steps, completed_tools, failed_tool, error, execution_id, elapsed, failed_at)

6.4 状態: cancelled

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "⏹️ 実行中止", "emoji": true }
  },
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "✅ 1. *従業員一覧を取得* — `list_employees`\n✅ 2. *勤怠データ取得* — `list_attendance`\n⬜ 3. *残業時間計算* — `calculate_overtime`\n⬜ 4. *Sheet 書き込み* — `write_rows_to_google_sheet`\n⬜ 5. *完了通知* — `send_slack_dm`"
    }
  },
  { "type": "divider" },
  {
    "type": "context",
    "elements": [
      { "type": "mrkdwn", "text": "⏹️ <@{cancelled_by}> により中止されました · {cancelled_at}" }
    ]
  }
]

関数: build_execution_card_cancelled(steps, completed_tools, cancelled_by, cancelled_at)


7. 却下理由モーダル

Prompt / Process の [却下] ボタン押下時に views.open で表示するモーダル。

7.1 モーダル定義

{
  "type": "modal",
  "callback_id": "rejection_reason_modal",
  "title": {
    "type": "plain_text",
    "text": "却下理由"
  },
  "submit": {
    "type": "plain_text",
    "text": "送信して再生成"
  },
  "close": {
    "type": "plain_text",
    "text": "キャンセル"
  },
  "private_metadata": "{\"type\": \"prompt|process\", \"id\": \"{resource_id}\", \"task_id\": \"{task_id}\"}",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "却下理由を入力してください。この内容を反映して新しいバージョンを生成します。"
      }
    },
    {
      "type": "input",
      "block_id": "rejection_reason_block",
      "element": {
        "type": "plain_text_input",
        "action_id": "rejection_reason_input",
        "multiline": true,
        "placeholder": {
          "type": "plain_text",
          "text": "例: ステップ 3 の前にデータの検証を追加してください"
        }
      },
      "label": {
        "type": "plain_text",
        "text": "却下理由"
      }
    }
  ]
}

7.2 モーダル処理フロー

  1. [却下] ボタン押下 → trigger_id を受け取る
  2. views.open(trigger_id, view) でモーダル表示
  3. ユーザーが理由を入力して [送信して再生成] を押下
  4. view_submission イベントで callback_id: rejection_reason_modal を受信
  5. private_metadata から typeid を取得
  6. rejection_reason を DB に保存
  7. 既存カードを「却下 → 再生成済み」状態に chat.update
  8. 新しいバージョンの Prompt/Process を生成
  9. 新しいカードを投稿

7.3 View Submission ハンドラ

@app.view("rejection_reason_modal")
def handle_rejection_modal(ack, view, client):
    ack()
    metadata = json.loads(view["private_metadata"])
    reason = view["state"]["values"]["rejection_reason_block"]["rejection_reason_input"]["value"]
    resource_type = metadata["type"]   # "prompt" or "process"
    resource_id = metadata["id"]
    task_id = metadata["task_id"]
    # → 再生成フローを開始

8. Agent Container サジェストプロンプト(Post-MVP)

MVP では Agent Container を実装しない。本節は Post-MVP 実装時のサジェストプロンプト仕様メモ。Agent Container 自体の詳細は docs/post-mvp-roadmap.md §4.6 を参照。

Agent Container を開いた時に表示するサジェストプロンプト。

suggested_prompts = [
    {
        "title": "勤怠集計",
        "message": "今月の勤怠をまとめて"
    },
    {
        "title": "残業確認",
        "message": "先月の残業時間を確認して"
    },
    {
        "title": "従業員一覧",
        "message": "従業員一覧を取得して"
    }
]

8.1 threadStarted ハンドラ

async def thread_started(say, set_suggested_prompts):
    await say(text="HR AI Agent です。業務を依頼してください。")
    await set_suggested_prompts(prompts=suggested_prompts)

9. Slack API 呼び出しパターン

9.1 カード投稿 → ts 取得

blocks = build_prompt_card_generating()
payload = wrap_in_attachment(blocks, "generating")
result = await client.chat_postMessage(
    channel=channel,
    thread_ts=thread_ts,
    text="実行方針を生成中...",  # fallback
    **payload,
)
message_ts = result["ts"]
# → slack_messages テーブルに保存

9.2 カード更新

blocks = build_prompt_card_pending(prompt_content, task_id, prompt_id, version)
payload = wrap_in_attachment(blocks, "pending_approval")
await client.chat_update(
    channel=channel,
    ts=message_ts,  # slack_messages から取得
    text="実行方針の確認をお願いします",  # fallback
    **payload,
)

9.3 モーダル表示

await client.views_open(
    trigger_id=body["trigger_id"],
    view=build_rejection_modal(resource_type, resource_id, task_id),
)

9.4 Rate Limit

API Tier Rate
chat.postMessage Tier 4 100+/min
chat.update Tier 3 50+/min
views.open Tier 4 100+/min
views.publish Tier 4 100+/min

L4 実行中の進捗更新は POLL_INTERVAL_SECONDS=3(20 回/min)で Tier 3 の制限内。


10. 関数一覧

関数名 引数 返り値 用途
build_task_card_generating() なし list[dict] Task 分析中
build_task_card_complete(title, description, priority, task_type, task_id) 5 list[dict] Task 分析完了
build_prompt_card_generating() なし list[dict] Prompt 生成中
build_prompt_card_pending(prompt_content, task_id, prompt_id, version) 4 list[dict] Prompt 承認待ち
build_prompt_card_approved(prompt_content, approved_by, approved_at) 3 list[dict] Prompt 承認済み
build_prompt_card_rejected(prompt_content, rejected_by, rejection_reason, next_version) 4 list[dict] Prompt 却下 → 再生成
build_process_card_generating() なし list[dict] Process 生成中
build_process_card_pending(steps, task_id, process_id, version) 4 list[dict] Process 承認待ち
build_process_card_approved(steps, approved_by, approved_at) 3 list[dict] Process 承認済み
build_process_card_rejected(steps, rejected_by, rejection_reason, next_version) 4 list[dict] Process 却下 → 再生成
build_execution_card_running(steps, current_tool, completed_tools, execution_id) 4 list[dict] Execution 実行中
build_execution_card_completed(steps, completed_tools, summary, elapsed, completed_at) 5 list[dict] Execution 完了
build_execution_card_failed(steps, completed_tools, failed_tool, error, execution_id, elapsed, failed_at) 7 list[dict] Execution 失敗
build_execution_card_cancelled(steps, completed_tools, cancelled_by, cancelled_at) 4 list[dict] Execution 中止
build_rejection_modal(resource_type, resource_id, task_id) 3 dict 却下理由モーダル
wrap_in_attachment(blocks, status) 2 dict ブロックを色付き attachment でラップ

11. プロトタイプからの差分

項目 プロトタイプ (cards.py) 本仕様
Prompt 却下 タスクキャンセルのみ 理由モーダル → 再生成
Process 却下 タスクキャンセルのみ 理由モーダル → 再生成
Execution 中止 なし [中止] ボタン + 確認ダイアログ
Execution 再実行 なし [再実行] ボタン
バージョン表示 なし Prompt/Process カードに v{N} 表示
承認時刻 なし Context に表示
実行時間 なし Execution 完了/失敗カードに表示
中止ボタン確認 - confirm オブジェクトで誤操作防止
失敗ステップ表示 全て ⬜ のまま ❌ マーク + failed_tool 識別
状態カラーバー なし attachment color で状態色表示(黄/青/緑/赤/紺/グレー)
メタデータ 2 列表示 context のみ section.fields で 2 列キーバリュー

変更履歴

日付 バージョン 変更内容
2026-04-18 v1.0 初版作成
2026-04-18 v1.1 attachment color による状態カラーバー、section.fields による 2 列レイアウト追加
2026-04-20 v1.2 Agent Container サジェストプロンプト節を Post-MVP スコープに移動(MVP はチャンネルメンションのみ)