chore(i18n): refresh ko translations

This commit is contained in:
openclaw-docs-i18n[bot] 2026-05-04 07:06:14 +00:00
parent dfd84aba5a
commit 5cb65bba36
7 changed files with 1995 additions and 1742 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,24 +4,24 @@ read_when:
summary: Slack 설정 및 런타임 동작(Socket Mode + HTTP 요청 URL)
title: Slack
x-i18n:
generated_at: "2026-05-04T02:22:03Z"
generated_at: "2026-05-04T07:02:41Z"
model: gpt-5.5
provider: openai
source_hash: 2be45f03511a64373b1f4316c59800eeeef8baccb4c00454b49999258b2e546b
source_hash: d4a91fc1ae5f1e03f714308be54e164ef204809e74efabed8dc75c3035c14228
source_path: channels/slack.md
workflow: 16
---
DM 및 채널에서 Slack 앱 통합을 통해 프로덕션 준비 완료 상태로 사용할 수 있습니다. 기본 모드는 Socket Mode이며, HTTP Request URLs도 지원됩니다.
Slack 앱 통합을 통해 DM 및 채널에서 프로덕션 준비 상태로 사용할 수 있습니다. 기본 모드는 Socket Mode이며, HTTP Request URLs도 지원됩니다.
<CardGroup cols={3}>
<Card title="페어링" icon="link" href="/ko/channels/pairing">
<Card title="Pairing" icon="link" href="/ko/channels/pairing">
Slack DM은 기본적으로 페어링 모드를 사용합니다.
</Card>
<Card title="슬래시 명령어" icon="terminal" href="/ko/tools/slash-commands">
네이티브 명령 동작 및 명령 카탈로그입니다.
<Card title="Slash commands" icon="terminal" href="/ko/tools/slash-commands">
네이티브 명령 동작 및 명령 카탈로그입니다.
</Card>
<Card title="채널 문제 해결" icon="wrench" href="/ko/channels/troubleshooting">
<Card title="Channel troubleshooting" icon="wrench" href="/ko/channels/troubleshooting">
채널 간 진단 및 복구 플레이북입니다.
</Card>
</CardGroup>
@ -29,19 +29,19 @@ DM 및 채널에서 Slack 앱 통합을 통해 프로덕션 준비 완료 상태
## 빠른 설정
<Tabs>
<Tab title="Socket Mode (기본값)">
<Tab title="Socket Mode (default)">
<Steps>
<Step title="새 Slack 앱 만들기">
<Step title="Create a new Slack app">
Slack 앱 설정에서 **[Create New App](https://api.slack.com/apps/new)** 버튼을 누릅니다.
- **from a manifest**를 선택하고 앱의 워크스페이스를 선택합니다.
- 아래의 [시 매니페스트](#manifest-and-scope-checklist)를 붙여넣고 계속 진행하여 만듭니다.
- `connections:write`있는 **App-Level Token**(`xapp-...`)을 생성합니다.
- 앱을 설치하고 표시되는 **Bot Token**(`xoxb-...`)을 복사합니다.
- **from a manifest**를 선택하고 앱용 워크스페이스를 선택합니다
- 아래의 [제 매니페스트](#manifest-and-scope-checklist)를 붙여넣고 생성을 계속합니다
- `connections:write`포함된 **App-Level Token**(`xapp-...`)을 생성합니다
- 앱을 설치하고 표시 **Bot Token**(`xoxb-...`)을 복사합니다
</Step>
<Step title="OpenClaw 구성하기">
<Step title="Configure OpenClaw">
권장 SecretRef 설정:
@ -73,7 +73,7 @@ SLACK_BOT_TOKEN=xoxb-...
</Step>
<Step title="Gateway 시작하기">
<Step title="Start gateway">
```bash
openclaw gateway
@ -86,17 +86,17 @@ openclaw gateway
<Tab title="HTTP Request URLs">
<Steps>
<Step title="새 Slack 앱 만들기">
<Step title="Create a new Slack app">
Slack 앱 설정에서 **[Create New App](https://api.slack.com/apps/new)** 버튼을 누릅니다.
- **from a manifest**를 선택하고 앱의 워크스페이스를 선택합니다.
- [시 매니페스트](#manifest-and-scope-checklist)를 붙여넣고 만들기 전에 URL을 업데이트합니다.
- 요청 검증을 위해 **Signing Secret**을 저장합니다.
- 앱을 설치하고 표시되는 **Bot Token**(`xoxb-...`)을 복사합니다.
- **from a manifest**를 선택하고 앱용 워크스페이스를 선택합니다
- [제 매니페스트](#manifest-and-scope-checklist)를 붙여넣고 생성 전에 URL을 업데이트합니다
- 요청 검증을 위해 **Signing Secret**을 저장합니다
- 앱을 설치하고 표시 **Bot Token**(`xoxb-...`)을 복사합니다
</Step>
<Step title="OpenClaw 구성하기">
<Step title="Configure OpenClaw">
권장 SecretRef 설정:
@ -121,14 +121,14 @@ openclaw config patch --file ./slack.http.patch.json5
```
<Note>
다중 계정 HTTP에는 고유한 webhook 경로를 사용하세요.
다중 계정 HTTP에는 고유한 webhook 경로를 사용하세요
등록이 충돌하지 않도록 각 계정에 별도의 `webhookPath`(기본값 `/slack/events`)를 지정하세요.
등록이 충돌하지 않도록 각 계정에 고유한 `webhookPath`(기본값 `/slack/events`)를 지정하세요.
</Note>
</Step>
<Step title="Gateway 시작하기">
<Step title="Start gateway">
```bash
openclaw gateway
@ -142,7 +142,7 @@ openclaw gateway
## Socket Mode 전송 튜닝
OpenClaw는 Socket Mode에 대해 Slack SDK 클라이언트 pong 제한 시간을 기본적으로 15초로 설정합니다. 워크스페이스 또는 호스트별 튜닝이 필요한 경우에만 전송 설정을 재정의하세요.
OpenClaw는 Socket Mode에서 Slack SDK 클라이언트 pong 타임아웃을 기본적으로 15초로 설정합니다. 워크스페이스 또는 호스트별 튜닝이 필요할 때만 전송 설정을 재정의하세요.
```json5
{
@ -159,11 +159,11 @@ OpenClaw는 Socket Mode에 대해 Slack SDK 클라이언트 pong 제한 시간
}
```
Slack websocket pong/server-ping 제한 시간이 로그에 기록되는 Socket Mode 워크스페이스 또는 이벤트 루프 고갈이 알려진 호스트에서만 이 설정을 사용하세요. `clientPingTimeout`은 SDK가 클라이언트 ping을 보낸 후 pong을 기다리는 시간이고, `serverPingTimeout`은 Slack 서버 ping을 기다리는 시간입니다. 앱 메시지와 이벤트는 전송 활성 신호가 아니라 애플리케이션 상태로 유지됩니다.
Slack websocket pong/server-ping 타임아웃을 기록하는 Socket Mode 워크스페이스 또는 이벤트 루프 고갈이 알려진 호스트에서 실행되는 경우에만 이것을 사용하세요. `clientPingTimeout`은 SDK가 클라이언트 ping을 보낸 뒤 pong을 기다리는 시간이고, `serverPingTimeout`은 Slack 서버 ping을 기다리는 시간입니다. 앱 메시지와 이벤트는 전송 활성 신호가 아니라 애플리케이션 상태로 유지됩니다.
## 매니페스트 및 범위 체크리스트
## 매니페스트 및 scope 체크리스트
기본 Slack 앱 매니페스트는 Socket Mode와 HTTP Request URLs에서 동일합니다. `settings` 블록(및 슬래시 명령어 `url`)만 다릅니다.
기본 Slack 앱 매니페스트는 Socket Mode와 HTTP Request URLs에서 동일합니다. `settings` 블록(및 slash command `url`)만 다릅니다.
기본 매니페스트(Socket Mode 기본값):
@ -240,7 +240,7 @@ Slack websocket pong/server-ping 제한 시간이 로그에 기록되는 Socket
}
```
**HTTP Request URLs 모드**의 경우 `settings`를 HTTP 변형으로 바꾸고 각 슬래시 명령어`url`을 추가합니다. 공개 URL이 필요합니다.
**HTTP Request URLs 모드**의 경우 `settings`를 HTTP 변형으로 교체하고 각 slash command`url`을 추가합니다. 공개 URL이 필요합니다.
```json
{
@ -286,20 +286,20 @@ Slack websocket pong/server-ping 제한 시간이 로그에 기록되는 Socket
위 기본값을 확장하는 다양한 기능을 노출합니다.
기본 매니페스트는 Slack App Home **Home** 탭을 활성화하고 `app_home_opened`를 구독합니다. 워크스페이스 멤버가 Home 탭을 열면 OpenClaw는 `views.publish`로 안전한 기본 Home 보기를 게시합니다. 대화 페이로드나 비공개 구성은 포함되지 않습니다. Slack DM을 위해 **Messages** 탭은 계속 활성화되어 있습니다.
기본 매니페스트는 Slack App Home **Home** 탭을 활성화하고 `app_home_opened`를 구독합니다. 워크스페이스 멤버가 Home 탭을 열면 OpenClaw는 `views.publish`로 안전한 기본 Home 보기를 게시합니다. 대화 페이로드나 비공개 구성은 포함되지 않습니다. **Messages** 탭은 Slack DM용으로 계속 활성화됩니다.
<AccordionGroup>
<Accordion title="선택적 네이티브 슬래시 명령어">
<Accordion title="Optional native slash commands">
단일 구성 명령어 대신 여러 [네이티브 슬래시 명령어](#commands-and-slash-behavior)를 세부적으로 사용할 수 있습니다.
여러 [네이티브 slash command](#commands-and-slash-behavior)를 미묘한 차이가 있는 단일 구성 명령 대신 사용할 수 있습니다.
- `/status` 명령어는 예약되어 있으므로 `/status` 대신 `/agentstatus`를 사용하세요.
- 한 번에 25개를 초과하는 슬래시 명령어를 사용할 수 없습니다.
- `/status` 명령 예약되어 있으므로 `/status` 대신 `/agentstatus`를 사용하세요.
- 한 번에 25개를 초과하는 slash command를 사용할 수는 없습니다.
기존 `features.slash_commands` 섹션을 [사용 가능한 명령](/ko/tools/slash-commands#command-list)의 일부로 바꾸세요.
기존 `features.slash_commands` 섹션을 [사용 가능한 명령](/ko/tools/slash-commands#command-list)의 하위 집합으로 교체하세요.
<Tabs>
<Tab title="Socket Mode (기본값)">
<Tab title="Socket Mode (default)">
```json
{
@ -423,7 +423,7 @@ Slack websocket pong/server-ping 제한 시간이 로그에 기록되는 Socket
</Tab>
<Tab title="HTTP Request URLs">
위 Socket Mode와 동일한 `slash_commands` 목록을 사용하고, 모든 항목에 `"url": "https://gateway-host.example.com/slack/events"`를 추가하세요. 예:
위 Socket Mode와 동일한 `slash_commands` 목록을 사용하고 모든 항목에 `"url": "https://gateway-host.example.com/slack/events"`를 추가하세요. 예:
```json
{
@ -443,14 +443,14 @@ Slack websocket pong/server-ping 제한 시간이 로그에 기록되는 Socket
}
```
목록의 모든 명령어에서 해당 `url` 값을 반복하세요.
목록의 모든 명령에 해당 `url` 값을 반복해서 넣으세요.
</Tab>
</Tabs>
</Accordion>
<Accordion title="선택적 작성자 범위(쓰기 작업)">
발신 메시지 기본 Slack 앱 ID 대신 활성 에이전트 ID(사용자 지정 사용자 이름 및 아이콘)를 사용하게 하려면 `chat:write.customize` 봇 범위를 추가하세요.
<Accordion title="선택적 작성자 표시 범위(쓰기 작업)">
발신 메시지에서 기본 Slack 앱 ID 대신 활성 에이전트 ID(사용자 지정 사용자 이름 및 아이콘)를 사용하려면 `chat:write.customize` 봇 범위를 추가하세요.
이모지 아이콘을 사용하는 경우 Slack은 `:emoji_name:` 구문을 기대합니다.
@ -475,22 +475,22 @@ Slack websocket pong/server-ping 제한 시간이 로그에 기록되는 Socket
- HTTP 모드에는 `botToken` + `signingSecret`이 필요합니다.
- `botToken`, `appToken`, `signingSecret`, `userToken`은 일반 텍스트
문자열 또는 SecretRef 객체를 허용합니다.
- 구성 토큰은 env fallback을 재정의합니다.
- `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` env fallback은 기본 계정에만 적용됩니다.
- `userToken`(`xoxp-...`)은 구성 전용(env fallback 없음)이며 기본값은 읽기 전용 동작(`userTokenReadOnly: true`)입니다.
- 구성 토큰은 env 폴백을 재정의합니다.
- `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` env 폴백은 기본 계정에만 적용됩니다.
- `userToken`(`xoxp-...`)은 구성 전용(env 폴백 없음)이며 기본값은 읽기 전용 동작(`userTokenReadOnly: true`)입니다.
상태 스냅샷 동작:
- Slack 계정 검사는 자격 증명별 `*Source``*Status`
필드(`botToken`, `appToken`, `signingSecret`, `userToken`)를 추적합니다.
- 상태는 `available`, `configured_unavailable`, `missing` 중 하나입니다.
- `configured_unavailable`은 계정이 SecretRef 또는 다른 비인라인 시크릿 소스를 통해
구성되었지만, 현재 명령/런타임 경로에서 실제 값을 확인할 수 없었음을 의미합니다.
- HTTP 모드에서는 `signingSecretStatus`가 포함되, Socket Mode에서는
- 상태는 `available`, `configured_unavailable` 또는 `missing`입니다.
- `configured_unavailable`은 계정이 SecretRef 또는 다른 비인라인 비밀 소스를 통해
구성되어 있지만, 현재 명령/런타임 경로에서 실제 값을 확인할 수 없다는 뜻입니다.
- HTTP 모드에서는 `signingSecretStatus`가 포함되, Socket Mode에서는
필요한 쌍이 `botTokenStatus` + `appTokenStatus`입니다.
<Tip>
작업/디렉터리 읽기에는 구성된 경우 사용자 토큰이 선호될 수 있습니다. 쓰기에는 봇 토큰이 계속 선호됩니다. 사용자 토큰 쓰기는 `userTokenReadOnly: false`이고 봇 토큰을 사용할 수 없을 때만 허용됩니다.
작업/디렉터리 읽기의 경우 구성되어 있으면 사용자 토큰이 우선될 수 있습니다. 쓰기의 경우 봇 토큰이 계속 우선됩니다. 사용자 토큰 쓰기는 `userTokenReadOnly: false`이고 봇 토큰을 사용할 수 없을 때만 허용됩니다.
</Tip>
## 작업 및 게이트
@ -501,13 +501,13 @@ Slack 작업은 `channels.slack.actions.*`로 제어됩니다.
| 그룹 | 기본값 |
| ---------- | ------- |
| messages | 활성화됨 |
| reactions | 활성화됨 |
| pins | 활성화됨 |
| memberInfo | 활성화됨 |
| emojiList | 활성화됨 |
| 메시지 | 활성화됨 |
| 반응 | 활성화됨 |
| | 활성화됨 |
| 멤버 정보 | 활성화됨 |
| 이모지 목록 | 활성화됨 |
현재 Slack 메시지 작업에는 `send`, `upload-file`, `download-file`, `read`, `edit`, `delete`, `pin`, `unpin`, `list-pins`, `member-info`, `emoji-list`가 포함됩니다. `download-file`인바운드 파일 플레이스홀더에 표시된 Slack 파일 ID를 허용하며, 이미지의 경우 이미지 미리 보기를, 다른 파일 형식의 경우 로컬 파일 메타데이터를 반환합니다.
현재 Slack 메시지 작업에는 `send`, `upload-file`, `download-file`, `read`, `edit`, `delete`, `pin`, `unpin`, `list-pins`, `member-info`, `emoji-list`가 포함됩니다. `download-file`수신 파일 자리 표시자에 표시된 Slack 파일 ID를 허용하고, 이미지의 경우 이미지 미리 보기를 반환하며 다른 파일 형식의 경우 로컬 파일 메타데이터를 반환합니다.
## 접근 제어 및 라우팅
@ -517,7 +517,7 @@ Slack 작업은 `channels.slack.actions.*`로 제어됩니다.
- `pairing`(기본값)
- `allowlist`
- `open`(`channels.slack.allowFrom`에 `"*"`가 포함되어야 함)
- `open`(`channels.slack.allowFrom`에 `"*"`를 포함해야 함)
- `disabled`
DM 플래그:
@ -534,7 +534,7 @@ Slack 작업은 `channels.slack.actions.*`로 제어됩니다.
- 명명된 계정은 자체 `allowFrom`이 설정되지 않은 경우 `channels.slack.allowFrom`을 상속합니다.
- 명명된 계정은 `channels.slack.accounts.default.allowFrom`을 상속하지 않습니다.
레거시 `channels.slack.dm.policy``channels.slack.dm.allowFrom`은 호환성을 위해 계속 읽힙니다. `openclaw doctor --fix`는 접근을 변경하지 않고 가능할 때 이를 `dmPolicy``allowFrom`으로 마이그레이션합니다.
레거시 `channels.slack.dm.policy``channels.slack.dm.allowFrom`은 호환성을 위해 계속 읽습니다. 접근을 변경하지 않고 처리할 수 있으면 `openclaw doctor --fix` 이를 `dmPolicy``allowFrom`으로 마이그레이션합니다.
DM에서의 페어링은 `openclaw pairing approve slack <code>`를 사용합니다.
@ -549,16 +549,16 @@ Slack 작업은 `channels.slack.actions.*`로 제어됩니다.
채널 허용 목록은 `channels.slack.channels` 아래에 있으며 구성 키로 **안정적인 Slack 채널 ID**(예: `C12345678`)를 사용해야 합니다.
런타임 참고: `channels.slack`이 완전히 없으면(env 전용 설정), 런타임은 `groupPolicy="allowlist"`로 fallback하고 경고를 기록합니다(`channels.defaults.groupPolicy`가 설정되어 있더라도).
런타임 참고: `channels.slack`이 완전히 누락된 경우(env 전용 설정), 런타임은 `groupPolicy="allowlist"`로 폴백하고 경고를 기록합니다(`channels.defaults.groupPolicy`가 설정되어 있어도 동일).
이름/ID 확인:
- 채널 허용 목록 항목과 DM 허용 목록 항목은 토큰 접근이 허용할 때 시작 시 확인됩니다
- 확인되지 않은 채널 이름 항목은 구성된 상태로 유지되지만 기본적으로 라우팅에서는 무시됩니다
- 인바운드 권한 부여와 채널 라우팅은 기본적으로 ID 우선입니다. 직접 사용자 이름/슬러그 매칭에는 `channels.slack.dangerouslyAllowNameMatching: true`가 필요합니다
- 채널 허용 목록 항목과 DM 허용 목록 항목은 토큰 접근이 허용될 때 시작 시 확인됩니다.
- 확인되지 않은 채널 이름 항목은 구성된 상태로 유지되지만 기본적으로 라우팅에서는 무시됩니다.
- 수신 권한 부여와 채널 라우팅은 기본적으로 ID 우선입니다. 직접 사용자 이름/슬러그 매칭에는 `channels.slack.dangerouslyAllowNameMatching: true`가 필요합니다.
<Warning>
이름 기반 키(`#channel-name` 또는 `channel-name`)는 `groupPolicy: "allowlist"`에서 일치하지 않습니다. 채널 조회는 기본적으로 ID 우선이므로 이름 기반 키는 절대 성공적으로 라우팅되지 않으며 해당 채널의 모든 메시지 조용히 차단됩니다. 이는 채널 키가 라우팅에 필요하지 않아 이름 기반 키가 작동하는 것처럼 보이는 `groupPolicy: "open"`과 다릅니다.
이름 기반 키(`#channel-name` 또는 `channel-name`)는 `groupPolicy: "allowlist"`에서 일치하지 **않습니다**. 채널 조회는 기본적으로 ID 우선이므로 이름 기반 키는 절대 성공적으로 라우팅되지 않으며 해당 채널의 모든 메시지 조용히 차단됩니다. 이는 채널 키가 라우팅에 필요하지 않아 이름 기반 키가 작동하는 것처럼 보이는 `groupPolicy: "open"`과 다릅니다.
항상 Slack 채널 ID를 키로 사용하세요. 찾는 방법: Slack에서 채널을 마우스 오른쪽 버튼으로 클릭 → **링크 복사** — ID(`C...`)가 URL 끝에 표시됩니다.
@ -601,11 +601,11 @@ Slack 작업은 `channels.slack.actions.*`로 제어됩니다.
멘션 소스:
- 명시적 앱 멘션(`<@botId>`)
- 봇 사용자가 해당 사용자 그룹의 멤버일 때 Slack 사용자 그룹 멘션(`<!subteam^S...>`), `usergroups:read` 필요
- 멘션 정규식 패턴(`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`)
- 암시적 봇 답장 스레드 동작(`thread.requireExplicitMention`이 `true`이면 비활성화됨)
- 봇 사용자가 해당 사용자 그룹의 멤버일 때 Slack 사용자 그룹 멘션(`<!subteam^S...>`); `usergroups:read` 필요
- 멘션 정규식 패턴(`agents.list[].groupChat.mentionPatterns`, 대체 `messages.groupChat.mentionPatterns`)
- 암시적 봇 답글 스레드 동작(`thread.requireExplicitMention`이 `true`일 때 비활성화됨)
채널별 제어(`channels.slack.channels.<id>`, 이름은 시작 시 확인 또는 `dangerouslyAllowNameMatching`을 통해서만 가능):
채널별 제어(`channels.slack.channels.<id>`; 이름은 시작 시 해석 또는 `dangerouslyAllowNameMatching`을 통해서만 사용):
- `requireMention`
- `users`(허용 목록)
@ -613,54 +613,54 @@ Slack 작업은 `channels.slack.actions.*`로 제어됩니다.
- `skills`
- `systemPrompt`
- `tools`, `toolsBySender`
- `toolsBySender` 키 형식: `id:`, `e164:`, `username:`, `name:`, 또는 `"*"` 와일드카드
- `toolsBySender` 키 형식: `id:`, `e164:`, `username:`, `name:` 또는 `"*"` 와일드카드
(레거시 접두사 없는 키는 여전히 `id:`에만 매핑됨)
`allowBots`는 채널과 비공개 채널에 대해 보수적으로 동작합니다. 봇이 작성한 룸 메시지는 보내는 봇이 해당 룸`users` 허용 목록에 명시적으로 나열되어 있거나, `channels.slack.allowFrom`의 명시적 Slack 소유자 ID 중 하나 이상이 현재 멤버일 때만 허용됩니다. 와일드카드와 표시 이름 소유자 항목은 소유자 존재 조건을 충족하지 않습니다. 소유자 존재 여부는 Slack `conversations.members`를 사용합니다. 앱에 룸 유형에 맞는 읽기 범위가 있는지 확인하세요(공개 채널은 `channels:read`, 비공개 채널은 `groups:read`). 멤버 조회가 실패하면 OpenClaw는 봇이 작성한 룸 메시지를 드롭합니다.
`allowBots`는 채널 및 비공개 채널에 대해 보수적으로 동작합니다. 봇이 작성한 방 메시지는 보내는 봇이 해당 방`users` 허용 목록에 명시적으로 나열되어 있거나, `channels.slack.allowFrom`의 명시적 Slack 소유자 ID 중 하나 이상이 현재 멤버일 때만 허용됩니다. 와일드카드와 표시 이름 소유자 항목은 소유자 존재 조건을 충족하지 않습니다. 소유자 존재 여부는 Slack `conversations.members`를 사용합니다. 앱에 방 유형에 맞는 읽기 범위(공개 채널은 `channels:read`, 비공개 채널은 `groups:read`)가 있는지 확인하세요. 멤버 조회에 실패하면 OpenClaw는 봇이 작성한 방 메시지를 폐기합니다.
</Tab>
</Tabs>
## 스레딩, 세션 및 답장 태그
## 스레딩, 세션, 답글 태그
- DM은 `direct`로, 채널은 `channel`로, MPIM은 `group`으로 라우팅됩니다.
- Slack 라우트 바인딩은 원시 피어 ID와 `channel:C12345678`, `user:U12345678`, `<@U12345678>` 같은 Slack 대상 형식을 허용합니다.
- 기본 `session.dmScope=main`에서는 Slack DM이 에이전트 메인 세션으로 병합됩니다.
- 기본 `session.dmScope=main`에서는 Slack DM이 에이전트 메인 세션으로 합쳐집니다.
- 채널 세션: `agent:<agentId>:slack:channel:<channelId>`.
- 스레드 답은 적용 가능한 경우 스레드 세션 접미사(`:thread:<threadTs>`)를 만들 수 있습니다.
- `channels.slack.thread.historyScope` 기본값은 `thread`이고, `thread.inheritParent` 기본값은 `false`입니다.
- `channels.slack.thread.initialHistoryLimit` 새 스레드 세션이 시작될 때 가져올 기존 스레드 메시지 수를 제어합니다(기본값 `20`, 비활성화하려면 `0` 설정).
- `channels.slack.thread.requireExplicitMention`(기본값 `false`): `true`이면 암시적 스레드 멘션을 억제하여 봇이 이미 해당 스레드에 참여했더라도 스레드 안의 명시적 `@bot` 멘션에만 응답합니다. 이것이 없으면 봇이 참여한 스레드의 답장이 `requireMention` 게이트를 우회합니다.
- 스레드 답은 적용 가능한 경우 스레드 세션 접미사(`:thread:<threadTs>`)를 만들 수 있습니다.
- `channels.slack.thread.historyScope` 기본값은 `thread`입니다. `thread.inheritParent` 기본값은 `false`입니다.
- `channels.slack.thread.initialHistoryLimit` 새 스레드 세션이 시작될 때 가져올 기존 스레드 메시지 수를 제어합니다(기본값 `20`; 비활성화하려면 `0`으로 설정).
- `channels.slack.thread.requireExplicitMention`(기본값 `false`): `true`이면 암시적 스레드 멘션을 억제하여, 봇이 이미 스레드에 참여했더라도 스레드 안의 명시적 `@bot` 멘션에만 봇이 응답합니다. 이것이 없으면 봇이 참여한 스레드의 답글은 `requireMention` 게이트를 우회합니다.
스레딩 제어:
스레딩 제어:
- `channels.slack.replyToMode`: `off|first|all|batched`(기본값 `off`)
- `channels.slack.replyToModeByChatType`: `direct|group|channel`별 설정
- 직접 채팅을 위한 레거시 fallback: `channels.slack.dm.replyToMode`
- 직접 채팅용 레거시 대체값: `channels.slack.dm.replyToMode`
수동 답 태그가 지원됩니다.
수동 답 태그가 지원됩니다.
- `[[reply_to_current]]`
- `[[reply_to:<id>]]`
<Note>
`replyToMode="off"`는 명시적 `[[reply_to_*]]` 태그를 포함해 Slack의 **모든** 스레딩을 비활성화합니다. 이는 `"off"` 모드에서도 명시적 태그가 계속 적용되는 Telegram과 다릅니다. Slack 스레드는 채널에서 메시지를 숨기지만 Telegram 답장은 인라인으로 계속 표시됩니다.
`replyToMode="off"`는 명시적 `[[reply_to_*]]` 태그를 포함해 Slack의 **모든** 스레딩을 비활성화합니다. 이는 `"off"` 모드에서도 명시적 태그가 계속 적용되는 Telegram과 다릅니다. Slack 스레드는 채널에서 메시지를 숨기지만, Telegram 답글은 인라인으로 계속 표시됩니다.
</Note>
## 확인 반응
`ackReaction`은 OpenClaw가 인바운드 메시지를 처리하는 동안 확인 이모지를 보냅니다.
확인 순서:
해석 순서:
- `channels.slack.accounts.<accountId>.ackReaction`
- `channels.slack.ackReaction`
- `messages.ackReaction`
- 에이전트 ID 이모지 fallback(`agents.list[].identity.emoji`, 없으면 "👀")
- 에이전트 ID 이모지 대체값(`agents.list[].identity.emoji`, 없으면 "👀")
참고:
- Slack은 shortcode를 기대합니다(예: `"eyes"`).
- Slack은 숏코드를 기대합니다(예: `"eyes"`).
- Slack 계정 또는 전역에서 반응을 비활성화하려면 `""`를 사용하세요.
## 텍스트 스트리밍
@ -669,20 +669,39 @@ Slack 작업은 `channels.slack.actions.*`로 제어됩니다.
- `off`: 실시간 미리 보기 스트리밍을 비활성화합니다.
- `partial`(기본값): 미리 보기 텍스트를 최신 부분 출력으로 교체합니다.
- `block`: 청크 단위 미리 보기 업데이트를 추가합니다.
- `progress`: 생성 중 진행 상태 텍스트를 표시한 다음 최종 텍스트를 보냅니다.
- `streaming.preview.toolProgress`: 초안 미리 보기가 활성 상태일 때 도구/진행 업데이트를 동일한 편집된 미리 보기 메시지로 라우팅합니다(기본값: `true`). 별도의 도구/진행 메시지를 유지하려면 `false`로 설정하세요.
- `block`: 청크 미리 보기 업데이트를 추가합니다.
- `progress`: 생성 중에는 진행 상태 텍스트를 표시한 뒤 최종 텍스트를 보냅니다.
- `streaming.preview.toolProgress`: 초안 미리 보기가 활성화되어 있을 때 도구/진행 업데이트를 같은 편집된 미리 보기 메시지로 라우팅합니다(기본값: `true`). 별도의 도구/진행 메시지를 유지하려면 `false`로 설정하세요.
- `streaming.preview.commandText` / `streaming.progress.commandText`: 원시 명령/실행 텍스트를 숨기면서 간결한 도구 진행 줄을 유지하려면 `status`로 설정합니다(기본값: `raw`).
간결한 진행 줄은 유지하면서 원시 명령/실행 텍스트 숨기기:
```json
{
"channels": {
"slack": {
"streaming": {
"mode": "progress",
"progress": {
"toolProgress": true,
"commandText": "status"
}
}
}
}
}
```
`channels.slack.streaming.nativeTransport``channels.slack.streaming.mode``partial`일 때 Slack 네이티브 텍스트 스트리밍을 제어합니다(기본값: `true`).
- 네이티브 텍스트 스트리밍과 Slack 어시스턴트 스레드 상태가 표시되려면 답장 스레드를 사용할 수 있어야 합니다. 스레드 선택은 계속 `replyToMode`를 따릅니다.
- 채널, 그룹 채팅, 최상위 DM 루트는 네이티브 스트리밍을 사용할 수 없거나 답장 스레드가 없는 경우에도 일반 초안 미리 보기를 사용할 수 있습니다.
- 최상위 Slack DM은 기본적으로 스레드 밖에 유지되므로 Slack의 스레드 스타일 네이티브 스트림/상태 미리 보기를 표시하지 않습니다. 대신 OpenClaw는 DM에 초안 미리 보기를 게시하고 편집합니다.
- 미디어 및 비텍스트 페이로드는 일반 전달로 fallback합니다.
- 미디어/오류 최종 응답은 대기 중인 미리 보기 편집을 취소합니다. 적격 텍스트/블록 최종 응답은 미리 보기를 제자리에서 편집할 수 있을 때만 플러시됩니다.
- 스트리밍이 답장 중간에 실패하면 OpenClaw는 남은 페이로드에 대해 일반 전달로 fallback합니다.
- 네이티브 텍스트 스트리밍과 Slack 어시스턴트 스레드 상태가 표시되려면 답글 스레드가 있어야 합니다. 스레드 선택은 계속 `replyToMode`를 따릅니다.
- 채널, 그룹 채팅, 최상위 DM 루트는 네이티브 스트리밍을 사용할 수 없거나 답글 스레드가 없을 때도 일반 초안 미리 보기를 사용할 수 있습니다.
- 최상위 Slack DM은 기본적으로 스레드 밖에 유지되므로 Slack의 스레드 스타일 네이티브 스트림/상태 미리 보기를 표시하지 않습니다. 대신 OpenClaw DM에 초안 미리 보기를 게시하고 편집합니다.
- 미디어 및 비텍스트 페이로드는 일반 전달로 대체됩니다.
- 미디어/오류 최종 응답은 대기 중인 미리 보기 편집을 취소합니다. 조건에 맞는 텍스트/블록 최종 응답은 미리 보기를 제자리에서 편집할 수 있을 때만 플러시됩니다.
- 스트리밍이 답글 도중 실패하면 OpenClaw는 남은 페이로드에 대해 일반 전달로 대체합니다.
Slack 네이티브 텍스트 스트리밍 대신 초안 미리 보기를 사용합니다.
Slack 네이티브 텍스트 스트리밍 대신 초안 미리 보기 사용:
```json5
{
@ -700,45 +719,45 @@ Slack 네이티브 텍스트 스트리밍 대신 초안 미리 보기를 사용
레거시 키:
- `channels.slack.streamMode`(`replace | status_final | append`)는 `channels.slack.streaming.mode`로 자동 마이그레이션됩니다.
- boolean `channels.slack.streaming``channels.slack.streaming.mode` `channels.slack.streaming.nativeTransport`로 자동 마이그레이션됩니다.
- 불리언 `channels.slack.streaming``channels.slack.streaming.mode` `channels.slack.streaming.nativeTransport`로 자동 마이그레이션됩니다.
- 레거시 `channels.slack.nativeStreaming``channels.slack.streaming.nativeTransport`로 자동 마이그레이션됩니다.
## 입력 중 반응 fallback
## 입력 중 반응 대체 동작
`typingReaction`은 OpenClaw가 답장을 처리하는 동안 인바운드 Slack 메시지에 임시 반응을 추가한 다음 실행이 끝나면 제거합니다. 이는 기본 "is typing..." 상태 표시기를 사용하는 스레드 답 밖에서 가장 유용합니다.
`typingReaction`은 OpenClaw가 응답을 처리하는 동안 수신 Slack 메시지에 임시 반응을 추가한 뒤, 실행이 끝나면 제거합니다. 이는 기본 "입력 중..." 상태 표시기를 사용하는 스레드 답 밖에서 가장 유용합니다.
확인 순서:
해결 순서:
- `channels.slack.accounts.<accountId>.typingReaction`
- `channels.slack.typingReaction`
참고:
- Slack은 코드(예: `"hourglass_flowing_sand"`)를 기대합니다.
- 반응은 최선형으로 처리되며, 답 또는 실패 경로가 완료된 뒤 정리가 자동으로 시도됩니다.
- Slack은 쇼트코드(예: `"hourglass_flowing_sand"`)를 기대합니다.
- 반응은 최선형으로 처리되며, 답 또는 실패 경로가 완료된 뒤 정리가 자동으로 시도됩니다.
## 미디어, 청킹 전달
## 미디어, 청킹, 전달
<AccordionGroup>
<Accordion title="Inbound attachments">
<Accordion title="수신 첨부 파일">
Slack 파일 첨부는 Slack에서 호스팅되는 비공개 URL(토큰 인증 요청 흐름)에서 다운로드되며, 가져오기에 성공하고 크기 제한이 허용되면 미디어 저장소에 기록됩니다. 파일 플레이스홀더에는 Slack `fileId`가 포함되어 에이전트가 `download-file`로 원본 파일을 가져올 수 있습니다.
다운로드에는 제한된 유휴 및 총 시간 제한이 사용됩니다. Slack 파일 검색이 멈추거나 실패하면 OpenClaw는 메시지 처리를 계속하고 파일 플레이스홀더로 대체합니다.
다운로드에는 제한된 유휴 및 전체 시간 제한이 적용됩니다. Slack 파일 검색이 멈추거나 실패하면 OpenClaw는 메시지 처리를 계속하고 파일 플레이스홀더로 폴백합니다.
런타임 인바운드 크기 상한은 `channels.slack.mediaMaxMb`로 재정의하지 않는 한 기본값이 `20MB`입니다.
런타임 수신 크기 상한은 `channels.slack.mediaMaxMb`로 재정의하지 않는 한 기본값이 `20MB`입니다.
</Accordion>
<Accordion title="Outbound text and files">
- 텍스트 청크는 `channels.slack.textChunkLimit`를 사용합니다(기본값 4000).
- `channels.slack.chunkMode="newline"`은 단 우선 분할을 활성화합니다.
- 파일 전송은 Slack 업로드 API를 사용하며 스레드 답(`thread_ts`)을 포함할 수 있습니다.
- 아웃바운드 미디어 상한은 구성된 경우 `channels.slack.mediaMaxMb`를 따르며, 그렇지 않으면 채널 전송은 미디어 파이프라인의 MIME 종류 기본값을 사용합니다.
<Accordion title="송신 텍스트 및 파일">
- 텍스트 청크는 `channels.slack.textChunkLimit`(기본값 4000)을 사용합니다
- `channels.slack.chunkMode="newline"`단 우선 분할을 활성화합니다
- 파일 전송은 Slack 업로드 API를 사용하며 스레드 답(`thread_ts`)을 포함할 수 있습니다
- 송신 미디어 상한은 구성된 경우 `channels.slack.mediaMaxMb`를 따릅니다. 그렇지 않으면 채널 전송은 미디어 파이프라인의 MIME 종류 기본값을 사용합니다
</Accordion>
<Accordion title="Delivery targets">
선호되는 명시적 대상:
<Accordion title="전달 대상">
권장되는 명시적 대상:
- DM에는 `user:<id>`
- 채널에는 `channel:<id>`
@ -750,7 +769,7 @@ Slack 네이티브 텍스트 스트리밍 대신 초안 미리 보기를 사용
## 명령 및 슬래시 동작
슬래시 명령은 Slack에서 단일 구성 명령 또는 여러 네이티브 명령으로 나타납니다. 명령 기본값을 변경하려면 `channels.slack.slashCommand`를 구성하세요.
슬래시 명령은 Slack에서 단일 구성 명령 또는 여러 네이티브 명령으로 표시됩니다. 명령 기본값을 변경하려면 `channels.slack.slashCommand`를 구성하세요.
- `enabled: false`
- `name: "openclaw"`
@ -761,7 +780,7 @@ Slack 네이티브 텍스트 스트리밍 대신 초안 미리 보기를 사용
/openclaw /help
```
네이티브 명령은 Slack 앱에 [추가 매니페스트 설정](#additional-manifest-settings)이 필요하며, 대신 글로벌 구성에서 `channels.slack.commands.native: true` 또는 `commands.native: true`로 활성화됩니다.
네이티브 명령은 Slack 앱에 [추가 매니페스트 설정](#additional-manifest-settings)이 필요하며, 대신 전역 구성에서 `channels.slack.commands.native: true` 또는 `commands.native: true`로 활성화됩니다.
- Slack에서는 네이티브 명령 자동 모드가 **꺼져** 있으므로 `commands.native: "auto"`는 Slack 네이티브 명령을 활성화하지 않습니다.
@ -772,19 +791,19 @@ Slack 네이티브 텍스트 스트리밍 대신 초안 미리 보기를 사용
네이티브 인수 메뉴는 선택된 옵션 값을 디스패치하기 전에 확인 모달을 표시하는 적응형 렌더링 전략을 사용합니다.
- 최대 5개 옵션: 버튼 블록
- 6~100개 옵션: 정적 선택 메뉴
- 100개 초과 옵션: 상호작용 옵션 핸들러를 사용할 수 있을 때 비동기 옵션 필터링이 포함된 외부 선택
- Slack 제한 초과: 인코딩된 옵션 값은 버튼으로 대체
- 6-100개 옵션: 정적 선택 메뉴
- 100개 초과 옵션: 상호작용 옵션 핸들러를 사용할 수 있을 때 비동기 옵션 필터링을 사용하는 외부 선택
- Slack 제한 초과: 인코딩된 옵션 값은 버튼으로 폴백합니다
```txt
/think
```
슬래시 세션은 `agent:<agentId>:slack:slash:<userId>` 같은 격리된 키를 사용하며, 여전히 `CommandTargetSessionKey`를 사용해 명령 실행을 대상 대화 세션으로 라우팅합니다.
슬래시 세션은 `agent:<agentId>:slack:slash:<userId>` 같은 격리된 키를 사용하며, 여전히 `CommandTargetSessionKey`를 사용해 대상 대화 세션으로 명령 실행을 라우팅합니다.
## 대화형 답장
## 상호작용 응답
Slack은 에이전트가 작성한 대화형 답장 컨트롤을 렌더링할 수 있지만, 이 기능은 기본적으로 비활성화되어 있습니다.
Slack은 에이전트가 작성한 상호작용 응답 컨트롤을 렌더링할 수 있지만, 이 기능은 기본적으로 비활성화되어 있습니다.
전역으로 활성화:
@ -818,44 +837,43 @@ Slack은 에이전트가 작성한 대화형 답장 컨트롤을 렌더링할
}
```
활성화되면 에이전트는 Slack 전용 답장 지시문을 내보낼 수 있습니다.
활성화하면 에이전트가 Slack 전용 응답 지시문을 내보낼 수 있습니다.
- `[[slack_buttons: Approve:approve, Reject:reject]]`
- `[[slack_select: Choose a target | Canary:canary, Production:production]]`
이 지시문은 Slack Block Kit으로 컴파일되며 클릭 또는 선택을 기존 Slack 상호작용 이벤트 경로를 통해 다시 라우팅합니다.
이 지시문은 Slack Block Kit으로 컴파일되며, 클릭 또는 선택을 기존 Slack 상호작용 이벤트 경로를 통해 다시 라우팅합니다.
참고:
- 이것은 Slack 전용 UI입니다. 다른 채널은 Slack Block Kit 지시문을 자체 버튼 시스템으로 변환하지 않습니다.
- 대화형 콜백 값은 원시 에이전트 작성 값이 아니라 OpenClaw가 생성한 불투명 토큰입니다.
- 생성된 대화형 블록이 Slack Block Kit 제한을 초과할 경우, OpenClaw는 유효하지 않은 블록 페이로드를 보내는 대신 원래 텍스트 답장으로 대체합니다.
- 이 Slack 전용 UI입니다. 다른 채널은 Slack Block Kit 지시문을 자체 버튼 시스템으로 변환하지 않습니다.
- 상호작용 콜백 값은 에이전트가 작성한 원시 값이 아니라 OpenClaw가 생성한 불투명 토큰입니다.
- 생성된 상호작용 블록이 Slack Block Kit 제한을 초과하면 OpenClaw는 잘못된 블록 페이로드를 보내는 대신 원래 텍스트 응답으로 폴백합니다.
## Slack의 Exec 승인
Slack은 Web UI 또는 터미널로 대체하는 대신, 대화형 버튼과 상호작용을 갖춘 네이티브 승인 클라이언트로 동작할 수 있습니다.
Slack은 Web UI 또는 터미널로 폴백하는 대신, 상호작용 버튼과 상호작용을 갖춘 네이티브 승인 클라이언트로 동작할 수 있습니다.
- Exec 승인은 네이티브 DM/채널 라우팅에 `channels.slack.execApprovals.*`를 사용합니다.
- 요청이 이미 Slack에 도착했고 승인 ID 종류가 `plugin:`인 경우, Plugin 승인은 동일한 Slack 네이티브 버튼 표면을 통해 계속 해결될 수 있습니다.
- 요청이 이미 Slack에 도착했고 승인 ID 종류가 `plugin:`인 경우, Plugin 승인도 같은 Slack 네이티브 버튼 표면을 통해 해결될 수 있습니다.
- 승인자 권한 부여는 계속 적용됩니다. 승인자로 식별된 사용자만 Slack을 통해 요청을 승인하거나 거부할 수 있습니다.
이는 다른 채널과 동일한 공유 승인 버튼 표면을 사용합니다. Slack 앱 설정에서 `interactivity`가 활성화되면 승인 프롬프트가 대화 안에 Block Kit 버튼으로 직접 렌더링됩니다.
해당 버튼이 있으면 그것이 기본 승인 UX입니다. OpenClaw는 도구 결과가 채팅
승인을 사용할 수 없다고 하거나 수동 승인이 유일한 경로라고 할 때
수동 `/approve` 명령을 포함해야 합니다.
승인을 사용할 수 없다고 하거나 수동 승인이 유일한 경로라고 할 때만 수동
`/approve` 명령을 포함해야 합니다.
구성 경로:
- `channels.slack.execApprovals.enabled`
- `channels.slack.execApprovals.approvers`(선택 사항, 가능하면 `commands.ownerAllowFrom`으로 대체)
- `channels.slack.execApprovals.approvers`(선택 사항. 가능하면 `commands.ownerAllowFrom`으로 폴백)
- `channels.slack.execApprovals.target`(`dm` | `channel` | `both`, 기본값: `dm`)
- `agentFilter`, `sessionFilter`
Slack은 `enabled`가 설정되지 않았거나 `"auto"`이고 하나 이상의
승인자가 확인되면 네이티브 Exec 승인을 자동으로 활성화합니다. Slack을 네이티브 승인 클라이언트로 명시적으로 비활성화하려면 `enabled: false`를 설정하세요.
Slack은 `enabled`가 설정되지 않았거나 `"auto"`이고 하나 이상의 승인자가 확인되면 네이티브 exec 승인을 자동으로 활성화합니다. Slack을 네이티브 승인 클라이언트로 명시적으로 비활성화하려면 `enabled: false`를 설정하세요.
승인자가 확인될 때 네이티브 승인을 강제로 켜려면 `enabled: true`를 설정하세요.
명시적 Slack Exec 승인 구성이 없을 때의 기본 동작:
명시적 Slack exec 승인 구성이 없을 때의 기본 동작:
```json5
{
@ -882,34 +900,32 @@ Slack은 `enabled`가 설정되지 않았거나 `"auto"`이고 하나 이상의
}
```
공유 `approvals.exec` 전달은 별도입니다. Exec 승인 프롬프트를 다른 채팅 또는 명시적인 대역 외 대상에도
라우팅해야 할 때만 사용하세요. 공유 `approvals.plugin` 전달도
별도입니다. 해당 요청이 이미 Slack에 도착한 경우 Slack 네이티브 버튼으로 Plugin 승인을 계속 해결할 수 있습니다.
공유 `approvals.exec` 포워딩은 별개입니다. exec 승인 프롬프트가 다른 채팅이나 명시적 대역 외 대상으로도 라우팅되어야 할 때만 사용하세요. 공유 `approvals.plugin` 포워딩도 별개입니다. 해당 요청이 이미 Slack에 도착한 경우 Slack 네이티브 버튼은 여전히 Plugin 승인을 해결할 수 있습니다.
동일 채팅 `/approve`는 이미 명령을 지원하는 Slack 채널과 DM에서도 동작합니다. 전체 승인 전달 모델은 [Exec 승인](/ko/tools/exec-approvals)을 참고하세요.
동일 채팅 `/approve`도 이미 명령을 지원하는 Slack 채널과 DM에서 작동합니다. 전체 승인 포워딩 모델은 [Exec 승인](/ko/tools/exec-approvals)을 참조하세요.
## 이벤트 및 운영 동작
- 메시지 편집/삭제는 시스템 이벤트로 매핑됩니다.
- 스레드 브로드캐스트("채널에도 보내기" 스레드 답)는 일반 사용자 메시지로 처리됩니다.
- 메시지 수정/삭제는 시스템 이벤트로 매핑됩니다.
- 스레드 브로드캐스트("채널에도 보내기" 스레드 답)는 일반 사용자 메시지로 처리됩니다.
- 반응 추가/제거 이벤트는 시스템 이벤트로 매핑됩니다.
- 멤버 참여/퇴장, 채널 생성/이름 변경, 핀 추가/제거 이벤트는 시스템 이벤트로 매핑됩니다.
- `configWrites`가 활성화되면 `channel_id_changed` 채널 구성 키를 마이그레이션할 수 있습니다.
- 채널 주제/목적 메타데이터는 신뢰할 수 없는 컨텍스트로 취급되며 라우팅 컨텍스트에 입될 수 있습니다.
- 스레드 시작 메시지와 초기 스레드 기록 컨텍스트 시딩은 해당되는 경우 구성된 발신자 허용 목록으로 필터링됩니다.
- 블록 작업과 모달 상호작용은 풍부한 페이로드 필드를 포함 구조화된 `Slack interaction: ...` 시스템 이벤트를 내보냅니다.
- 블록 작업: 선택된 값, 레이블, 피커 값 `workflow_*` 메타데이터
- 라우팅된 채널 메타데이터와 양식 입력을 포함한 모달 `view_submission``view_closed` 이벤트
- 멤버 참여/나가기, 채널 생성/이름 변경, 핀 추가/제거 이벤트는 시스템 이벤트로 매핑됩니다.
- `configWrites`가 활성화된 경우 `channel_id_changed` 채널 구성 키를 마이그레이션할 수 있습니다.
- 채널 주제/목적 메타데이터는 신뢰할 수 없는 컨텍스트로 취급되며 라우팅 컨텍스트에 입될 수 있습니다.
- 스레드 시작와 초기 스레드 기록 컨텍스트 시딩은 해당되는 경우 구성된 발신자 허용 목록으로 필터링됩니다.
- 블록 작업과 모달 상호작용은 풍부한 페이로드 필드를 포함하는 구조화된 `Slack interaction: ...` 시스템 이벤트를 내보냅니다.
- 블록 작업: 선택된 값, 레이블, 피커 값, `workflow_*` 메타데이터
- 라우팅된 채널 메타데이터와 입력을 포함한 모달 `view_submission``view_closed` 이벤트
## 구성 참조
기본 참조: [구성 참조 - Slack](/ko/gateway/config-channels#slack).
<Accordion title="High-signal Slack fields">
<Accordion title="중요도가 높은 Slack 필드">
- 모드/인증: `mode`, `botToken`, `appToken`, `signingSecret`, `webhookPath`, `accounts.*`
- DM 접근: `dm.enabled`, `dmPolicy`, `allowFrom`(레거시: `dm.policy`, `dm.allowFrom`), `dm.groupEnabled`, `dm.groupChannels`
- 호환성 토글: `dangerouslyAllowNameMatching`(비상용, 필요하지 않으면 꺼둠)
- 호환성 토글: `dangerouslyAllowNameMatching`(비상용. 필요하지 않으면 꺼 두세요)
- 채널 접근: `groupPolicy`, `channels.*`, `channels.*.users`, `channels.*.requireMention`
- 스레딩/기록: `replyToMode`, `replyToModeByChatType`, `thread.*`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit`
- 전달: `textChunkLimit`, `chunkMode`, `mediaMaxMb`, `streaming`, `streaming.nativeTransport`, `streaming.preview.toolProgress`
@ -920,11 +936,11 @@ Slack은 `enabled`가 설정되지 않았거나 `"auto"`이고 하나 이상의
## 문제 해결
<AccordionGroup>
<Accordion title="No replies in channels">
<Accordion title="채널에서 응답 없음">
순서대로 확인하세요.
- `groupPolicy`
- 채널 허용 목록(`channels.slack.channels`) — **키는 채널 이름(`#channel-name`)이 아니라 채널 ID**(`C12345678`)여야 합니다. 채널 라우팅은 기본적으로 ID 우선이므로, `groupPolicy: "allowlist"`에서 이름 기반 키는 조용히 실패합니다. ID를 찾으려면 Slack에서 채널을 우클릭 → **링크 복사** — URL 끝의 `C...` 값이 채널 ID입니다.
- 채널 허용 목록(`channels.slack.channels`) — **키는 채널 이름**(`#channel-name`)이 아니라 **채널 ID**(`C12345678`)여야 합니다. 채널 라우팅은 기본적으로 ID 우선이므로 `groupPolicy: "allowlist"`에서 이름 기반 키는 조용히 실패합니다. ID를 찾으려면 Slack에서 채널을 스 오른쪽 버튼으로 클릭 → **링크 복사** — URL 끝의 `C...` 값이 채널 ID입니다.
- `requireMention`
- 채널별 `users` 허용 목록
@ -938,7 +954,7 @@ openclaw doctor
</Accordion>
<Accordion title="DM messages ignored">
<Accordion title="DM 메시지가 무시됨">
확인하세요.
- `channels.slack.dm.enabled`
@ -946,7 +962,7 @@ openclaw doctor
- 페어링 승인 / 허용 목록 항목
- Slack Assistant DM 이벤트: `drop message_changed`를 언급하는 상세 로그는
일반적으로 Slack이 메시지 메타데이터에 복구 가능한 사람 발신자 없이
편집된 Assistant 스레드 이벤트를 보냈다는 뜻입니다.
수정된 Assistant 스레드 이벤트를 보냈다는 뜻입니다
```bash
openclaw pairing list slack
@ -954,33 +970,33 @@ openclaw pairing list slack
</Accordion>
<Accordion title="Socket mode not connecting">
Slack 앱 설정에서 봇 + 앱 토큰과 Socket Mode 활성화를 검증하세요.
<Accordion title="Socket 모드가 연결되지 않음">
Slack 앱 설정에서 bot + app 토큰과 Socket Mode 활성화를 검증하세요.
`openclaw channels status --probe --json``botTokenStatus` 또는
`appTokenStatus: "configured_unavailable"`가 표시되면, Slack 계정은
구성되지만 현재 런타임이 SecretRef 기반 값을 확인할 수 없었다는 뜻입니다.
`appTokenStatus: "configured_unavailable"`가 표시되면 Slack 계정은
구성되어 있지만 현재 런타임이 SecretRef 기반 값을 확인할 수 없었다는 뜻입니다.
</Accordion>
<Accordion title="HTTP mode not receiving events">
<Accordion title="HTTP 모드가 이벤트를 받지 않음">
검증하세요.
- 서명 시크릿
- 서명 비밀
- Webhook 경로
- Slack 요청 URL(이벤트 + 상호작용 + 슬래시 명령)
- HTTP 계정별 고유한 `webhookPath`
계정 스냅샷에 `signingSecretStatus: "configured_unavailable"`가 표시되면,
HTTP 계정은 구성되었지만 현재 런타임이 SecretRef 기반 서명 시크릿
HTTP 계정은 구성되어 있지만 현재 런타임이 SecretRef 기반 서명 비밀
확인할 수 없었다는 뜻입니다.
</Accordion>
<Accordion title="Native/slash commands not firing">
<Accordion title="네이티브/슬래시 명령이 실행되지 않음">
의도한 것이 무엇인지 확인하세요.
- Slack에 등록된 일치하는 슬래시 명령과 함께 사용하는 네이티브 명령 모드(`channels.slack.commands.native: true`)
- Slack에 등록된 일치하는 슬래시 명령이 있는 네이티브 명령 모드(`channels.slack.commands.native: true`)
- 또는 단일 슬래시 명령 모드(`channels.slack.slashCommand.enabled: true`)
`commands.useAccessGroups`와 채널/사용자 허용 목록도 확인하세요.
@ -988,19 +1004,19 @@ openclaw pairing list slack
</Accordion>
</AccordionGroup>
## 첨부 비전 참조
## 첨부 파일 비전 참조
Slack 파일 다운로드에 성공하고 크기 제한이 허용되면 Slack은 다운로드된 미디어를 에이전트 턴에 첨부할 수 있습니다. 이미지 파일은 미디어 이해 경로를 통과하거나 비전 지원 답장 모델에 직접 전달될 수 있습니다. 다른 파일은 이미지 입력으로 처리되지 않고 다운로드 가능한 파일 컨텍스트로 보존됩니다.
Slack 파일 다운로드에 성공하고 크기 제한이 허용되면 Slack은 다운로드된 미디어를 에이전트 턴에 첨부할 수 있습니다. 이미지 파일은 미디어 이해 경로를 통해 전달되거나 비전 가능 응답 모델에 직접 전달될 수 있습니다. 다른 파일은 이미지 입력으로 취급되지 않고 다운로드 가능한 파일 컨텍스트로 유지됩니다.
### 지원되는 미디어 유형
| 미디어 유형 | 소스 | 현재 동작 | 참고 |
| 미디어 유형 | 소스 | 현재 동작 | 참고 사항 |
| ------------------------------ | -------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| JPEG / PNG / GIF / WebP 이미지 | Slack 파일 URL | 다운로드되어 비전 지원 처리를 위해 턴에 첨부됨 | 파일당 제한: `channels.slack.mediaMaxMb`(기본값 20 MB) |
| PDF 파일 | Slack 파일 URL | 다운로드되어 `download-file` 또는 `pdf` 같은 도구의 파일 컨텍스트로 노출됨 | Slack 인바운드는 PDF를 이미지 비전 입력으로 자동 변환하지 않음 |
| 기타 파일 | Slack 파일 URL | 가능한 경우 다운로드되어 파일 컨텍스트로 노출됨 | 바이너리 파일은 이미지 입력으로 취급되지 않음 |
| 스레드 답글 | 스레드 시작 메시지 파일 | 답글에 직접 미디어가 없으면 루트 메시지 파일을 컨텍스트로 하이드레이션할 수 있음 | 파일만 있는 시작 메시지는 첨부 파일 플레이스홀더를 사용함 |
| 다중 이미지 메시지 | 여러 Slack 파일 | 각 파일이 독립적으로 평가됨 | Slack 처리는 메시지당 최대 8개 파일로 제한됨 |
| JPEG / PNG / GIF / WebP 이미지 | Slack 파일 URL | 다운로드되어 비전 지원 처리를 위해 턴에 첨부됨 | 파일별 한도: `channels.slack.mediaMaxMb`(기본값 20 MB) |
| PDF 파일 | Slack 파일 URL | 다운로드되어 `download-file` 또는 `pdf` 같은 도구의 파일 컨텍스트로 노출됨 | Slack 인바운드는 PDF를 이미지 비전 입력으로 자동 변환하지 않음 |
| 기타 파일 | Slack 파일 URL | 가능한 경우 다운로드되어 파일 컨텍스트로 노출됨 | 바이너리 파일은 이미지 입력으로 취급되지 않음 |
| 스레드 답글 | 스레드 시작자 파일 | 답글에 직접 미디어가 없을 때 루트 메시지 파일을 컨텍스트로 하이드레이션할 수 있음 | 파일만 있는 시작자는 첨부 파일 플레이스홀더를 사용함 |
| 다중 이미지 메시지 | 여러 Slack 파일 | 각 파일은 독립적으로 평가됨 | Slack 처리는 메시지당 8개 파일로 제한됨 |
### 인바운드 파이프라인
@ -1010,15 +1026,15 @@ Slack 파일 다운로드에 성공하고 크기 제한이 허용되면 Slack은
2. 성공하면 파일이 미디어 저장소에 기록됩니다.
3. 다운로드된 미디어 경로와 콘텐츠 유형이 인바운드 컨텍스트에 추가됩니다.
4. 이미지 지원 모델/도구 경로는 해당 컨텍스트의 이미지 첨부를 사용할 수 있습니다.
5. 이미지가 아닌 파일은 이를 처리할 수 있는 도구에서 파일 메타데이터 또는 미디어 참조로 계속 사용할 수 있습니다.
5. 이미지가 아닌 파일은 이를 처리할 수 있는 도구를 위해 파일 메타데이터 또는 미디어 참조로 계속 사용할 수 있습니다.
### 스레드 루트 첨부 상속
메시지가 스레드에 도착하면(`thread_ts` 부모가 있음):
- 답글 자체에 직접 미디어가 없고 포함된 루트 메시지에 파일이 있으면, Slack은 루트 파일을 스레드 시작 컨텍스트로 하이드레이션할 수 있습니다.
- 답글 자체에 직접 미디어가 없고 포함된 루트 메시지에 파일이 있으면 Slack은 루트 파일을 스레드 시작 컨텍스트로 하이드레이션할 수 있습니다.
- 직접 답글 첨부가 루트 메시지 첨부보다 우선합니다.
- 파일만 있고 텍스트가 없는 루트 메시지는 첨부 파일 플레이스홀더로 표현되어 fallback이 해당 파일을 계속 포함할 수 있습니다.
- 파일만 있고 텍스트가 없는 루트 메시지는 대체 동작이 여전히 파일을 포함할 수 있도록 첨부 파일 플레이스홀더로 표현됩니다.
### 다중 첨부 처리
@ -1031,29 +1047,29 @@ Slack 파일 다운로드에 성공하고 크기 제한이 허용되면 Slack은
### 크기, 다운로드, 모델 제한
- **크기 한**: 기본값은 파일당 20 MB입니다. `channels.slack.mediaMaxMb`로 구성할 수 있습니다.
- **크기 **: 파일당 기본 20 MB입니다. `channels.slack.mediaMaxMb`로 구성할 수 있습니다.
- **다운로드 실패**: Slack이 제공할 수 없는 파일, 만료된 URL, 접근할 수 없는 파일, 크기 초과 파일, Slack 인증/로그인 HTML 응답은 지원되지 않는 형식으로 보고되지 않고 건너뜁니다.
- **비전 모델**: 이미지 분석은 비전을 지원하는 경우 활성 답글 모델을 사용하거나, `agents.defaults.imageModel`에 구성된 이미지 모델을 사용합니다.
- **비전 모델**: 이미지 분석은 비전을 지원하는 경우 활성 답글 모델을 사용하거나 `agents.defaults.imageModel`에 구성된 이미지 모델을 사용합니다.
### 알려진 제한
| 시나리오 | 현재 동작 | 해결 방법 |
| -------------------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| 만료된 Slack 파일 URL | 파일을 건너뜀; 오류가 표시되지 않음 | Slack에 파일을 다시 업로드 |
| 비전 모델이 구성되지 않음 | 이미지 첨부가 미디어 참조로 저장되지만 이미지로 분석되지 않음 | `agents.defaults.imageModel`을 구성하거나 비전 지원 답글 모델 사용 |
| 매우 큰 이미지(기본값 기준 > 20 MB) | 크기 한에 따라 건너뜀 | Slack이 허용하는 경우 `channels.slack.mediaMaxMb` 증가 |
| 전달/공유된 첨부 | 텍스트 및 Slack 호스팅 이미지/파일 미디어는 최선 노력으로 처리됨 | OpenClaw 스레드에서 직접 다시 공유 |
| PDF 첨부 | 파일/미디어 컨텍스트로 저장되며 이미지 비전을 통해 자동 라우팅되지 않음 | 파일 메타데이터에는 `download-file`을 사용하거나 PDF 분석에는 `pdf` 도구 사용 |
| 시나리오 | 현재 동작 | 해결 방법 |
| ------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| 만료된 Slack 파일 URL | 파일을 건너뜀; 오류가 표시되지 않음 | Slack에 파일을 다시 업로드 |
| 비전 모델이 구성되지 않음 | 이미지 첨부가 미디어 참조로 저장되지만 이미지로 분석되지 않음 | `agents.defaults.imageModel`을 구성하거나 비전 지원 답글 모델 사용 |
| 매우 큰 이미지(기본값 기준 > 20 MB) | 크기 한에 따라 건너뜀 | Slack이 허용하는 경우 `channels.slack.mediaMaxMb` 증가 |
| 전달/공유된 첨부 | 텍스트와 Slack 호스팅 이미지/파일 미디어는 최선형으로 처리됨 | OpenClaw 스레드에서 직접 다시 공유 |
| PDF 첨부 | 파일/미디어 컨텍스트로 저장되며 이미지 비전을 통해 자동 라우팅되지 않음 | 파일 메타데이터에는 `download-file`을 사용하거나 PDF 분석에는 `pdf` 도구 사용 |
### 관련 문서
- [미디어 이해 파이프라인](/ko/nodes/media-understanding)
- [PDF 도구](/ko/tools/pdf)
- 에픽: [#51349](https://github.com/openclaw/openclaw/issues/51349) — Slack 첨부 비전 활성화
- Epic: [#51349](https://github.com/openclaw/openclaw/issues/51349) — Slack 첨부 비전 활성화
- 회귀 테스트: [#51353](https://github.com/openclaw/openclaw/issues/51353)
- 라이브 검증: [#51354](https://github.com/openclaw/openclaw/issues/51354)
## 관련 항목
## 관련
<CardGroup cols={2}>
<Card title="Pairing" icon="link" href="/ko/channels/pairing">

View File

@ -1,38 +1,38 @@
---
read_when:
- Telegram 기능 또는 Webhook 작업하기
summary: Telegram 봇 지원 상태, 기능 및 설정
summary: Telegram 봇 지원 상태, 기능 및 구성
title: Telegram
x-i18n:
generated_at: "2026-05-04T06:22:43Z"
generated_at: "2026-05-04T07:02:47Z"
model: gpt-5.5
provider: openai
source_hash: c7f49db5f3fe8fd724e53a2ae3d226446f248bf9d021fcc01c1cf816649381d2
source_hash: 6ef1b019a6a0e261b33972b5edffaedd29310b1333d112bade2e79e9d56887c6
source_path: channels/telegram.md
workflow: 16
---
프로덕션에서 사용할 준비가 된 grammY 기반 봇 DM 및 그룹 지원입니다. 롱 폴링이 기본 모드이며, Webhook 모드는 선택 사항입니다.
grammY를 통해 bot DM 및 그룹에서 프로덕션 준비 완료 상태로 사용할 수 있습니다. Long polling이 기본 모드이며, webhook 모드는 선택 사항입니다.
<CardGroup cols={3}>
<Card title="페어링" icon="link" href="/ko/channels/pairing">
Telegram의 기본 DM 정책은 페어링입니다.
</Card>
<Card title="채널 문제 해결" icon="wrench" href="/ko/channels/troubleshooting">
채널 진단 및 복구 플레이북입니다.
교차 채널 진단 및 복구 플레이북입니다.
</Card>
<Card title="Gateway 구성" icon="settings" href="/ko/gateway/configuration">
전체 채널 구성 패턴 예시입니다.
전체 채널 구성 패턴 예시입니다.
</Card>
</CardGroup>
## 빠른 설정
<Steps>
<Step title="BotFather에서 토큰 만들기">
<Step title="BotFather에서 bot 토큰 만들기">
Telegram을 열고 **@BotFather**와 채팅합니다(핸들이 정확히 `@BotFather`인지 확인).
`/newbot`을 실행하고 안내를 따른 뒤 토큰을 저장합니다.
`/newbot`을 실행하고 프롬프트를 따른 뒤 토큰을 저장합니다.
</Step>
@ -51,12 +51,12 @@ x-i18n:
}
```
환경 변수 폴백: `TELEGRAM_BOT_TOKEN=...`(기본 계정만 해당).
Telegram은 `openclaw channels login telegram`을 사용하지 **않습니다**. config/env에 토큰을 구성한 다음 Gateway를 시작하세요.
Env 폴백: `TELEGRAM_BOT_TOKEN=...`(기본 계정 전용).
Telegram은 `openclaw channels login telegram`을 사용하지 **않습니다**. config/env에 토큰을 구성한 다음 Gateway를 시작하세요.
</Step>
<Step title="Gateway를 시작하고 첫 DM 승인">
<Step title="Gateway 시작 및 첫 DM 승인">
```bash
openclaw gateway
@ -68,77 +68,77 @@ openclaw pairing approve telegram <CODE>
</Step>
<Step title="그룹에 추가">
그룹에 봇을 추가한 다음, 액세스 모델에 맞게 `channels.telegram.groups` `groupPolicy`를 설정합니다.
<Step title="bot을 그룹에 추가">
bot을 그룹에 추가한 다음, 접근 모델에 맞게 `channels.telegram.groups` `groupPolicy`를 설정합니다.
</Step>
</Steps>
<Note>
토큰 확인 순서는 계정을 인식합니다. 실제로는 구성 값이 환경 변수 폴백보다 우선하며, `TELEGRAM_BOT_TOKEN`은 기본 계정에만 적용됩니다.
토큰 확인 순서는 계정을 인식합니다. 실제로는 config 값이 env 폴백보다 우선하며, `TELEGRAM_BOT_TOKEN`은 기본 계정에만 적용됩니다.
</Note>
## Telegram 설정
## Telegram 설정
<AccordionGroup>
<Accordion title="개인정보 보호 모드 및 그룹 가시성">
Telegram 봇은 기본적으로 **개인정보 보호 모드**를 사용하며, 이 모드는 봇이 받을 수 있는 그룹 메시지를 제한합니다.
<Accordion title="프라이버시 모드 및 그룹 표시 여부">
Telegram bot은 기본적으로 **프라이버시 모드**를 사용하며, 이 모드는 bot이 수신하는 그룹 메시지를 제한합니다.
봇이 모든 그룹 메시지를 확인해야 한다면 다음 중 하나를 수행하세요.
bot이 모든 그룹 메시지를 확인해야 한다면 다음 중 하나를 수행합니다.
- `/setprivacy`로 개인정보 보호 모드를 비활성화하거나
- 을 그룹 관리자로 지정합니다.
- `/setprivacy`를 통해 프라이버시 모드를 비활성화하거나
- bot을 그룹 관리자로 지정합니다.
개인정보 보호 모드를 전환할 때는 Telegram이 변경 사항을 적용하도록 각 그룹에서 봇을 제거한 뒤 다시 추가하세요.
프라이버시 모드를 전환할 때는 Telegram이 변경 사항을 적용하도록 각 그룹에서 bot을 제거한 뒤 다시 추가하세요.
</Accordion>
<Accordion title="그룹 권한">
관리자 상태는 Telegram 그룹 설정에서 제어됩니다.
관리자 봇은 모든 그룹 메시지를 받으므로, 상시 동작하는 그룹 동작에 유용합니다.
관리자 bot은 모든 그룹 메시지를 수신하므로, 항상 켜져 있는 그룹 동작에 유용합니다.
</Accordion>
<Accordion title="유용한 BotFather 토글">
- 그룹 추가를 허용/거부하는 `/setjoingroups`
- 그룹 가시성 동작을 위한 `/setprivacy`
- 그룹 추가 허용/거부용 `/setjoingroups`
- 그룹 표시 동작용 `/setprivacy`
</Accordion>
</AccordionGroup>
## 액세스 제어 및 활성화
## 접근 제어 및 활성화
<Tabs>
<Tab title="DM 정책">
`channels.telegram.dmPolicy`직접 메시지 액세스를 제어합니다.
`channels.telegram.dmPolicy`다이렉트 메시지 접근을 제어합니다.
- `pairing`(기본값)
- `allowlist`(`allowFrom`에 하나 이상의 발신자 ID 필요)
- `open`(`allowFrom`에 `"*"` 포함 필요)
- `disabled`
`allowFrom: ["*"]`와 함께 `dmPolicy: "open"`을 사용하면 봇 사용자 이름을 찾거나 추측한 모든 Telegram 계정이 봇에 명령할 수 있습니다. 도구가 엄격히 제한된 의도적인 공개 봇에만 사용하세요. 단일 소유자 봇은 숫자 사용자 ID와 함께 `allowlist`를 사용해야 합니다.
`allowFrom: ["*"]`와 함께 `dmPolicy: "open"`을 사용하면 bot 사용자 이름을 찾거나 추측한 모든 Telegram 계정이 bot에 명령을 보낼 수 있습니다. 도구가 엄격히 제한된 의도적인 공개 bot에만 사용하세요. 단일 소유자 bot은 숫자 사용자 ID와 함께 `allowlist`를 사용해야 합니다.
`channels.telegram.allowFrom`은 숫자 Telegram 사용자 ID를 허용합니다. `telegram:` / `tg:` 접두사는 허용되며 정규화됩니다.
다중 계정 구성에서는 제한적인 최상위 `channels.telegram.allowFrom`이 안전 경계로 처리됩니다. 병합 후 유효 계정 허용 목록에 명시적 와일드카드가 여전히 포함되어 있지 않으면, 계정 수준의 `allowFrom: ["*"]` 항목이 해당 계정을 공개로 만들지 않습니다.
`allowFrom`과 함께 `dmPolicy: "allowlist"`를 사용하면 모든 DM이 차단되며 구성 검증에서 거부됩니다.
설정 숫자 사용자 ID만 요청합니다.
업그레이드 후 구성에 `@username` 허용 목록 항목이 포함되어 있다면 `openclaw doctor --fix`를 실행해 이를 확인하세요(최선의 시도이며, Telegram 봇 토큰 필요).
이전에 페어링 저장소 허용 목록 파일에 의존했다면, `openclaw doctor --fix`가 allowlist 흐름에서 항목을 `channels.telegram.allowFrom`으로 복구할 수 있습니다(예: `dmPolicy: "allowlist"`에 아직 명시적 ID가 없는 경우).
다중 계정 구성에서는 제한적인 최상위 `channels.telegram.allowFrom`이 안전 경계로 처리됩니다. 계정 수준의 `allowFrom: ["*"]` 항목은 병합 후 유효 계정 allowlist에 명시적 와일드카드가 여전히 포함되어 있지 않으면 해당 계정을 공개로 만들지 않습니다.
비어 있는 `allowFrom`과 함께 `dmPolicy: "allowlist"`를 사용하면 모든 DM이 차단되며 config 유효성 검사에서 거부됩니다.
설정에서는 숫자 사용자 ID만 요청합니다.
업그레이드 후 config에 `@username` allowlist 항목이 포함되어 있다면, `openclaw doctor --fix`를 실행하여 이를 해석하세요(최선의 노력 방식이며 Telegram bot 토큰이 필요함).
이전에 pairing-store allowlist 파일에 의존했다면, `openclaw doctor --fix`가 allowlist 흐름에서 항목을 `channels.telegram.allowFrom`으로 복구할 수 있습니다(예: `dmPolicy: "allowlist"`에 아직 명시적 ID가 없는 경우).
단일 소유자 봇의 경우, 이전 페어링 승인에 의존하는 대신 액세스 정책이 구성에 지속되도록 명시적인 숫자 `allowFrom` ID와 함께 `dmPolicy: "allowlist"`를 사용하는 것이 좋습니다.
단일 소유자 bot의 경우, 이전 페어링 승인에 의존하는 대신 접근 정책을 config에 지속적으로 유지하려면 명시적 숫자 `allowFrom` ID와 함께 `dmPolicy: "allowlist"`를 사용하는 것이 좋습니다.
흔한 혼동: DM 페어링 승인은 "이 발신자가 모든 곳에서 승인되었다"는 뜻이 아닙니다.
페어링은 DM 액세스를 부여합니다. 명령 소유자가 아직 없으면, 첫 승인된 페어링은 소유자 전용 명령과 실행 승인이 명시적인 운영자 계정을 갖도록 `commands.ownerAllowFrom`도 설정합니다.
그룹 발신자 인증은 여전히 명시적인 구성 허용 목록에서 가져옵니다.
"한 번 승인되면 DM과 그룹 명령이 모두 작동"하기를 원한다면 숫자 Telegram 사용자 ID를 `channels.telegram.allowFrom`에 넣으세요. 소유자 전용 명령의 경우 `commands.ownerAllowFrom``telegram:<your user id>`가 포함되어 있는지 확인하세요.
흔한 혼동: DM 페어링 승인이 "이 발신자는 모든 곳에서 승인됨"을 의미하지는 않습니다.
페어링은 DM 접근을 부여합니다. 명령 소유자가 아직 없으면, 첫 번째 승인된 페어링은 소유자 전용 명령 및 exec 승인이 명시적 운영자 계정을 갖도록 `commands.ownerAllowFrom`도 설정합니다.
그룹 발신자 승인은 여전히 명시적 config allowlist에서 가져옵니다.
"한 번 승인되면 DM과 그룹 명령이 모두 작동"하도록 하려면 숫자 Telegram 사용자 ID를 `channels.telegram.allowFrom`에 넣으세요. 소유자 전용 명령의 경우 `commands.ownerAllowFrom``telegram:<your user id>`가 포함되어 있는지 확인하세요.
### Telegram 사용자 ID 찾기
더 안전한 방법(서드파티 봇 없음):
더 안전한 방법(타사 bot 없음):
1. 에 DM을 보냅니다.
1. bot에 DM을 보냅니다.
2. `openclaw logs --follow`를 실행합니다.
3. `from.id`를 확인합니다.
@ -148,35 +148,35 @@ openclaw pairing approve telegram <CODE>
curl "https://api.telegram.org/bot<bot_token>/getUpdates"
```
서드파티 방법(개인정보 보호 수준 낮음): `@userinfobot` 또는 `@getidsbot`.
타사 방법(프라이버시가 더 낮음): `@userinfobot` 또는 `@getidsbot`.
</Tab>
<Tab title="그룹 정책 및 허용 목록">
가지 제어가 함께 적용됩니다.
<Tab title="그룹 정책 및 allowlist">
제어 항목이 함께 적용됩니다.
1. **허용되는 그룹**(`channels.telegram.groups`)
- `groups` 구성이 없음:
- `groups` config 없음:
- `groupPolicy: "open"`인 경우: 모든 그룹이 그룹 ID 검사를 통과할 수 있음
- `groupPolicy: "allowlist"`(기본값)인 경우: `groups` 항목(또는 `"*"`)을 추가할 때까지 그룹이 차단됨
- `groups`가 구성됨: 허용 목록처럼 동작(명시적 ID 또는 `"*"`)
- `groups`가 구성됨: allowlist로 동작(명시적 ID 또는 `"*"`)
2. **그룹에서 허용되는 발신자**(`channels.telegram.groupPolicy`)
- `open`
- `allowlist`(기본값)
- `disabled`
`groupAllowFrom`은 그룹 발신자 필터링에 사용됩니다. 설정하지 않으면 Telegram은 `allowFrom`으로 폴백합니다.
`groupAllowFrom`은 그룹 발신자 필터링에 사용됩니다. 설정되지 않은 경우 Telegram은 `allowFrom`으로 폴백합니다.
`groupAllowFrom` 항목은 숫자 Telegram 사용자 ID여야 합니다(`telegram:` / `tg:` 접두사는 정규화됨).
Telegram 그룹 또는 슈퍼그룹 채팅 ID를 `groupAllowFrom`에 넣지 마세요. 음수 채팅 ID는 `channels.telegram.groups` 아래에 니다.
숫자가 아닌 항목은 발신자 인에서 무시됩니다.
보안 경계(`2026.2.25+`): 그룹 발신자 인증은 DM 페어링 저장소 승인을 상속하지 **않습니다**.
페어링은 DM 전용으로 유지됩니다. 그룹의 경우 `groupAllowFrom` 또는 그룹별/주제`allowFrom`을 설정하세요.
`groupAllowFrom`이 설정되지 않은 경우 Telegram은 페어링 저장소가 아니라 구성의 `allowFrom`으로 폴백합니다.
단일 소유자 의 실용적인 패턴: 사용자 ID를 `channels.telegram.allowFrom`에 설정하고, `groupAllowFrom`은 설정하지 않은 채 대상 그룹을 `channels.telegram.groups` 아래에서 허용합니다.
런타임 참고: `channels.telegram`이 완전히 누락된 경우, `channels.defaults.groupPolicy`가 명시적으로 설정되어 있지 않으면 런타임은 fail-closed `groupPolicy="allowlist"`를 기본값으로 사용합니다.
Telegram 그룹 또는 슈퍼그룹 채팅 ID를 `groupAllowFrom`에 넣지 마세요. 음수 채팅 ID는 `channels.telegram.groups` 아래에 있어야 합니다.
숫자가 아닌 항목은 발신자 인에서 무시됩니다.
보안 경계(`2026.2.25+`): 그룹 발신자 인증은 DM pairing-store 승인을 상속하지 **않습니다**.
페어링은 DM 전용으로 유지됩니다. 그룹의 경우 `groupAllowFrom` 또는 그룹별/토픽`allowFrom`을 설정하세요.
`groupAllowFrom`이 설정되지 않은 경우 Telegram은 pairing store가 아니라 config `allowFrom`으로 폴백합니다.
단일 소유자 bot의 실용적인 패턴: 사용자 ID를 `channels.telegram.allowFrom`에 설정하고, `groupAllowFrom`은 설정하지 않은 채 대상 그룹을 `channels.telegram.groups` 아래에서 허용합니다.
런타임 참고: `channels.telegram`이 완전히 없으면, `channels.defaults.groupPolicy`가 명시적으로 설정되지 않는 한 런타임은 기본적으로 실패 시 닫힘 방식의 `groupPolicy="allowlist"` 사용합니다.
예시: 특정 그룹 하나 모든 멤버 허용:
예시: 특정 그룹 하나에서 모든 멤버 허용:
```json5
{
@ -193,7 +193,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
예시: 특정 그룹 하나에서 특정 사용자만 허용:
예시: 특정 그룹 하나에서 특정 사용자만 허용:
```json5
{
@ -211,11 +211,11 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
```
<Warning>
흔한 실수: `groupAllowFrom`은 Telegram 그룹 허용 목록이 아닙니다.
흔한 실수: `groupAllowFrom`은 Telegram 그룹 allowlist가 아닙니다.
- `-1001234567890` 같은 음수 Telegram 그룹 또는 슈퍼그룹 채팅 ID는 `channels.telegram.groups` 아래에 넣으세요.
- 허용된 그룹 안에서 어떤 사람이 을 트리거할 수 있는지 제한하려면 `8734062810` 같은 Telegram 사용자 ID를 `groupAllowFrom` 아래에 넣으세요.
- 허용된 그룹의 모든 멤버가 봇과 대화할 수 있게 하려는 경우에만 `groupAllowFrom: ["*"]` 사용하세요.
- 허용된 그룹 안에서 어떤 사람이 bot을 트리거할 수 있는지 제한하려면 `8734062810` 같은 Telegram 사용자 ID를 `groupAllowFrom` 아래에 넣으세요.
- 허용된 그룹의 모든 멤버가 bot과 대화할 수 있게 하려는 경우에만 `groupAllowFrom: ["*"]` 사용하세요.
</Warning>
@ -236,9 +236,9 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `/activation always`
- `/activation mention`
는 세션 상태만 업데이트합니다. 지속하려면 구성을 사용하세요.
항목들은 세션 상태만 업데이트합니다. 지속성을 위해서는 config를 사용하세요.
지속 구성 예시:
지속 config 예시:
```json5
{
@ -255,7 +255,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
그룹 채팅 ID 가져오기:
- 그룹 메시지를 `@userinfobot` / `@getidsbot`으로 전달
- 또는 `openclaw logs --follow`에서 `chat.id` 읽기
- 또는 `openclaw logs --follow`에서 `chat.id` 확인
- 또는 Bot API `getUpdates` 검사
</Tab>
@ -265,31 +265,32 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- Telegram은 Gateway 프로세스가 소유합니다.
- 라우팅은 결정적입니다. Telegram 인바운드는 Telegram으로 답장합니다(모델이 채널을 선택하지 않음).
- 인바운드 메시지는 답장 메타데이터와 미디어 플레이스홀더가 포함된 공유 채널 엔벌로프로 정규화됩니다.
- 그룹 세션은 그룹 ID로 격리됩니다. 포럼 주제는 주제를 격리하기 위해 `:topic:<threadId>`를 추가합니다.
- DM 메시지는 `message_thread_id`를 포함할 수 있습니다. OpenClaw는 답장을 위해 스레드 ID를 보존하지만 기본적으로 DM은 플랫 세션에 유지합니다. 의도적으로 DM 주제 세션 격리를 원할 때는 `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct.<chatId>.threadReplies: "inbound"`, `requireTopic: true` 또는 일치하는 주제 구성을 설정하세요.
- 롱 폴링은 채팅별/스레드별 순서를 적용하는 grammY runner를 사용합니다. 전체 runner sink 동시성은 `agents.defaults.maxConcurrent`를 사용합니다.
- 롱 폴링은 각 Gateway 프로세스 내부에서 보호되므로 한 번에 하나의 활성 poller만 봇 토큰을 사용할 수 있습니다. 그래도 `getUpdates` 409 충돌이 보인다면 다른 OpenClaw Gateway, 스크립트 또는 외부 poller가 같은 토큰을 사용 중일 가능성이 큽니다.
- 롱 폴링 watchdog 재시작은 기본적으로 완료된 `getUpdates` 활성 신호가 120초 동안 없을 때 트리거됩니다. 배포 환경에서 장시간 실행 작업 중 잘못된 polling-stall 재시작이 계속 발생하는 경우에만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 값은 밀리초 단위이며 `30000`부터 `600000`까지 허용됩니다. 계정별 오버라이드가 지원됩니다.
- 인바운드 메시지는 답장 메타데이터와 미디어 placeholder가 포함된 공유 채널 envelope로 정규화됩니다.
- 그룹 세션은 그룹 ID별로 격리됩니다. 포럼 토픽은 토픽을 격리하기 위해 `:topic:<threadId>`를 덧붙입니다.
- DM 메시지는 `message_thread_id`를 포함할 수 있습니다. OpenClaw는 답장용 스레드 ID를 보존하지만, 기본적으로 DM은 평면 세션으로 유지합니다. DM 토픽 세션 격리를 의도적으로 원하는 경우 `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct.<chatId>.threadReplies: "inbound"`, `requireTopic: true` 또는 일치하는 토픽 config를 구성하세요.
- Long polling은 채팅별/스레드별 순서를 보장하는 grammY runner를 사용합니다. 전체 runner sink 동시성은 `agents.defaults.maxConcurrent`를 사용합니다.
- Long polling은 각 Gateway 프로세스 내부에서 보호되어 한 번에 하나의 활성 poller만 bot 토큰을 사용할 수 있습니다. 여전히 `getUpdates` 409 충돌이 보인다면, 다른 OpenClaw Gateway, 스크립트 또는 외부 poller가 같은 토큰을 사용 중일 가능성이 큽니다.
- Long-polling watchdog 재시작은 기본적으로 완료된 `getUpdates` 활성 상태가 120초 동안 없으면 트리거됩니다. 장시간 실행 작업 중에도 배포 환경에서 잘못된 polling-stall 재시작이 계속 보이는 경우에만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 값은 밀리초 단위이며 `30000`부터 `600000`까지 허용됩니다. 계정별 재정의가 지원됩니다.
- Telegram Bot API는 읽음 확인을 지원하지 않습니다(`sendReadReceipts`는 적용되지 않음).
## 기능 참
## 기능 참
<AccordionGroup>
<Accordion title="실시간 스트림 미리보기(메시지 편집)">
<Accordion title="라이브 스트림 미리보기(메시지 편집)">
OpenClaw는 부분 답장을 실시간으로 스트리밍할 수 있습니다.
- 직접 채팅: 미리보기 메시지 + `editMessageText`
- 그룹/주제: 미리보기 메시지 + `editMessageText`
- 그룹/토픽: 미리보기 메시지 + `editMessageText`
요구 사항:
- `channels.telegram.streaming``off | partial | block | progress`입니다(기본값: `partial`)
- `progress`는 편집 가능한 상태 초안 하나를 유지하고 최종 전달 전까지 도구 진행 상황으로 업데이트합니다.
- `streaming.preview.toolProgress`는 도구/진행 상황 업데이트가 같은 편집된 미리보기 메시지를 재사용할지 제어합니다(기본값: 미리보기 스트리밍이 활성화된 경우 `true`).
- 기존 `channels.telegram.streamMode`와 불리언 `streaming` 값은 감지됩니다. `openclaw doctor --fix`를 실행해 `channels.telegram.streaming.mode`로 마이그레이션하세요.
- `progress`는 편집 가능한 상태 초안 하나를 유지하고 최종 전달 전까지 도구 진행 상황으로 업데이트합니다
- `streaming.preview.toolProgress`는 도구/진행 상황 업데이트가 동일한 편집된 미리보기 메시지를 재사용할지 제어합니다(미리보기 스트리밍이 활성일 때 기본값: `true`)
- `streaming.preview.commandText`는 해당 도구 진행 줄 내부의 command/exec 세부 정보를 제어합니다. `raw`(기본값, 릴리스된 동작 보존) 또는 `status`(도구 레이블만)
- 기존 `channels.telegram.streamMode` 및 boolean `streaming` 값은 감지됩니다. 이를 `channels.telegram.streaming.mode`로 마이그레이션하려면 `openclaw doctor --fix`를 실행하세요
도구 진행 상황 미리보기 업데이트는 도구가 실행되는 동안 표시되는 짧은 상태 줄입니다. 예를 들어 명령 실행, 파일 읽기, 계획 업데이트 또는 패치 요약이 있습니다. Telegram은 `v2026.4.22` 및 이후 버전의 릴리스된 OpenClaw 동작과 일치하도록 기본적으로 이를 활성화합니다. 답변 텍스트용 편집 미리보기는 유지하되 도구 진행 상황 줄을 숨기려면 다음을 설정하세요.
도구 진행 미리보기 업데이트는 도구가 실행되는 동안 표시되는 짧은 상태 줄입니다. 예를 들어 명령 실행, 파일 읽기, 계획 업데이트 또는 패치 요약이 있습니다. Telegram은 `v2026.4.22` 및 이후 버전의 릴리스된 OpenClaw 동작과 일치하도록 기본적으로 이를 활성화합니다. 답변 텍스트용 편집 미리보기는 유지하되 도구 진행 줄을 숨기려면 다음과 같이 설정하세요.
```json
{
@ -306,47 +307,82 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
`streaming.mode: "off"`는 최종 응답만 전달하려는 경우에만 사용하세요. Telegram 미리 보기 편집이 비활성화되고, 일반 도구/진행 상황 잡담은 독립 상태 메시지로 전송되는 대신 억제됩니다. 승인 프롬프트, 미디어 페이로드, 오류는 여전히 일반 최종 전달 경로를 통해 라우팅됩니다. 도구 진행 상태 줄은 숨기면서 답변 미리 보기 편집만 유지하려면 `streaming.preview.toolProgress: false`를 사용하세요.
도구 진행은 표시하되 command/exec 텍스트는 숨기려면 다음과 같이 설정하세요.
```json
{
"channels": {
"telegram": {
"streaming": {
"mode": "partial",
"preview": {
"commandText": "status"
}
}
}
}
}
```
진행 초안 모드의 경우 동일한 명령 텍스트 정책을 `streaming.progress` 아래에 넣으세요.
```json
{
"channels": {
"telegram": {
"streaming": {
"mode": "progress",
"progress": {
"toolProgress": true,
"commandText": "status"
}
}
}
}
}
```
최종 응답만 전달하려는 경우에만 `streaming.mode: "off"`를 사용하세요. Telegram 미리보기 편집은 비활성화되고, 일반 도구/진행 잡담은 독립 상태 메시지로 전송되는 대신 억제됩니다. 승인 프롬프트, 미디어 페이로드, 오류는 여전히 일반 최종 전달 경로를 통해 라우팅됩니다. 도구 진행 상태 줄을 숨기면서 답변 미리보기 편집만 유지하려면 `streaming.preview.toolProgress: false`를 사용하세요.
<Note>
Telegram 선택 인용 답장은 예외입니다. `replyToMode``"first"`, `"all"` 또는 `"batched"`이고 인바운드 메시지에 선택된 인용 텍스트가 포함된 경우, OpenClaw는 답변 미리 보기를 편집하는 대신 Telegram의 네이티브 인용 답장 경로를 통해 최종 답변을 전송하므로 `streaming.preview.toolProgress`는 해당 턴의 짧은 상태 줄을 표시할 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 답장은 계속 미리 보기 스트리밍을 유지합니다. 도구 진행 상황 표시가 네이티브 인용 답장보다 더 중요하면 `replyToMode: "off"`를 설정하거나, 이 절충을 인정하려면 `streaming.preview.toolProgress: false`를 설정하세요.
Telegram 선택 인용 답은 예외입니다. `replyToMode``"first"`, `"all"` 또는 `"batched"`이고 인바운드 메시지에 선택된 인용 텍스트가 포함된 경우, OpenClaw는 답변 미리보기를 편집하는 대신 Telegram의 네이티브 인용 답글 경로를 통해 최종 답변을 전송하므로, 해당 턴에서는 `streaming.preview.toolProgress` 짧은 상태 줄을 표시할 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 답글은 미리보기 스트리밍을 계속 유지합니다. 도구 진행 표시가 네이티브 인용 답글보다 더 중요하면 `replyToMode: "off"`를 설정하거나, 이 절충을 인정하려면 `streaming.preview.toolProgress: false`를 설정하세요.
</Note>
텍스트 전용 답장의 경우:
텍스트 전용 답의 경우:
- 짧은 DM/그룹/토픽 미리 보기: 미리 보기가 나타난 뒤 보이는 비미리 보기 메시지가 전송되지 않은 한, OpenClaw는 같은 미리 보기 메시지를 유지하고 제자리에서 최종 편집을 수행합니다.
- 미리 보기 뒤에 보이는 비미리 보기 출력이 이어지는 경우: OpenClaw는 완료된 답장을 새 최종 메시지로 전송하고 이전 미리 보기를 정리하므로, 최종 답변은 중간 출력 뒤에 표시됩니다.
- 약 1분보다 오래된 미리 보기: OpenClaw는 완료된 답장을 새 최종 메시지로 전송한 다음 미리 보기를 정리하므로, Telegram의 표시 타임스탬프는 미리 보기 생성 시간이 아니라 완료 시간을 반영합니다.
- 짧은 DM/그룹/토픽 미리보기: 미리보기가 나타난 뒤 표시되는 비미리보기 메시지가 전송되지 않았다면 OpenClaw는 동일한 미리보기 메시지를 유지하고 제자리에서 최종 편집을 수행합니다
- 표시되는 비미리보기 출력 뒤의 미리보기: OpenClaw는 완료된 답글을 새 최종 메시지로 전송하고 이전 미리보기를 정리하므로, 최종 답변이 중간 출력 뒤에 나타납니다
- 약 1분보다 오래된 미리보기: OpenClaw는 완료된 답글을 새 최종 메시지로 전송한 뒤 미리보기를 정리하므로, Telegram의 표시 타임스탬프가 미리보기 생성 시간이 아니라 완료 시간을 반영합니다
복잡한 답장(예: 미디어 페이로드)의 경우, OpenClaw는 일반 최종 전달 방식으로 폴백한 다음 미리 보기 메시지를 정리합니다.
복잡한 답글(예: 미디어 페이로드)의 경우 OpenClaw는 일반 최종 전달로 대체한 뒤 미리보기 메시지를 정리합니다.
미리 보기 스트리밍은 블록 스트리밍과 별개입니다. Telegram에서 블록 스트리밍이 명시적으로 활성화된 경우, OpenClaw는 이중 스트리밍을 피하기 위해 미리 보기 스트림을 건너뜁니다.
미리보기 스트리밍은 블록 스트리밍과 별개입니다. Telegram에 대해 블록 스트리밍이 명시적으로 활성화되어 있으면 OpenClaw는 이중 스트리밍을 피하기 위해 미리보기 스트림을 건너뜁니다.
Telegram 전용 추론 스트림:
- `/reasoning stream`은 생성 중 추론을 실시간 미리 보기에 전송합니다.
- 최종 전달 후 추론 미리 보기는 삭제됩니다. 추론을 계속 표시해야 하면 `/reasoning on`을 사용하세요.
- 최종 답변은 추론 텍스트 없이 전송됩니다.
- `/reasoning stream`은 생성 중 추론을 실시간 미리보기로 전송합니다
- 추론 미리보기는 최종 전달 후 삭제됩니다. 추론을 계속 표시해야 하면 `/reasoning on`을 사용하세요
- 최종 답변은 추론 텍스트 없이 전송됩니다
</Accordion>
<Accordion title="Formatting and HTML fallback">
<Accordion title="서식 지정 및 HTML 대체">
아웃바운드 텍스트는 Telegram `parse_mode: "HTML"`을 사용합니다.
- Markdown과 유사한 텍스트는 Telegram에 안전한 HTML로 렌더링됩니다.
- Markdown 스타일 텍스트는 Telegram에 안전한 HTML로 렌더링됩니다.
- 원시 모델 HTML은 Telegram 파싱 실패를 줄이기 위해 이스케이프됩니다.
- Telegram이 파싱된 HTML을 거부하면 OpenClaw는 일반 텍스트로 다시 시도합니다.
링크 미리 보기는 기본적으로 활성화되며 `channels.telegram.linkPreview: false`로 비활성화할 수 있습니다.
링크 미리보기는 기본적으로 활성화되어 있으`channels.telegram.linkPreview: false`로 비활성화할 수 있습니다.
</Accordion>
<Accordion title="Native commands and custom commands">
<Accordion title="네이티브 명령 및 사용자 지정 명령">
Telegram 명령 메뉴 등록은 시작 시 `setMyCommands`로 처리됩니다.
네이티브 명령 기본값:
- `commands.native: "auto"`는 Telegram에서 네이티브 명령을 활성화합니다.
- `commands.native: "auto"`는 Telegram에 대해 네이티브 명령을 활성화합니다
사용자 지정 명령 메뉴 항목 추가:
@ -365,47 +401,47 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
규칙:
- 이름은 정규화됩니다(앞의 `/` 제거, 소문자화).
- 이름은 정규화됩니다(앞의 `/` 제거, 소문자화)
- 유효한 패턴: `a-z`, `0-9`, `_`, 길이 `1..32`
- 사용자 지정 명령은 네이티브 명령을 재정의할 수 없습니다.
- 충돌/중복은 건너뛰고 기록됩니다.
- 사용자 지정 명령은 네이티브 명령을 재정의할 수 없습니다
- 충돌/중복은 건너뛰고 로그에 기록됩니다
참고:
- 사용자 지정 명령은 메뉴 항목일 뿐이며, 동작을 자동으로 구현하지 않습니다.
- Plugin/skill 명령은 Telegram 메뉴에 표시되지 않더라도 입력하면 계속 작동할 수 있습니다.
- 사용자 지정 명령은 메뉴 항목일 뿐이며, 동작을 자동으로 구현하지 않습니다
- Telegram 메뉴에 표시되지 않더라도 Plugin/Skills 명령은 입력 시 계속 작동할 수 있습니다
네이티브 명령이 비활성화된 경우, 기본 제공 명령은 제거됩니다. 구성된 경우 사용자 지정/Plugin 명령은 계속 등록될 수 있습니다.
네이티브 명령이 비활성화되면 기본 제공 항목이 제거됩니다. 구성된 경우 사용자 지정/Plugin 명령은 여전히 등록될 수 있습니다.
일반적인 설정 실패:
- `BOT_COMMANDS_TOO_MUCH`와 함께 `setMyCommands failed`가 표시되면, 잘라낸 뒤에도 Telegram 메뉴가 여전히 넘쳤다는 뜻입니다. Plugin/skill/사용자 지정 명령을 줄이거나 `channels.telegram.commands.native`를 비활성화하세요.
- 직접 Bot API curl 명령은 작동하지만 `deleteWebhook`, `deleteMyCommands` 또는 `setMyCommands``404: Not Found`로 실패하면 `channels.telegram.apiRoot`가 전체 `/bot<TOKEN>` 엔드포인트로 설정되었을 수 있습니다. `apiRoot`는 Bot API 루트만이어야 하며, `openclaw doctor --fix`는 실수로 붙은 뒤쪽 `/bot<TOKEN>`을 제거합니다.
- `getMe returned 401`은 Telegram이 구성된 봇 토큰을 거부했다는 뜻입니다. `botToken`, `tokenFile` 또는 `TELEGRAM_BOT_TOKEN`현재 BotFather 토큰으로 업데이트하세요. OpenClaw는 폴링 전에 중지하므로 이것은 Webhook 정리 실패로 보고되지 않습니다.
- 네트워크/페치 오류와 함께 `setMyCommands failed`가 표시되면 일반적으로 `api.telegram.org`의 아웃바운드 DNS/HTTPS가 차단되었다는 뜻입니다.
- `BOT_COMMANDS_TOO_MUCH`와 함께 `setMyCommands failed`가 표시되면 정리 후에도 Telegram 메뉴가 여전히 초과되었다는 뜻입니다. Plugin/Skills/사용자 지정 명령을 줄이거나 `channels.telegram.commands.native`를 비활성화하세요.
- 직접 Bot API curl 명령은 작동하는데 `deleteWebhook`, `deleteMyCommands` 또는 `setMyCommands``404: Not Found`로 실패하면 `channels.telegram.apiRoot`가 전체 `/bot<TOKEN>` 엔드포인트로 설정되었을 수 있습니다. `apiRoot`는 Bot API 루트만이어야 하며, `openclaw doctor --fix`는 실수로 붙은 후행 `/bot<TOKEN>`을 제거합니다.
- `getMe returned 401`은 Telegram이 구성된 봇 토큰을 거부했다는 뜻입니다. 현재 BotFather 토큰으로 `botToken`, `tokenFile` 또는 `TELEGRAM_BOT_TOKEN`을 업데이트하세요. OpenClaw는 폴링 전에 중지되므로 이는 Webhook 정리 실패로 보고되지 않습니다.
- 네트워크/fetch 오류와 함께 `setMyCommands failed`가 표시되면 일반적으로 `api.telegram.org` 나가는 DNS/HTTPS가 차단되었다는 뜻입니다.
### 기기 페어링 명령(`device-pair` Plugin)
`device-pair` Plugin이 설치된 경우:
1. `/pair`가 설정 코드를 생성합니다.
2. iOS 앱에 코드를 붙여넣습니다.
3. `/pair pending`은 대기 중인 요청(역할/스코프 포함)을 나열합니다.
4. 요청을 승인합니다.
- 명시적 승인 `/pair approve <requestId>`
1. `/pair`는 설정 코드를 생성합니다
2. iOS 앱에 코드를 붙여 넣습니다
3. `/pair pending`은 대기 중인 요청을 나열합니다(역할/범위 포함)
4. 요청을 승인합니다:
- 명시적 승인에는 `/pair approve <requestId>`
- 대기 중인 요청이 하나뿐이면 `/pair approve`
- 가장 최근 요청 `/pair approve latest`
- 가장 최근 요청에는 `/pair approve latest`
설정 코드는 수명이 짧은 부트스트랩 토큰을 포함합니다. 기본 제공 부트스트랩 인계는 기본 Node 토큰을 `scopes: []`로 유지합니다. 인계된 모든 운영자 토큰은 `operator.approvals`, `operator.read`, `operator.talk.secrets`, `operator.write`로 제한됩니다. 부트스트랩 스코프 검사는 역할 접두사를 사용하므로 해당 운영자 허용 목록은 운영자 요청만 충족합니다. 비운영자 역할은 여전히 자체 역할 접두사 아래의 스코프가 필요합니다.
설정 코드는 수명이 짧은 부트스트랩 토큰을 전달합니다. 기본 제공 부트스트랩 인계는 기본 노드 토큰을 `scopes: []`로 유지합니다. 인계된 모든 운영자 토큰은 `operator.approvals`, `operator.read`, `operator.talk.secrets`, `operator.write`로 제한됩니다. 부트스트랩 범위 검사는 역할 접두사가 붙으므로, 해당 운영자 허용 목록은 운영자 요청만 충족합니다. 비운영자 역할은 여전히 자체 역할 접두사 아래의 범위가 필요합니다.
기기가 변경된 인증 세부 정보(예: 역할/스코프/공개 키)로 다시 시도하면 이전 대기 요청은 대체되고 새 요청은 다른 `requestId`를 사용합니다. 승인하기 전에 `/pair pending`을 다시 실행하세요.
기기가 변경된 인증 세부 정보(예: 역할/범위/공개 키)로 다시 시도하면 이전 대기 요청은 대체되고 새 요청은 다른 `requestId`를 사용합니다. 승인하기 전에 `/pair pending`을 다시 실행하세요.
자세한 내용: [페어링](/ko/channels/pairing#pair-via-telegram-recommended-for-ios).
</Accordion>
<Accordion title="Inline buttons">
인라인 키보드 스코프 구성:
<Accordion title="인라인 버튼">
인라인 키보드 범위 구성:
```json5
{
@ -437,7 +473,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
스코프:
범위:
- `off`
- `dm`
@ -445,9 +481,9 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `all`
- `allowlist`(기본값)
레거시 `capabilities: ["inlineButtons"]``inlineButtons: "all"`로 매핑됩니다.
기존 `capabilities: ["inlineButtons"]``inlineButtons: "all"`로 매핑됩니다.
메시지 작 예시:
메시지 작 예시:
```json5
{
@ -465,13 +501,13 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
콜백 클릭은 텍스트로 에이전트에 전달됩니다.
콜백 클릭은 텍스트로 에이전트에 전달됩니다:
`callback_data: <value>`
</Accordion>
<Accordion title="Telegram message actions for agents and automation">
Telegram 도구 작업에는 다음이 포함됩니다.
<Accordion title="에이전트 및 자동화를 위한 Telegram 메시지 동작">
Telegram 도구 동작에는 다음이 포함됩니다:
- `sendMessage`(`to`, `content`, 선택 사항 `mediaUrl`, `replyToMessageId`, `messageThreadId`)
- `react`(`chatId`, `messageId`, `emoji`)
@ -479,9 +515,9 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `editMessage`(`chatId`, `messageId`, `content`)
- `createForumTopic`(`chatId`, `name`, 선택 사항 `iconColor`, `iconCustomEmojiId`)
채널 메시지 작업은 인체공학적인 별칭(`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`)을 노출합니다.
채널 메시지 동작은 사용하기 쉬운 별칭(`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`)을 노출합니다.
게이 제어:
게이 제어:
- `channels.telegram.actions.sendMessage`
- `channels.telegram.actions.deleteMessage`
@ -489,47 +525,47 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `channels.telegram.actions.sticker`(기본값: 비활성화)
참고: `edit``topic-create`는 현재 기본적으로 활성화되어 있으며 별도의 `channels.telegram.actions.*` 토글이 없습니다.
런타임 전송은 활성 구성/시크릿 스냅샷(시작/다시 로드)을 사용하므로 작 경로는 전송마다 임시 SecretRef 재해석을 수행하지 않습니다.
런타임 전송은 활성 구성/비밀 스냅샷(시작/다시 로드)을 사용하므로, 작 경로는 전송마다 임시 SecretRef 재해석을 수행하지 않습니다.
반응 제거 의미 체계: [/tools/reactions](/ko/tools/reactions)
</Accordion>
<Accordion title="Reply threading tags">
Telegram은 생성된 출력에서 명시적 답장 스레딩 태그를 지원합니다.
<Accordion title="답글 스레딩 태그">
Telegram은 생성된 출력에서 명시적 답글 스레딩 태그를 지원합니다:
- `[[reply_to_current]]`는 트리거한 메시지에 답장합니다.
- `[[reply_to:<id>]]`는 특정 Telegram 메시지 ID에 답장합니다.
- `[[reply_to_current]]`는 트리거한 메시지에 답글을 답니다
- `[[reply_to:<id>]]`는 특정 Telegram 메시지 ID에 답글을 답니다
`channels.telegram.replyToMode`는 처리를 제어합니다.
`channels.telegram.replyToMode`는 처리를 제어합니다:
- `off`(기본값)
- `first`
- `all`
장 스레딩이 활성화되어 있고 원본 Telegram 텍스트 또는 캡션을 사용할 수 있으면, OpenClaw는 네이티브 Telegram 인용 발췌를 자동으로 포함합니다. Telegram은 네이티브 인용 텍스트를 1024 UTF-16 코드 단위로 제한하므로 더 긴 메시지는 시작 부분부터 인용되고 Telegram이 인용을 거부하면 일반 답장으로 폴백합니다.
글 스레딩이 활성화되어 있고 원래 Telegram 텍스트 또는 캡션을 사용할 수 있으면 OpenClaw는 네이티브 Telegram 인용 발췌를 자동으로 포함합니다. Telegram은 네이티브 인용 텍스트를 1024 UTF-16 코드 단위로 제한하므로, 더 긴 메시지는 시작 부분부터 인용되며 Telegram이 인용을 거부하면 일반 답글로 대체됩니다.
참고: `off`는 암시적 답 스레딩을 비활성화합니다. 명시적 `[[reply_to_*]]` 태그는 여전히 적용됩니다.
참고: `off`는 암시적 답 스레딩을 비활성화합니다. 명시적 `[[reply_to_*]]` 태그는 여전히 적용됩니다.
</Accordion>
<Accordion title="Forum topics and thread behavior">
<Accordion title="포럼 토픽 및 스레드 동작">
포럼 슈퍼그룹:
- 토픽 세션 키는 `:topic:<threadId>`추가합니다.
- 답장과 입력 중 표시는 토픽 스레드를 대상으로 합니다.
- 토픽 세션 키는 `:topic:<threadId>`덧붙입니다
- 답글 및 입력 상태는 토픽 스레드를 대상으로 합니다
- 토픽 구성 경로:
`channels.telegram.groups.<chatId>.topics.<threadId>`
일반 토픽(`threadId=1`) 특수 사례:
- 메시지 전송은 `message_thread_id`를 생략합니다(Telegram은 `sendMessage(...thread_id=1)`를 거부함).
- 입력 중 작업은 여전히 `message_thread_id`를 포함합니다.
- 메시지 전송은 `message_thread_id`를 생략합니다(Telegram은 `sendMessage(...thread_id=1)`을 거부합니다)
- 입력 동작은 여전히 `message_thread_id`를 포함합니다
토픽 상속: 토픽 항목은 재정의되지 않는 한 그룹 설정(`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`)을 상속합니다.
토픽 상속: 토픽 항목은 재정의되지 않는 한 그룹 설정을 상속합니다(`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`).
`agentId`는 토픽 전용이며 그룹 기본값에서 상속되지 않습니다.
**토픽별 에이전트 라우팅**: 각 토픽은 토픽 구성에서 `agentId`를 설정하여 다른 에이전트로 라우팅할 수 있습니다. 이렇게 하면 각 토픽은 자체 격리된 워크스페이스, 메모리, 세션을 갖습니다. 예시:
**토픽별 에이전트 라우팅**: 각 토픽은 토픽 구성에서 `agentId`를 설정하여 다른 에이전트로 라우팅할 수 있습니다. 이렇게 하면 각 토픽에 고유한 격리된 작업 공간, 메모리, 세션이 제공됩니다. 예시:
```json5
{
@ -549,26 +585,28 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
그러면 각 토픽은 자체 세션 키를 갖습니다. `agent:zu:telegram:group:-1001234567890:topic:3`
그러면 각 토픽에는 고유한 세션 키가 있습니다: `agent:zu:telegram:group:-1001234567890:topic:3`
**영구 ACP 토픽 바인딩**: 포럼 토픽은 최상위 타입 지정 ACP 바인딩(`type: "acp"`와 `match.channel: "telegram"`, `peer.kind: "group"``-1001234567890:topic:42` 같은 토픽 한정 ID를 포함하는 `bindings[]`)을 통해 ACP 하네스 세션을 고정할 수 있습니다. 현재 그룹/슈퍼그룹의 포럼 토픽으로 범위가 제한됩니다. [ACP 에이전트](/ko/tools/acp-agents)를 참조하세요.
**영구 ACP 토픽 바인딩**: 포럼 토픽은 최상위 형식화 ACP 바인딩(`type: "acp"` 및 `match.channel: "telegram"`, `peer.kind: "group"`, 그리고 `-1001234567890:topic:42`와 같은 토픽 한정 ID가 포함된 `bindings[]`)을 통해 ACP 하네스 세션을 고정할 수 있습니다. 현재 그룹/슈퍼그룹의 포럼 토픽으로 범위가 지정됩니다. [ACP 에이전트](/ko/tools/acp-agents)를 참조하세요.
**채팅에서 스레드 바인딩 ACP 생성**: `/acp spawn <agent> --thread here|auto`는 현재 토픽을 새 ACP 세션에 바인딩합니다. 후속 메시지는 해당 세션으로 직접 라우팅됩니다. OpenClaw는 생성 확인을 토픽 안에 고정합니다. `channels.telegram.threadBindings.spawnSessions`계속 활성화되어 있어야 합니다(기본값: `true`).
**채팅에서 스레드 바인딩 ACP 생성**: `/acp spawn <agent> --thread here|auto`는 현재 토픽을 새 ACP 세션에 바인딩합니다. 후속 메시지는 그곳으로 직접 라우팅됩니다. OpenClaw는 생성 확인을 토픽 안에 고정합니다. `channels.telegram.threadBindings.spawnSessions`활성화된 상태로 유지되어야 합니다(기본값: `true`).
템플릿 컨텍스트는 `MessageThreadId``IsForum`을 노출합니다. `message_thread_id`가 있는 DM 채팅은 기본적으로 플랫 세션에서 DM 라우팅과 답장 메타데이터를 유지합니다. `threadReplies: "inbound"`, `threadReplies: "always"`, `requireTopic: true` 또는 일치하는 토픽 구성으로 설정된 경우에만 스레드 인식 세션 키를 사용합니다. 계정 기본값에는 최상위 `channels.telegram.dm.threadReplies`를 사용하거나, 단일 DM에는 `direct.<chatId>.threadReplies`를 사용하세요.
템플릿 컨텍스트는 `MessageThreadId``IsForum`을 노출합니다. `message_thread_id`가 있는 DM 채팅은 기본적으로 플랫 세션에서 DM 라우팅과 답장 메타데이터를 유지합니다. `threadReplies: "inbound"`, `threadReplies: "always"`, `requireTopic: true` 또는 일치하는 토픽 설정으로 구성된 경우에만 스레드를 인식하는 세션 키를 사용합니다. 계정 기본값에는 최상위 `channels.telegram.dm.threadReplies`를 사용하고, 특정 DM 하나에는 `direct.<chatId>.threadReplies`를 사용하세요.
</Accordion>
<Accordion title="Audio, video, and stickers">
<Accordion title="오디오, 비디오, 스티커">
### 오디오 메시지
Telegram은 음성 메모와 오디오 파일을 구분합니다.
- 기본값: 오디오 파일 동작
- 음성 메모 전송을 강제하려면 에이전트 답장에 `[[audio_as_voice]]` 태그를 사용하세요.
- 인바운드 음성 메모 전사는 에이전트 컨텍스트에서 기계 생성의 신뢰할 수 없는 텍스트로 프레이밍됩니다. 멘션 감지는 여전히 원시 전사를 사용하므로 멘션 게이트 음성 메시지는 계속 작동합니다.
- 에이전트 답장에 태그 `[[audio_as_voice]]`를 넣으면 음성 메모 전송을 강제합니다.
- 수신 음성 메모의 전사는 에이전트 컨텍스트에서 기계 생성,
신뢰할 수 없는 텍스트로 구성됩니다. 멘션 감지는 여전히 원시
전사를 사용하므로 멘션으로 제한된 음성 메시지는 계속 작동합니다.
메시지 작업 예시:
메시지 액션 예시:
```json5
{
@ -580,11 +618,11 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
### 동영상 메시지
### 비디오 메시지
Telegram은 동영상 파일과 동영상 노트를 구분합니다.
Telegram은 비디오 파일과 비디오 메모를 구분합니다.
메시지 작업 예시:
메시지 액션 예시:
```json5
{
@ -596,15 +634,15 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
동영상 노트는 캡션을 지원하지 않으며, 제공된 메시지 텍스트는 별도로 전송됩니다.
비디오 메모는 캡션을 지원하지 않습니다. 제공된 메시지 텍스트는 별도로 전송됩니다.
### 스티커
인바운드 스티커 처리:
수신 스티커 처리:
- 정적 WEBP: 다운로드 및 처리됨(자리표시자 `<media:sticker>`)
- 정적 WEBP: 다운로드 후 처리됨(플레이스홀더 `<media:sticker>`)
- 애니메이션 TGS: 건너뜀
- 동영상 WEBM: 건너뜀
- 비디오 WEBM: 건너뜀
스티커 컨텍스트 필드:
@ -618,9 +656,9 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `~/.openclaw/telegram/sticker-cache.json`
스티커는 가능한 경우 한 번 설명되고, 반복되는 비전 호출을 줄이기 위해 캐시됩니다.
스티커는 한 번 설명되고(가능한 경우) 반복적인 비전 호출을 줄이기 위해 캐시됩니다.
스티커 작업 활성화:
스티커 액션 활성화:
```json5
{
@ -634,7 +672,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
스티커 작업 전송:
스티커 액션 전송:
```json5
{
@ -659,7 +697,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
</Accordion>
<Accordion title="반응 알림">
Telegram 반응은 `message_reaction` 업데이트로 도착합니다(메시지 페이로드와 별).
Telegram 반응은 `message_reaction` 업데이트로 도착합니다(메시지 페이로드와 별).
활성화되면 OpenClaw는 다음과 같은 시스템 이벤트를 큐에 넣습니다.
@ -672,25 +710,25 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
참고:
- `own`은 봇이 보낸 메시지에 대한 사용자 반응만 의미합니다(전송 메시지 캐시를 통한 최선의 처리).
- 반응 이벤트는 여전히 Telegram 접근 제어(`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`)를 따르며, 권한이 없는 발신자는 제외됩니다.
- `own`은 봇이 보낸 메시지에 대한 사용자 반응만 의미합니다(보낸 메시지 캐시를 통한 최선 노력).
- 반응 이벤트 Telegram 접근 제어(`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`)를 따릅니다. 권한이 없는 발신자는 삭제됩니다.
- Telegram은 반응 업데이트에서 스레드 ID를 제공하지 않습니다.
- 포럼이 아닌 그룹은 그룹 채팅 세션으로 라우팅됩니다.
- 포럼 그룹은 그룹 채팅 세션으로 라우팅됩니다.
- 포럼 그룹은 정확한 원래 토픽이 아니라 그룹 일반 토픽 세션(`:topic:1`)으로 라우팅됩니다.
폴링/Webhook용 `allowed_updates`에는 `message_reaction`이 자동으로 포함됩니다.
</Accordion>
<Accordion title="확인 반응">
`ackReaction`은 OpenClaw가 인바운드 메시지를 처리하는 동안 확인 이모지를 보냅니다.
<Accordion title="Ack 반응">
`ackReaction`은 OpenClaw가 수신 메시지를 처리하는 동안 확인 이모지를 보냅니다.
확인 순서:
해석 순서:
- `channels.telegram.accounts.<accountId>.ackReaction`
- `channels.telegram.ackReaction`
- `messages.ackReaction`
- 에이전트 ID 이모지 폴백(`agents.list[].identity.emoji`, 없으면 "👀")
- 에이전트 ID 이모지 대체값(`agents.list[].identity.emoji`, 없으면 "👀")
참고:
@ -699,7 +737,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
</Accordion>
<Accordion title="Telegram 이벤트 명령에서 설정 쓰기">
<Accordion title="Telegram 이벤트 명령에서 설정 쓰기">
채널 설정 쓰기는 기본적으로 활성화되어 있습니다(`configWrites !== false`).
Telegram으로 트리거되는 쓰기에는 다음이 포함됩니다.
@ -722,29 +760,29 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
</Accordion>
<Accordion title="롱 폴링과 Webhook">
기본값은 롱 폴링입니다. Webhook 모드의 경우 `channels.telegram.webhookUrl``channels.telegram.webhookSecret`을 설정하세요. 선택 사항은 `webhookPath`, `webhookHost`, `webhookPort`니다(기본값 `/telegram-webhook`, `127.0.0.1`, `8787`).
기본값은 롱 폴링입니다. Webhook 모드의 경우 `channels.telegram.webhookUrl``channels.telegram.webhookSecret`을 설정하세요. 선택 사항으로 `webhookPath`, `webhookHost`, `webhookPort`가 있습니다(기본값 `/telegram-webhook`, `127.0.0.1`, `8787`).
로컬 리스너는 `127.0.0.1:8787`에 바인딩됩니다. 공개 인그레스의 경우 로컬 포트 앞에 리버스 프록시를 두거나 의도적으로 `webhookHost: "0.0.0.0"`을 설정하세요.
Webhook 모드는 Telegram에 `200`을 반환하기 전에 요청 가드, Telegram 비밀 토큰, JSON 본문을 검증합니다.
그런 다음 OpenClaw는 롱 폴링에서 사용하는 것과 동일한 채팅별/토픽별 봇 레인을 통해 업데이트를 비동기적으로 처리하므로, 느린 에이전트 턴이 Telegram의 전달 ACK를 붙잡지 않습니다.
그런 다음 OpenClaw는 롱 폴링에서 사용하는 동일한 채팅별/토픽별 봇 레인을 통해 업데이트를 비동기적으로 처리하므로 느린 에이전트 턴이 Telegram의 전달 ACK를 붙잡지 않습니다.
</Accordion>
<Accordion title="제한, 재시도 CLI 대상">
<Accordion title="제한, 재시도, CLI 대상">
- `channels.telegram.textChunkLimit` 기본값은 4000입니다.
- `channels.telegram.chunkMode="newline"`은 길이 분할 전에 단 경계(빈 줄)를 우선합니다.
- `channels.telegram.mediaMaxMb`(기본값 100)는 인바운드 및 아웃바운드 Telegram 미디어 크기를 제한합니다.
- `channels.telegram.mediaGroupFlushMs`(기본값 500)는 OpenClaw가 Telegram 앨범/미디어 그룹을 하나의 인바운드 메시지로 디스패치하기 전에 버퍼링하는 시간을 제어합니다. 앨범 일부가 늦게 도착하면 늘리고, 앨범 답장 지연 시간을 줄이려면 줄이세요.
- `channels.telegram.timeoutSeconds`는 Telegram API 클라이언트 타임아웃을 재정의합니다(설정하지 않으면 grammY 기본값 적용). 봇 클라이언트는 설정된 값을 60초 아웃바운드 텍스트/타이핑 요청 가드보다 낮게 제한하여, OpenClaw의 전송 가드와 폴백이 실행되기 전에 grammY가 표시 가능한 답장 전달을 중단하지 않도록 합니다. 롱 폴링은 여전히 45초 `getUpdates` 요청 가드를 사용하므로 유휴 폴이 무기한 방치되지 않습니다.
- `channels.telegram.pollingStallThresholdMs`의 기본값은 `120000`입니다. 거짓 양성 폴링 정지 재시작에 대해서만 `30000`에서 `600000` 사이로 조정하세요.
- 그룹 컨텍스트 기록은 `channels.telegram.historyLimit` 또는 `messages.groupChat.historyLimit`(기본값 50)을 사용합니다. `0`은 비활성화합니다.
- `channels.telegram.chunkMode="newline"`은 길이 분할 전에 단 경계(빈 줄)를 우선합니다.
- `channels.telegram.mediaMaxMb`(기본값 100)는 수신 및 발신 Telegram 미디어 크기를 제한합니다.
- `channels.telegram.mediaGroupFlushMs`(기본값 500)는 OpenClaw가 Telegram 앨범/미디어 그룹을 하나의 수신 메시지로 디스패치하기 전에 버퍼링하는 시간을 제어합니다. 앨범 일부가 늦게 도착하면 늘리고, 앨범 답장 지연 시간을 줄이려면 줄이세요.
- `channels.telegram.timeoutSeconds`는 Telegram API 클라이언트 타임아웃을 재정의합니다(설정하지 않으면 grammY 기본값 적용). 봇 클라이언트는 구성된 값이 60초 발신 텍스트/입력 중 요청 가드보다 낮으면 해당 가드 아래로 제한하여, OpenClaw의 전송 가드와 대체 처리가 실행되기 전에 grammY가 표시되는 답장 전달을 중단하지 않도록 합니다. 롱 폴링은 여전히 45초 `getUpdates` 요청 가드를 사용하므로 유휴 폴이 무기한 방치되지 않습니다.
- `channels.telegram.pollingStallThresholdMs` 기본값은 `120000`입니다. 잘못된 긍정 폴링 정지 재시작에 대해서만 `30000`에서 `600000` 사이로 조정하세요.
- 그룹 컨텍스트 기록은 `channels.telegram.historyLimit` 또는 `messages.groupChat.historyLimit`를 사용합니다(기본값 50). `0`은 비활성화합니다.
- 답장/인용/전달 보조 컨텍스트는 현재 수신된 그대로 전달됩니다.
- Telegram 허용 목록은 주로 누가 에이전트를 트리거할 수 있는지를 제한하며, 완전한 보조 컨텍스트 삭제 경계는 아닙니다.
- Telegram 허용 목록은 주로 에이전트를 트리거할 수 있는 사람을 제어하며, 전체 보조 컨텍스트 삭제 경계가 아닙니다.
- DM 기록 제어:
- `channels.telegram.dmHistoryLimit`
- `channels.telegram.dms["<user_id>"].historyLimit`
- `channels.telegram.retry` 설정은 복구 가능한 아웃바운드 API 오류에 대해 Telegram 전송 헬퍼(CLI/도구/작업)에 적용됩니다. 인바운드 최종 답장 전달도 Telegram 사전 연결 실패에 대해 제한된 안전 전송 재시도를 사용하지만, 표시 메시지를 중복할 수 있는 모호한 전송 후 네트워크 엔벌로프는 재시도하지 않습니다.
- `channels.telegram.retry` 설정은 복구 가능한 발신 API 오류에 대해 Telegram 전송 헬퍼(CLI/도구/액션)에 적용됩니다. 수신 최종 답장 전달도 Telegram 연결 전 실패에 대해 제한된 안전 전송 재시도를 사용하지만, 표시되는 메시지를 중복할 수 있는 모호한 전송 후 네트워크 봉투는 재시도하지 않습니다.
CLI 전송 대상은 숫자 채팅 ID 또는 사용자 이름일 수 있습니다.
@ -774,32 +812,32 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
- `channels.telegram.capabilities.inlineButtons`가 허용하는 경우 인라인 키보드용 `buttons` 블록과 함께 `--presentation`
- 봇이 해당 채팅에서 고정할 수 있을 때 고정 전달을 요청하는 `--pin` 또는 `--delivery '{"pin":true}'`
- 아웃바운드 이미지 및 GIF를 압축 사진 또는 애니메이션 미디어 업로드 대신 문서로 보내는 `--force-document`
- 발신 이미지와 GIF를 압축된 사진 또는 애니메이션 미디어 업로드 대신 문서로 보내는 `--force-document`
작업 게이팅:
액션 게이팅:
- `channels.telegram.actions.sendMessage=false`는 폴을 포함한 아웃바운드 Telegram 메시지를 비활성화합니다.
- `channels.telegram.actions.poll=false`는 일반 전송은 활성 상태로 둔 채 Telegram 폴 생성을 비활성화합니다.
- `channels.telegram.actions.sendMessage=false`는 폴을 포함해 발신 Telegram 메시지를 비활성화합니다.
- `channels.telegram.actions.poll=false`는 일반 전송을 활성화한 채 Telegram 폴 생성을 비활성화합니다.
</Accordion>
<Accordion title="Telegram의 실행 승인">
Telegram은 승인자 DM에서 실행 승인을 지원하며, 선택적으로 원래 채팅 또는 토픽에 프롬프트를 게시할 수 있습니다. 승인자는 숫자 Telegram 사용자 ID여야 합니다.
<Accordion title="Telegram의 Exec 승인">
Telegram은 승인자 DM에서 exec 승인을 지원하며, 선택적으로 원래 채팅이나 토픽에 프롬프트를 게시할 수 있습니다. 승인자는 숫자 Telegram 사용자 ID여야 합니다.
설정 경로:
- `channels.telegram.execApprovals.enabled`(확인 가능한 승인자가 하나 이상 있으면 자동 활성화)
- `channels.telegram.execApprovals.approvers`(`commands.ownerAllowFrom`의 숫자 소유자 ID로 폴백)
- `channels.telegram.execApprovals.approvers`(`commands.ownerAllowFrom`의 숫자 소유자 ID로 대체)
- `channels.telegram.execApprovals.target`: `dm`(기본값) | `channel` | `both`
- `agentFilter`, `sessionFilter`
`channels.telegram.allowFrom`, `groupAllowFrom`, `defaultTo`누가 봇과 대화할 수 있는지와 봇이 일반 답장을 어디로 보내는지를 제어합니다. 이것들이 누군가를 실행 승인자로 만들지는 않습니다. 아직 명령 소유자가 없을 때 첫 번째 승인된 DM 페어링은 `commands.ownerAllowFrom`을 부트스트랩하므로, 단일 소유자 설정은 `execApprovals.approvers` 아래에 ID를 중복하지 않아도 계속 작동합니다.
`channels.telegram.allowFrom`, `groupAllowFrom`, `defaultTo`봇과 대화할 수 있는 사람과 일반 답장을 보내는 위치를 제어합니다. 이것들이 누군가를 exec 승인자로 만들지는 않습니다. 아직 명령 소유자가 없을 때 처음 승인된 DM 페어링은 `commands.ownerAllowFrom`을 부트스트랩하므로, 단일 소유자 설정은 `execApprovals.approvers` 아래에 ID를 중복하지 않아도 계속 작동합니다.
채널 전달은 채팅에 명령 텍스트를 표시합니다. 신뢰할 수 있는 그룹/토픽에서만 `channel` 또는 `both`를 활성화하세요. 프롬프트가 포럼 토픽에 도착하면 OpenClaw는 승인 프롬프트와 후속 조치에 해당 토픽을 유지합니다. 실행 승인은 기본적으로 30분 후 만료됩니다.
채널 전달은 채팅에 명령 텍스트를 표시합니다. 신뢰할 수 있는 그룹/토픽에서만 `channel` 또는 `both`를 활성화하세요. 프롬프트가 포럼 토픽에 도착하면 OpenClaw는 승인 프롬프트와 후속 작업에 해당 토픽을 보존합니다. Exec 승인은 기본적으로 30분 후 만료됩니다.
인라인 승인 버튼도 `channels.telegram.capabilities.inlineButtons`대상 표면(`dm`, `group` 또는 `all`)을 허용해야 합니다. `plugin:` 접두사가 붙은 승인 ID는 Plugin 승인을 통해 확인되고, 그 외에는 먼저 실행 승인을 통해 확인됩니다.
인라인 승인 버튼도 대상 표면(`dm`, `group` 또는 `all`)을 허용하려면 `channels.telegram.capabilities.inlineButtons`필요합니다. `plugin:` 접두사가 있는 승인 ID는 Plugin 승인을 통해 해석되고, 그 외에는 exec 승인을 먼저 통해 해석됩니다.
[실행 승인](/ko/tools/exec-approvals)을 참조하세요.
[Exec 승인](/ko/tools/exec-approvals)을 참조하세요.
</Accordion>
</AccordionGroup>
@ -808,10 +846,10 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
에이전트가 전달 또는 제공자 오류를 만나면 Telegram은 오류 텍스트로 답장하거나 이를 억제할 수 있습니다. 두 설정 키가 이 동작을 제어합니다.
| 키 | 값 | 기본값 | 설명 |
| ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- |
| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply`는 채팅에 친한 오류 메시지를 보냅니다. `silent`는 오류 답장을 완전히 억제합니다. |
| `channels.telegram.errorCooldownMs` | 숫자(ms) | `60000` | 같은 채팅에 대한 오류 답장 간 최소 시간입니다. 장애 중 오류 스팸을 방지합니다. |
| 키 | 값 | 기본값 | 설명 |
| ----------------------------------- | ----------------- | ------- | ------------------------------------------------------------------------------------------------- |
| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply`는 채팅에 친한 오류 메시지를 보냅니다. `silent`는 오류 답장을 완전히 억제합니다. |
| `channels.telegram.errorCooldownMs` | 숫자(ms) | `60000` | 같은 채팅에 보내는 오류 답장 사이의 최소 시간입니다. 장애 중 오류 스팸을 방지합니다. |
계정별, 그룹별, 토픽별 재정의가 지원됩니다(다른 Telegram 설정 키와 동일한 상속).
@ -823,7 +861,7 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
errorCooldownMs: 120000,
groups: {
"-1001234567890": {
errorPolicy: "silent", // 이 그룹에서 오류 억제
errorPolicy: "silent", // suppress errors in this group
},
},
},
@ -834,56 +872,56 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
## 문제 해결
<AccordionGroup>
<Accordion title="봇이 멘션 없는 그룹 메시지에 응답하지 않음">
<Accordion title="봇이 멘션 없는 그룹 메시지에 응답하지 않음">
- `requireMention=false`인 경우 Telegram 개인정보 보호 모드 전체 가시성을 허용해야 합니다.
- BotFather: `/setprivacy` -> 비활성화
- 그런 다음 그룹에서 봇을 제거하고 다시 추가
- 설정이 멘션 없는 그룹 메시지를 기대할 때 `openclaw channels status`가 경고합니다.
- `openclaw channels status --probe`는 명시적인 숫자 그룹 ID를 확인할 수 있습니다. 와일드카드 `"*"`는 멤버십 프로브가 불가능합니다.
- `requireMention=false`인 경우 Telegram 개인정보 보호 모드 전체 가시성을 허용해야 합니다.
- BotFather: `/setprivacy` -> Disable
- 그런 다음 그룹에서 봇을 제거하고 다시 추가하세요.
- 설정이 멘션되지 않은 그룹 메시지를 기대할 때 `openclaw channels status`가 경고합니다.
- `openclaw channels status --probe`는 명시적인 숫자 그룹 ID를 확인할 수 있습니다. 와일드카드 `"*"`는 멤버십 프로브를 할 수 없습니다.
- 빠른 세션 테스트: `/activation always`.
</Accordion>
<Accordion title="봇이 그룹 메시지를 전혀 보지 못함">
- `channels.telegram.groups`가 있으면 그룹이 목록에 있어야 합니다(또는 `"*"` 포함).
- 그룹 봇 멤버십 확인
- 건너뛰기 이유는 로그 검토: `openclaw logs --follow`
- `channels.telegram.groups`가 있으면 그룹이 목록에 있어야 합니다(또는 `"*"` 포함)
- 그룹 봇 멤버십 확인
- 건너뛰기 사유를 보려면 로그 검토: `openclaw logs --follow`
</Accordion>
<Accordion title="명령이 부분적으로만 작동하거나 전혀 작동하지 않음">
- 발신자 ID 승인(페어링 및/또는 숫자 `allowFrom`)
- 그룹 정책이 `open`이어도 명령 권한 부여는 계속 적용됩니다.
- `BOT_COMMANDS_TOO_MUCH`와 함께 `setMyCommands failed`표시되면 네이티브 메뉴에 항목이 너무 많다는 뜻입니다. Plugin/Skill/사용자 지정 명령을 줄이거나 네이티브 메뉴를 비활성화하세요.
- `deleteMyCommands` / `setMyCommands` 시작 호출과 `sendChatAction` 타이핑 호출은 제한되며 요청 타임아웃 시 Telegram의 전송 폴백을 통해 한 번 재시도됩니다. 지속적인 네트워크/페치 오류는 보통 `api.telegram.org`에 대한 DNS/HTTPS 도달성 문제를 나타냅니다.
- 발신자 ID 승인(페어링 및/또는 숫자 `allowFrom`)
- 그룹 정책이 `open`이어도 명령 승인은 계속 적용됨
- `BOT_COMMANDS_TOO_MUCH`와 함께 `setMyCommands failed`발생하면 네이티브 메뉴 항목이 너무 많다는 뜻입니다. Plugin/스킬/사용자 지정 명령을 줄이거나 네이티브 메뉴를 비활성화하세요.
- 시작 시 `deleteMyCommands` / `setMyCommands` 호출과 `sendChatAction` 입력 표시 호출은 제한 시간이 정해져 있으며, 요청 제한 시간 초과 시 Telegram의 전송 대체 경로를 통해 한 번 재시도합니다. 지속적인 네트워크/가져오기 오류는 보통 `api.telegram.org`에 대한 DNS/HTTPS 도달성 문제를 나타냅니다.
</Accordion>
<Accordion title="시작 시 권한 없는 토큰 보고">
<Accordion title="시작 시 승인되지 않은 토큰이 보고됨">
- `getMe returned 401`은 구성된 봇 토큰에 대한 Telegram 인증 실패입니다.
- BotFather에서 봇 토큰을 다시 복사하거나 재생성한 다음, 기본 계정의 `channels.telegram.botToken`, `channels.telegram.tokenFile`, `channels.telegram.accounts.<id>.botToken` 또는 `TELEGRAM_BOT_TOKEN`을 업데이트하세요.
- 시작 중 `deleteWebhook 401 Unauthorized`도 인증 실패입니다. 이를 "webhook이 없음"으로 처리하면 동일한 잘못된 토큰 실패가 이후 API 호출로 미뤄질 뿐입니다.
- 시작 중 `deleteWebhook 401 Unauthorized`도 인증 실패입니다. 이를 "Webhook이 없음"으로 처리하면 동일한 잘못된 토큰 실패가 이후 API 호출로 지연될 뿐입니다.
</Accordion>
<Accordion title="폴링 또는 네트워크 불안정">
- Node 22+와 사용자 지정 fetch/proxy는 AbortSignal 타입이 일치하지 않으면 즉시 중단 동작을 유발할 수 있습니다.
- 일부 호스트는 `api.telegram.org`를 IPv6로 먼저 확인합니다. IPv6 송신이 손상되어 있으면 간헐적인 Telegram API 실패가 발생할 수 있습니다.
- 로그에 `TypeError: fetch failed` 또는 `Network request for 'getUpdates' failed!`가 포함되면 OpenClaw는 이제 이를 복구 가능한 네트워크 오류로 재시도합니다.
- 폴링 시작 중 OpenClaw는 grammY에 성공한 시작 `getMe` 프로브를 재사용하므로, 러너가 첫 `getUpdates` 전에 두 번째 `getMe`를 수행할 필요가 없습니다.
- 폴링 시작 중 일시적인 네트워크 오류로 `deleteWebhook`이 실패하면 OpenClaw는 다른 사전 폴링 제어 평면 호출을 만들지 않고 롱 폴링으로 계속 진행합니다. 아직 활성 상태인 webhook은 `getUpdates` 충돌로 나타납니다. 그러면 OpenClaw는 Telegram 전송을 다시 빌드하고 webhook 정리를 재시도합니다.
- Telegram 소켓이 짧은 고정 주기로 재활용된다면 낮은 `channels.telegram.timeoutSeconds` 값을 확인하세요. 봇 클라이언트는 구성된 값이 송신 및 `getUpdates` 요청 가드보다 낮으면 이를 제한하지만, 이전 릴리스에서는 이 값이 해당 가드보다 낮게 설정된 경우 모든 폴링이나 응답이 중단될 수 있었습니다.
- 로그에 `Polling stall detected`가 포함되면 OpenClaw는 기본적으로 완료된 롱 폴 활성 상태 없이 120초가 지난 뒤 폴링을 다시 시작하고 Telegram 전송을 다시 빌드합니다.
- `openclaw channels status --probe``openclaw doctor`는 실행 중인 폴링 계정이 시작 유예 `getUpdates`를 완료하지 않았거나, 실행 중인 webhook 계정이 시작 유예 후 `setWebhook`을 완료하지 않았거나, 마지막으로 성공한 폴링 전송 활동이 오래된 경우 경고합니다.
- 장시간 실행되는 `getUpdates` 호출은 정상인데도 호스트가 잘못된 폴링 중단 재시작을 계속 보고하는 경우에만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 지속적인 중단은 일반적으로 호스트와 `api.telegram.org` 사이의 proxy, DNS, IPv6 또는 TLS 송신 문제를 가리킵니다.
- Telegram은 Bot API 전송에 대해 `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`이들의 소문자 변형을 포함한 프로세스 proxy 환경 변수도 따릅니다. `NO_PROXY` / `no_proxy`는 여전히 `api.telegram.org`를 우회할 수 있습니다.
- 서비스 환경에서 OpenClaw 관리 proxy가 `OPENCLAW_PROXY_URL`을 통해 구성되어 있고 표준 proxy 환경 변수가 없으면, Telegram도 Bot API 전송에 해당 URL을 사용합니다.
- 직접 송신/TLS가 불안정한 VPS 호스트에서는 `channels.telegram.proxy`를 통해 Telegram API 호출을 라우팅하세요.
- Node 22+와 사용자 지정 fetch/proxy 조합은 AbortSignal 유형이 일치하지 않으면 즉시 중단 동작을 유발할 수 있습니다.
- 일부 호스트는 `api.telegram.org`를 IPv6로 먼저 해석합니다. 손상된 IPv6 송신은 간헐적인 Telegram API 실패를 일으킬 수 있습니다.
- 로그에 `TypeError: fetch failed` 또는 `Network request for 'getUpdates' failed!`가 포함되어 있으면 OpenClaw는 이제 이를 복구 가능한 네트워크 오류로 재시도합니다.
- 폴링 시작 중 OpenClaw는 성공한 시작 `getMe` 프로브를 grammY에 재사용하므로 러너가 첫 `getUpdates` 전에 두 번째 `getMe`를 수행할 필요가 없습니다.
- 폴링 시작 중 일시적인 네트워크 오류로 `deleteWebhook`이 실패하면 OpenClaw는 또 다른 사전 폴링 제어 플레인 호출을 수행하는 대신 롱 폴링으로 계속 진행합니다. 아직 활성 상태인 Webhook은 `getUpdates` 충돌로 나타납니다. 그러면 OpenClaw는 Telegram 전송을 다시 빌드하고 Webhook 정리를 재시도합니다.
- Telegram 소켓이 짧은 고정 주기로 재활용된다면 낮은 `channels.telegram.timeoutSeconds` 값을 확인하세요. 봇 클라이언트는 구성된 값을 송신 및 `getUpdates` 요청 가드 아래로 내려가지 않게 제한하지만, 이전 릴리스에서는 이 값이 해당 가드보다 낮게 설정되었을 때 모든 폴링 또는 응답이 중단될 수 있었습니다.
- 로그에 `Polling stall detected`가 포함되어 있으면 OpenClaw는 기본적으로 완료된 롱 폴링 활성 상태가 120초 동안 없을 때 폴링을 다시 시작하고 Telegram 전송을 다시 빌드합니다.
- `openclaw channels status --probe``openclaw doctor`는 실행 중인 폴링 계정이 시작 유예 시간 후 `getUpdates`를 완료하지 못했거나, 실행 중인 Webhook 계정이 시작 유예 시간 후 `setWebhook`을 완료하지 못했거나, 마지막으로 성공한 폴링 전송 활동이 오래된 경우 경고합니다.
- 장시간 실행되는 `getUpdates` 호출이 정상인데도 호스트가 잘못된 폴링 중단 재시작을 계속 보고할 때만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 지속적인 중단은 보통 호스트와 `api.telegram.org` 사이의 프록시, DNS, IPv6 또는 TLS 송신 문제를 가리킵니다.
- Telegram은 Bot API 전송에 대해 `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`각각의 소문자 변형을 포함한 프로세스 프록시 환경 변수도 따릅니다. `NO_PROXY` / `no_proxy`는 여전히 `api.telegram.org`를 우회할 수 있습니다.
- 서비스 환경에서 OpenClaw 관리 프록시가 `OPENCLAW_PROXY_URL`을 통해 구성되어 있고 표준 프록시 환경 변수가 없으면 Telegram도 Bot API 전송에 해당 URL을 사용합니다.
- 직접 송신/TLS가 불안정한 VPS 호스트에서는 Telegram API 호출을 `channels.telegram.proxy`를 통해 라우팅하세요.
```yaml
channels:
@ -891,8 +929,8 @@ channels:
proxy: socks5://<user>:<password>@proxy-host:1080
```
- Node 22+는 기본적으로 `autoSelectFamily=true`입니다(WSL2 제외). Telegram DNS 결과 순서는 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`, 그다음 `channels.telegram.network.dnsResultOrder`, 그다음 `NODE_OPTIONS=--dns-result-order=ipv4first` 같은 프로세스 기본값을 따릅니다. 아무것도 적용되지 않으면 Node 22+는 `ipv4first`로 폴백합니다.
- 호스트가 WSL2이거나 IPv4 전용 동작에서 명시적으로 더 잘 작동한다면 패밀리 선택을 강제하세요.
- Node 22+는 기본적으로 `autoSelectFamily=true`입니다(WSL2 제외). Telegram DNS 결과 순서는 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`, `channels.telegram.network.dnsResultOrder`, `NODE_OPTIONS=--dns-result-order=ipv4first` 같은 프로세스 기본값 순서로 따릅니다. 아무것도 적용되지 않으면 Node 22+는 `ipv4first`로 대체됩니다.
- 호스트가 WSL2이거나 IPv4 전용 동작 명시적으로 더 잘 작동한다면 패밀리 선택을 강제하세요.
```yaml
channels:
@ -901,7 +939,7 @@ channels:
autoSelectFamily: false
```
- RFC 2544 벤치마크 범위 응답(`198.18.0.0/15`)은 기본적으로 Telegram 미디어 다운로드에 이미 허용됩니다. 신뢰할 수 있는 가짜 IP 또는 투명 proxy가 미디어 다운로드 중 `api.telegram.org`를 다른 private/internal/special-use 주소로 다시 쓰는 경우, Telegram 전용 우회를 선택할 수 있습니다.
- RFC 2544 벤치마크 범위 응답(`198.18.0.0/15`)은 기본적으로 Telegram 미디어 다운로드에 이미 허용됩니다. 신뢰할 수 있는 fake-IP 또는 투명 프록시가 미디어 다운로드 중 `api.telegram.org`를 다른 private/internal/special-use 주소로 재작성한다면 Telegram 전용 우회에 옵트인할 수 있습니다.
```yaml
channels:
@ -910,15 +948,15 @@ channels:
dangerouslyAllowPrivateNetwork: true
```
- 동일한 옵트인은 계정별로
`channels.telegram.accounts.<accountId>.network.dangerouslyAllowPrivateNetwork`에서도 사용할 수 있습니다.
- proxy가 Telegram 미디어 호스트를 `198.18.x.x`로 확인한다면, 먼저 위험한 플래그를 꺼 둔 상태로 두세요. Telegram 미디어는 기본적으로 RFC 2544 벤치마크 범위를 이미 허용합니다.
- 계정별로도 동일한 옵트인이
`channels.telegram.accounts.<accountId>.network.dangerouslyAllowPrivateNetwork`에서 제공됩니다.
- 프록시가 Telegram 미디어 호스트를 `198.18.x.x`로 해석한다면 먼저 위험한 플래그를 끈 상태로 두세요. Telegram 미디어는 기본적으로 RFC 2544 벤치마크 범위를 이미 허용합니다.
<Warning>
`channels.telegram.network.dangerouslyAllowPrivateNetwork`는 Telegram
미디어 SSRF 보호를 약화합니다. Clash, Mihomo 또는 Surge 가짜 IP 라우팅처럼 신뢰할 수 있는 운영자 제어 proxy
환경에서 RFC 2544 벤치마크 범위 밖의 private 또는 special-use 응답을 합성하는 경우에만 사용하세요.
일반 공용 인터넷 Telegram 액세스에는 꺼 두세요.
미디어 SSRF 보호를 약화합니다. Clash, Mihomo, Surge fake-IP 라우팅처럼
RFC 2544 벤치마크 범위 밖의 private 또는 special-use 응답을 합성하는
신뢰할 수 있는 운영자 제어 프록시 환경에서만 사용하세요. 일반적인 공개 인터넷 Telegram 접근에는 꺼 두세요.
</Warning>
- 환경 재정의(임시):
@ -941,18 +979,18 @@ dig +short api.telegram.org AAAA
기본 참조: [구성 참조 - Telegram](/ko/gateway/config-channels#telegram).
<Accordion title="신호가 강한 Telegram 필드">
<Accordion title="중요 Telegram 필드">
- 시작/인증: `enabled`, `botToken`, `tokenFile`, `accounts.*` (`tokenFile`은 일반 파일을 가리켜야 하며, 심볼릭 링크는 거부됩니다)
- 액세스 제어: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, 최상위 `bindings[]` (`type: "acp"`)
- exec 승인: `execApprovals`, `accounts.*.execApprovals`
- 시작/인증: `enabled`, `botToken`, `tokenFile`, `accounts.*`(`tokenFile`은 일반 파일을 가리켜야 하며 심볼릭 링크는 거부됨)
- 접근 제어: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, 최상위 `bindings[]`(`type: "acp"`)
- 실행 승인: `execApprovals`, `accounts.*.execApprovals`
- 명령/메뉴: `commands.native`, `commands.nativeSkills`, `customCommands`
- 스레딩/응답: `replyToMode`, `dm.threadReplies`, `direct.*.threadReplies`
- 스트리밍: `streaming`(미리 보기), `streaming.preview.toolProgress`, `blockStreaming`
- 형식/전달: `textChunkLimit`, `chunkMode`, `linkPreview`, `responsePrefix`
- 미디어/네트워크: `mediaMaxMb`, `mediaGroupFlushMs`, `timeoutSeconds`, `pollingStallThresholdMs`, `retry`, `network.autoSelectFamily`, `network.dangerouslyAllowPrivateNetwork`, `proxy`
- 사용자 지정 API 루트: `apiRoot`(Bot API 루트만 해당, `/bot<TOKEN>`을 포함하지 마세요)
- webhook: `webhookUrl`, `webhookSecret`, `webhookPath`, `webhookHost`
- 사용자 지정 API 루트: `apiRoot`(Bot API 루트만 해당, `/bot<TOKEN>` 포함 금지)
- Webhook: `webhookUrl`, `webhookSecret`, `webhookPath`, `webhookHost`
- 작업/기능: `capabilities.inlineButtons`, `actions.sendMessage|editMessage|deleteMessage|reactions|sticker`
- 반응: `reactionNotifications`, `reactionLevel`
- 오류: `errorPolicy`, `errorCooldownMs`
@ -961,7 +999,7 @@ dig +short api.telegram.org AAAA
</Accordion>
<Note>
다중 계정 우선순위: 두 개 이상의 계정 ID가 구성된 경우 기본 라우팅을 명시하려면 `channels.telegram.defaultAccount`를 설정하세요(또는 `channels.telegram.accounts.default`를 포함하세요). 그렇지 않으면 OpenClaw는 첫 번째 정규화된 계정 ID로 폴백하고 `openclaw doctor`가 경고합니다. 이름 있는 계정은 `channels.telegram.allowFrom` / `groupAllowFrom`을 상속하지만 `accounts.default.*` 값은 상속하지 않습니다.
다중 계정 우선순위: 두 개 이상의 계정 ID가 구성된 경우 기본 라우팅을 명시하려면 `channels.telegram.defaultAccount`를 설정하세요(또는 `channels.telegram.accounts.default` 포함). 그렇지 않으면 OpenClaw는 정규화된 첫 번째 계정 ID로 대체하고 `openclaw doctor`가 경고합니다. 이름 있는 계정은 `channels.telegram.allowFrom` / `groupAllowFrom`을 상속하지만 `accounts.default.*` 값은 상속하지 않습니다.
</Note>
## 관련 항목
@ -971,18 +1009,18 @@ dig +short api.telegram.org AAAA
Telegram 사용자를 Gateway에 페어링합니다.
</Card>
<Card title="그룹" icon="users" href="/ko/channels/groups">
그룹 및 토픽 허용 목록 동작.
그룹 및 주제 허용 목록 동작입니다.
</Card>
<Card title="채널 라우팅" icon="route" href="/ko/channels/channel-routing">
인바운드 메시지를 에이전트로 라우팅합니다.
</Card>
<Card title="보안" icon="shield" href="/ko/gateway/security">
위협 모델과 강화.
위협 모델 및 강화입니다.
</Card>
<Card title="다중 에이전트 라우팅" icon="sitemap" href="/ko/concepts/multi-agent">
그룹과 토픽을 에이전트에 매핑합니다.
그룹과 주제를 에이전트에 매핑합니다.
</Card>
<Card title="문제 해결" icon="wrench" href="/ko/channels/troubleshooting">
교차 채널 진단.
채널 진단입니다.
</Card>
</CardGroup>

View File

@ -1,15 +1,15 @@
---
read_when:
- 채널에서 스트리밍 또는 청크 처리 방식 설명
- 블록 스트리밍 또는 채널 청크 처리 동작 변경
- 채널에서 스트리밍 또는 청크 처리가 작동하는 방식 설명
- 블록 스트리밍 또는 채널 청 동작 변경
- 중복/조기 블록 응답 또는 채널 미리보기 스트리밍 디버깅
summary: 스트리밍 + 청킹 동작 (블록 응답, 채널 미리보기 스트리밍, 모드 매핑)
summary: 스트리밍 + 청크 처리 동작(블록 답장, 채널 미리보기 스트리밍, 모드 매핑)
title: 스트리밍 및 청크 처리
x-i18n:
generated_at: "2026-05-04T06:23:53Z"
generated_at: "2026-05-04T07:03:02Z"
model: gpt-5.5
provider: openai
source_hash: fcb41ceb5602ab42c3fd41a59de62cc965ea61fdbc058c052fb93689a9c5299b
source_hash: ff7b6cd8127255352fe16fb746469e9828e7d5aea183d3799ab10cc768515bd1
source_path: concepts/streaming.md
workflow: 16
---
@ -19,11 +19,11 @@ OpenClaw에는 두 개의 별도 스트리밍 계층이 있습니다.
- **블록 스트리밍(채널):** 어시스턴트가 작성하는 동안 완료된 **블록**을 내보냅니다. 이는 일반 채널 메시지입니다(토큰 델타가 아님).
- **미리보기 스트리밍(Telegram/Discord/Slack):** 생성 중 임시 **미리보기 메시지**를 업데이트합니다.
현재 채널 메시지로 보내는 **진정한 토큰 델타 스트리밍**은 없습니다. 미리보기 스트리밍은 메시지 기반입니다(전송 + 편집/추가).
현재 채널 메시지에는 **진정한 토큰 델타 스트리밍**이 없습니다. 미리보기 스트리밍은 메시지 기반입니다(전송 + 수정/추가).
## 블록 스트리밍(채널 메시지)
블록 스트리밍은 사용할 수 있게 되는 대로 어시스턴트 출력을 큼직한 청크로 보냅니다.
블록 스트리밍은 어시스턴트 출력을 사용할 수 있게 되는 대로 큰 단위의 청크로 보냅니다.
```
Model output
@ -37,107 +37,124 @@ Model output
범례:
- `text_delta/events`: 모델 스트림 이벤트입니다(비스트리밍 모델에서는 드물 수 있음).
- `chunker`: 최소/최대 경계와 분할 선호도를 적용하는 `EmbeddedBlockChunker`입니다.
- `channel send`: 실제 발신 메시지입니다(블록 답).
- `text_delta/events`: 모델 스트림 이벤트(비스트리밍 모델에서는 드물 수 있음).
- `chunker`: 최소/최대 범위 + 중단 선호도를 적용하는 `EmbeddedBlockChunker`.
- `channel send`: 실제 발신 메시지(블록 답).
**제어:**
**제어 항목:**
- `agents.defaults.blockStreamingDefault`: `"on"`/`"off"`(기본값 꺼짐).
- 채널 재정의: 채널별로 `"on"`/`"off"`를 강제하는 `*.blockStreaming`(및 계정별 변형).
- `agents.defaults.blockStreamingBreak`: `"text_end"` 또는 `"message_end"`.
- `agents.defaults.blockStreamingChunk`: `{ minChars, maxChars, breakPreference? }`.
- `agents.defaults.blockStreamingCoalesce`: `{ minChars?, maxChars?, idleMs? }`(전송 전 스트리밍된 블록 병합).
- 채널 하드 한: `*.textChunkLimit`(예: `channels.whatsapp.textChunkLimit`).
- 채널 청크 모드: `*.chunkMode`(`length`가 기본값, `newline`은 길이 기준 청킹 전에 빈 줄(문단 경계)에서 분할).
- Discord 소프트 한: `channels.discord.maxLinesPerMessage`(기본값 17)는 UI 잘림을 피하기 위해 긴 응답을 분할합니다.
- 채널 하드 한: `*.textChunkLimit`(예: `channels.whatsapp.textChunkLimit`).
- 채널 청크 모드: `*.chunkMode`(`length`가 기본값, `newline`은 길이 청킹 전에 빈 줄(문단 경계)에서 분할).
- Discord 소프트 한: UI 잘림을 피하기 위해 긴 답장을 분할하는 `channels.discord.maxLinesPerMessage`(기본값 17).
**경계 의미:**
- `text_end`: 청크 처리기가 내보내는 즉시 블록을 스트리밍하고, 각 `text_end`에서 플러시합니다.
- `text_end`: chunker가 내보내는 즉시 블록을 스트리밍하고, 각 `text_end`에서 플러시합니다.
- `message_end`: 어시스턴트 메시지가 끝날 때까지 기다린 다음 버퍼링된 출력을 플러시합니다.
`message_end`버퍼링된 텍스트가 `maxChars`를 초과하면 여전히 청크 처리기를 사용하므로, 끝에서 여러 청크를 내보낼 수 있습니다.
버퍼링된 텍스트가 `maxChars`를 초과하면 `message_end`도 여전히 chunker를 사용하므로, 마지막에 여러 청크를 내보낼 수 있습니다.
### 블록 스트리밍의 미디어 전달
### 블록 스트리밍에서의 미디어 전달
`MEDIA:` 지시문은 일반 전달 메타데이터입니다. 블록 스트리밍이 미디어 블록을 일찍 보내면 OpenClaw는 해당 턴의 전달을 기억합니다. 최종 어시스턴트 페이로드가 같은 미디어 URL을 반복하면, 최종 전달은 첨부 파일을 다시 보내는 대신 중복 미디어를 제거합니다.
`MEDIA:` 지시문은 일반 전달 메타데이터입니다. 블록 스트리밍이 미디어 블록을
일찍 보내면 OpenClaw는 해당 턴의 전달을 기억합니다. 최종
어시스턴트 페이로드가 같은 미디어 URL을 반복하면 최종 전달은
첨부 파일을 다시 보내는 대신 중복 미디어를 제거합니다.
완전히 중복되는 최종 페이로드는 억제됩니다. 최종 페이로드가 이미 스트리밍된 미디어 주변에 별도의 텍스트를 추가하면, OpenClaw는 미디어를 한 번만 전달하도록 유지하면서 새 텍스트는 계속 보냅니다. 이렇게 하면 에이전트가 스트리밍 중 `MEDIA:`를 내보내고 제공자도 완료된 응답에 이를 포함할 때 Telegram 같은 채널에서 음성 메모나 파일이 중복되는 일을 방지합니다.
정확히 중복되는 최종 페이로드는 억제됩니다. 최종 페이로드가 이미
스트리밍된 미디어 주변에 별도의 텍스트를 추가하면, OpenClaw는 미디어는
한 번만 전달하도록 유지하면서 새 텍스트는 계속 보냅니다. 이렇게 하면 에이전트가
스트리밍 중 `MEDIA:`를 내보내고 제공자도 완료된 답장에 이를 포함할 때,
Telegram 같은 채널에서 음성 메모나 파일이 중복되는 것을 방지합니다.
## 청킹 알고리즘(하한/상한 경계)
## 청킹 알고리즘(하한/상한)
블록 청킹은 `EmbeddedBlockChunker`로 구현됩니다.
- **하한 경계:** 버퍼 >= `minChars`가 될 때까지 내보내지 않습니다(강제 경우 제외).
- **상한 경계:** `maxChars` 전에 분할하는 것을 선호하며, 강제된 경우 `maxChars`에서 분할합니다.
- **분할 선호도:** `paragraph``newline``sentence``whitespace`하드 분할.
- **코드 펜스:** 펜스 내부에서는 절대 분할하지 않습니다. `maxChars`에서 강제 분할할 때는 Markdown이 유효하게 유지되도록 펜스를 닫고 다시 엽니다.
- **하한:** 버퍼 >= `minChars`가 될 때까지 내보내지 않습니다(강제되는 경우 제외).
- **상한:** `maxChars` 전에 분할하는 것을 선호합니다. 강제되면 `maxChars`에서 분할합니다.
- **중단 선호도:** `paragraph``newline``sentence``whitespace`강제 중단.
- **코드 펜스:** 펜스 내부에서는 절대 분할하지 않습니다. `maxChars`에서 강제되는 경우 Markdown이 유효하도록 펜스를 닫고 다시 엽니다.
`maxChars`는 채널 `textChunkLimit`로 제한되므로 채널별 한도를 초과할 수 없습니다.
`maxChars`는 채널 `textChunkLimit`로 제한되므로, 채널별 제한을 초과할 수 없습니다.
## 병합(스트리밍된 블록 병합)
블록 스트리밍이 활성화되면 OpenClaw는 전송하기 전에 **연속된 블록 청크를 병합**할 수 있습니다. 이렇게 하면 점진적 출력을 제공하면서도 “한 줄 스팸”을 줄일 수 있습니다.
블록 스트리밍이 활성화되면 OpenClaw는 발신 전에 **연속된 블록 청크를 병합**할 수 있습니다. 이렇게 하면 점진적인 출력은 제공하면서도
“한 줄 스팸”을 줄일 수 있습니다.
- 병합은 플러시하기 전에 **유휴 간격**(`idleMs`)을 기다립니다.
- 버퍼는 `maxChars`로 제한되며, 이를 초과하면 플러시됩니다.
- `minChars`는 충분한 텍스트가 누적될 때까지 작은 조각이 전송되지 않도록 합니다(최종 플러시는 항상 남은 텍스트를 보냄).
- 조인자는 `blockStreamingChunk.breakPreference`에서 파생됩니다(`paragraph` → `\n\n`, `newline``\n`, `sentence` → 공백).
- 채널 재정의는 `*.blockStreamingCoalesce`를 통해 사용할 수 있습니다(계정별 설정 포함).
- 병합은 플러시 전에 **유휴 간격**(`idleMs`)을 기다립니다.
- 버퍼는 `maxChars`로 제한되며 이를 초과하면 플러시됩니다.
- `minChars`는 충분한 텍스트가 누적될 때까지 작은 조각이 전송되는 것을 방지합니다
(최종 플러시는 항상 남은 텍스트를 보냄).
- 조이너는 `blockStreamingChunk.breakPreference`에서 파생됩니다
(`paragraph` → `\n\n`, `newline``\n`, `sentence` → 공백).
- 채널 재정의는 `*.blockStreamingCoalesce`를 통해 사용할 수 있습니다(계정별 구성 포함).
- 기본 병합 `minChars`는 재정의하지 않는 한 Signal/Slack/Discord에서 1500으로 올라갑니다.
## 블록 사이의 사람 같은 속도 조절
블록 스트리밍이 활성화되면 블록 응답 사이에(첫 번째 블록 이후) **무작위 일시 중지**를 추가할 수 있습니다. 이렇게 하면 여러 말풍선 응답이 더 자연스럽게 느껴집니다.
블록 스트리밍이 활성화되면 블록 답장 사이(첫 번째 블록 이후)에 **무작위 일시정지**를 추가할 수 있습니다. 이렇게 하면 여러 말풍선 응답이
더 자연스럽게 느껴집니다.
- 설정: `agents.defaults.humanDelay`(`agents.list[].humanDelay`로 에이전트별 재정의).
- 구성: `agents.defaults.humanDelay`(`agents.list[].humanDelay`로 에이전트별 재정의).
- 모드: `off`(기본값), `natural`(800~2500ms), `custom`(`minMs`/`maxMs`).
- **블록 답**에만 적용되며, 최종 답이나 도구 요약에는 적용되지 않습니다.
- **블록 답**에만 적용되며, 최종 답이나 도구 요약에는 적용되지 않습니다.
## "청크 스트리밍 또는 전체 스트리밍"
이는 다음에 매핑됩니다.
- **청크 스트리밍:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(진행하면서 내보냄). Telegram이 아닌 채널은 `*.blockStreaming: true`도 필요합니다.
- **끝에서 전체 스트리밍:** `blockStreamingBreak: "message_end"`(한 번 플러시, 매우 길면 여러 청크 가능).
- **블록 스트리밍 없음:** `blockStreamingDefault: "off"`(최종 답만).
- **청크 스트리밍:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(진행 중 내보내기). Telegram이 아닌 채널에는 `*.blockStreaming: true`도 필요합니다.
- **마지막에 전체 스트리밍:** `blockStreamingBreak: "message_end"`(한 번 플러시, 매우 길면 여러 청크일 수 있음).
- **블록 스트리밍 없음:** `blockStreamingDefault: "off"`(최종 답만).
**채널 참고:** `*.blockStreaming`이 명시적으로 `true`로 설정되지 않는 한 블록 스트리밍은 **꺼져 있습니다**. 채널은 블록 응답 없이 실시간 미리보기(`channels.<channel>.streaming`)를 스트리밍할 수 있습니다.
**채널 참고:** `*.blockStreaming`이 명시적으로 `true`로 설정되지 않는 한 블록 스트리밍은 **꺼져 있습니다**. 채널은 블록 답장 없이 실시간 미리보기
(`channels.<channel>.streaming`)를 스트리밍할 수 있습니다.
설정 위치 알림: `blockStreaming*` 기본값은 루트 설정이 아니라 `agents.defaults` 아래에 있습니다.
구성 위치 알림: `blockStreaming*` 기본값은 루트 구성이 아니라
`agents.defaults` 아래에 있습니다.
## 미리보기 스트리밍 모드
정식 키: `channels.<channel>.streaming`
표준 키: `channels.<channel>.streaming`
모드:
- `off`: 미리보기 스트리밍을 비활성화합니다.
- `partial`: 최신 텍스트로 교체되는 단일 미리보기입니다.
- `partial`: 최신 텍스트로 대체되는 단일 미리보기.
- `block`: 청크/추가 단계로 미리보기를 업데이트합니다.
- `progress`: 생성 중 진행/상태 미리보기, 완료 시 최종 답변입니다.
- `progress`: 생성 중 진행/상태 미리보기, 완료 시 최종 답변.
`streaming.mode: "block"`은 Discord와 Telegram처럼 편집 가능한 채널을 위한 미리보기 스트리밍 모드입니다. 이것이 해당 채널에서 채널 블록 전달을 활성화하지는 않습니다. 일반 블록 응답을 원할 때는 `streaming.block.enabled` 또는 레거시 `blockStreaming` 채널 키를 사용하세요. Microsoft Teams는 예외입니다. 초안 미리보기 블록 전송이 없으므로 `streaming.mode: "block"`은 네이티브 partial/progress 스트리밍 대신 Teams 블록 전달에 매핑됩니다.
`streaming.mode: "block"`은 Discord와 Telegram처럼 수정 가능한 채널을 위한
미리보기 스트리밍 모드입니다. 이 설정은 해당 채널에서 채널 블록 전달을 활성화하지 않습니다.
일반 블록 답장을 원하면 `streaming.block.enabled` 또는 레거시
`blockStreaming` 채널 키를 사용하세요. Microsoft Teams는 예외입니다. 초안 미리보기
블록 전송이 없으므로 `streaming.mode: "block"`은 네이티브 partial/progress 스트리밍 대신 Teams 블록 전달로 매핑됩니다.
### 채널 매핑
| 채널 | `off` | `partial` | `block` | `progress` |
| ---------- | ----- | --------- | ------- | ------------------- |
| Telegram | ✅ | ✅ | ✅ | 편집 가능한 진행 초안 |
| Discord | ✅ | ✅ | ✅ | 편집 가능한 진행 초안 |
| Slack | ✅ | ✅ | ✅ | ✅ |
| Mattermost | ✅ | ✅ | ✅ | ✅ |
| MS Teams | ✅ | ✅ | ✅ | 네이티브 진행 스트림 |
| 채널 | `off` | `partial` | `block` | `progress` |
| ---------- | ----- | --------- | ------- | ----------------------- |
| Telegram | ✅ | ✅ | ✅ | 수정 가능한 진행 초안 |
| Discord | ✅ | ✅ | ✅ | 수정 가능한 진행 초안 |
| Slack | ✅ | ✅ | ✅ | ✅ |
| Mattermost | ✅ | ✅ | ✅ | ✅ |
| MS Teams | ✅ | ✅ | ✅ | 네이티브 진행 스트림 |
Slack 전용:
- `channels.slack.streaming.nativeTransport``channels.slack.streaming.mode="partial"`일 때 Slack 네이티브 스트리밍 API 호출을 전환합니다(기본값: `true`).
- Slack 네이티브 스트리밍과 Slack 어시스턴트 스레드 상태에는 답 스레드 대상이 필요합니다. 최상위 DM은 해당 스레드 스타일 미리보기를 표시하지 않지만, Slack 초안 미리보기 게시물과 편집은 계속 사용할 수 있습니다.
- Slack 네이티브 스트리밍과 Slack 어시스턴트 스레드 상태에는 답 스레드 대상이 필요합니다. 최상위 DM은 해당 스레드 스타일 미리보기를 표시하지 않지만, Slack 초안 미리보기 게시물과 수정을 계속 사용할 수 있습니다.
레거시 키 마이그레이션:
- Telegram: 레거시 `streamMode` 스칼라/불리언 `streaming` 값은 doctor/config 호환성 경로에서 감지되어 `streaming.mode`로 마이그레이션됩니다.
- Telegram: 레거시 `streamMode` 스칼라/불리언 `streaming` 값은 doctor/config 호환성 경로에서 감지되어 `streaming.mode`로 마이그레이션됩니다.
- Discord: `streamMode` + 불리언 `streaming``streaming` 열거형으로 자동 마이그레이션됩니다.
- Slack: `streamMode``streaming.mode`로 자동 마이그레이션됩니다. 불리언 `streaming``streaming.mode``streaming.nativeTransport`로 자동 마이그레이션됩니다. 레거시 `nativeStreaming``streaming.nativeTransport`로 자동 마이그레이션됩니다.
@ -145,52 +162,52 @@ Slack 전용:
Telegram:
- DM 그룹/토픽 전반에서 `sendMessage` + `editMessageText` 미리보기 업데이트를 사용합니다.
- 미리보기가 약 1분 동안 표시된 경우, 제자리에서 편집하는 대신 새로운 최종 메시지를 보낸 다음 Telegram의 타임스탬프가 응답 완료를 반영하도록 미리보기를 정리합니다.
- Telegram 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍 건너뜁니다(이중 스트리밍 방지).
- `/reasoning stream`은 최종 전달 후 삭제되는 임시 미리보기에 추론을 쓸 수 있습니다.
- DM 그룹/토픽 전반에서 `sendMessage` + `editMessageText` 미리보기 업데이트를 사용합니다.
- 미리보기가 약 1분 동안 표시된 경우 제자리에서 수정하는 대신 새 최종 메시지를 보낸 다음, Telegram의 타임스탬프가 답장 완료를 반영하도록 미리보기를 정리합니다.
- Telegram 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍 건너뜁니다(이중 스트리밍 방지).
- `/reasoning stream`은 최종 전달 후 삭제되는 일시적 미리보기에 추론을 쓸 수 있습니다.
Discord:
- 전송 + 편집 미리보기 메시지를 사용합니다.
- 전송 + 수정 미리보기 메시지를 사용합니다.
- `block` 모드는 초안 청킹(`draftChunk`)을 사용합니다.
- Discord 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍 건너뜁니다.
- 최종 미디어, 오류, 명시적 응답 페이로드는 새 초안을 플러시하지 않고 대기 중인 미리보기를 취소한 다음 일반 전달을 사용합니다.
- Discord 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍 건너뜁니다.
- 최종 미디어, 오류 및 명시적 답장 페이로드는 새 초안을 플러시하지 않고 보류 중인 미리보기를 취소한 다음 일반 전달을 사용합니다.
Slack:
- `partial`은 사용할 수 있을 때 Slack 네이티브 스트리밍(`chat.startStream`/`append`/`stop`)을 사용할 수 있습니다.
- `partial`은 사용 가능한 경우 Slack 네이티브 스트리밍(`chat.startStream`/`append`/`stop`)을 사용할 수 있습니다.
- `block`은 추가 스타일 초안 미리보기를 사용합니다.
- `progress`는 상태 미리보기 텍스트를 사용한 다음 최종 답변을 보냅니다.
- 답 스레드가 없는 최상위 DM은 Slack 네이티브 스트리밍 대신 초안 미리보기 게시물과 편집을 사용합니다.
- 네이티브 및 초안 미리보기 스트리밍은 해당 턴의 블록 답을 억제하므로 Slack 답은 하나의 전달 경로로만 스트리밍됩니다.
- 최종 미디어/오류 페이로드와 진행 최종 메시지는 일회용 초안 메시지를 만들지 않습니다. 미리보기를 편집할 수 있는 텍스트/블록 최종 메시지만 대기 중인 초안 텍스트를 플러시합니다.
- 답 스레드가 없는 최상위 DM은 Slack 네이티브 스트리밍 대신 초안 미리보기 게시물과 수정을 사용합니다.
- 네이티브 및 초안 미리보기 스트리밍은 해당 턴의 블록 답을 억제하므로 Slack 답은 하나의 전달 경로로만 스트리밍됩니다.
- 최종 미디어/오류 페이로드와 진행 최종 메시지는 일회용 초안 메시지를 만들지 않습니다. 미리보기를 수정할 수 있는 텍스트/블록 최종 메시지만 보류 중인 초안 텍스트를 플러시합니다.
Mattermost:
- 사고 과정, 도구 활동, 부분 응답 텍스트를 단일 초안 미리보기 게시물로 스트리밍하며, 최종 답변을 보내도 안전할 때 제자리에서 최종화합니다.
- 미리보기 게시물이 삭제되었거나 최종화 시 사용할 수 없는 경우 새 최종 게시물을 보내는 방식으로 폴백합니다.
- 최종 미디어/오류 페이로드는 임시 미리보기 게시물을 플러시하는 대신 일반 전달 전에 대기 중인 미리보기 업데이트를 취소합니다.
- 생각, 도구 활동, 부분 답장 텍스트를 단일 초안 미리보기 게시물로 스트리밍하며, 최종 답변을 안전하게 보낼 수 있을 때 제자리에서 완료합니다.
- 완료 시점에 미리보기 게시물이 삭제되었거나 사용할 수 없는 경우 새 최종 게시물을 보내는 방식으로 폴백합니다.
- 최종 미디어/오류 페이로드는 임시 미리보기 게시물을 플러시하는 대신 일반 전달 전에 보류 중인 미리보기 업데이트를 취소합니다.
Matrix:
- 최종 텍스트가 미리보기 이벤트를 재사용할 수 있으면 초안 미리보기를 제자리에서 최종화합니다.
- 미디어 전용, 오류, 답 대상 불일치 최종 메시지는 일반 전달 전에 대기 중인 미리보기 업데이트를 취소합니다. 이미 표시된 오래된 미리보기는 삭제됩니다.
- 최종 텍스트가 미리보기 이벤트를 재사용할 수 있으면 초안 미리보기가 제자리에서 완료됩니다.
- 미디어 전용, 오류, 답 대상 불일치 최종 메시지는 일반 전달 전에 보류 중인 미리보기 업데이트를 취소합니다. 이미 표시된 오래된 미리보기는 삭제 처리됩니다.
### 도구 진행 미리보기 업데이트
### 도구 진행 미리보기 업데이트
미리보기 스트리밍에는 **도구 진행** 업데이트도 포함될 수 있습니다. 이는 "웹 검색 중", "파일 읽는 중", "도구 호출 중" 같은 짧은 상태 줄로, 도구가 실행되는 동안 최종 응답보다 먼저 같은 미리보기 메시지에 표시됩니다. 이렇게 하면 여러 단계의 도구 턴이 첫 사고 과정 미리보기와 최종 답변 사이에 조용히 멈춰 있는 대신 시각적으로 살아 있게 유지됩니다.
미리보기 스트리밍에는 도구가 실행되는 동안 최종 답장보다 앞서 같은 미리보기 메시지에 표시되는 "웹 검색 중", "파일 읽는 중", "도구 호출 중" 같은 짧은 상태 줄**도구 진행률** 업데이트도 포함될 수 있습니다. 이렇게 하면 여러 단계의 도구 턴이 첫 생각 미리보기와 최종 답변 사이에서 조용히 멈춰 있는 대신 시각적으로 계속 살아 있게 됩니다.
지원되는 표면:
- **Discord**, **Slack**, **Telegram**, **Matrix**는 미리보기 스트리밍이 활성화된 경우 기본적으로 도구 진행을 실시간 미리보기 편집으로 스트리밍합니다. Microsoft Teams는 개인 채팅에서 네이티브 진행 스트림을 사용합니다.
- Telegram은 `v2026.4.22`부터 도구 진행 미리보기 업데이트가 활성화된 상태로 출시되었습니다. 이를 활성화 상태로 유지하면 릴리스된 동작이 보존됩니다.
- **Mattermost**는 이미 도구 활동을 단일 초안 미리보기 게시물에 포함합니다(위 참조).
- 도구 진행 편집은 활성 미리보기 스트리밍 모드를 따릅니다. 미리보기 스트리밍이 `off`이거나 블록 스트리밍이 메시지를 넘겨받은 경우 건너뜁니다. Telegram에서 `streaming.mode: "off"`는 최종 응답 전용입니다. 일반 진행 잡담도 독립 상태 메시지로 전달되지 않고 억제되지만, 승인 프롬프트, 미디어 페이로드, 오류는 계속 정상 라우팅됩니다.
- 미리보기 스트리밍은 유지하되 도구 진행 줄을 숨기려면 해당 채널의 `streaming.preview.toolProgress``false`로 설정하세요. 미리보기 편집을 완전히 비활성화하려면 `streaming.mode``off`로 설정하세요.
- Telegram 선택 인용 답은 예외입니다. `replyToMode``"off"`가 아니고 선택된 인용 텍스트가 있으면, OpenClaw는 해당 턴의 답변 미리보기 스트림을 건너뛰므로 도구 진행 미리보기 줄이 렌더링될 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 답은 미리보기 스트리밍을 계속 유지합니다. 자세한 내용은 [Telegram 채널 문서](/ko/channels/telegram)를 참조하세요.
- **Discord**, **Slack**, **Telegram**, **Matrix**는 미리보기 스트리밍이 활성화된 경우 기본적으로 도구 진행률을 실시간 미리보기 수정으로 스트리밍합니다. Microsoft Teams는 개인 채팅에서 네이티브 진행 스트림을 사용합니다.
- Telegram은 `v2026.4.22`부터 도구 진행 미리보기 업데이트가 활성화된 상태로 출시되었습니다. 이를 활성화 상태로 유지하면 릴리스된 동작이 보존됩니다.
- **Mattermost**는 이미 도구 활동을 단일 초안 미리보기 게시물에 접어 넣습니다(위 참조).
- 도구 진행률 수정은 활성 미리보기 스트리밍 모드를 따릅니다. 미리보기 스트리밍이 `off`이거나 블록 스트리밍이 메시지를 대신 처리한 경우 건너뜁니다. Telegram에서 `streaming.mode: "off"`는 최종 전용입니다. 일반 진행 잡담도 독립 상태 메시지로 전달되지 않고 억제되지만, 승인 프롬프트, 미디어 페이로드, 오류는 계속 정상적으로 라우팅됩니다.
- 미리보기 스트리밍은 유지하되 도구 진행 줄을 숨기려면 해당 채널의 `streaming.preview.toolProgress``false`로 설정합니다. 명령/실행 텍스트를 숨기면서 도구 진행률 줄을 계속 표시하려면 `streaming.preview.commandText``"status"`로 설정하거나 `streaming.progress.commandText``"status"`로 설정합니다. 릴리스된 동작을 보존하기 위해 기본값은 `"raw"`입니다. 이 정책은 Discord, Matrix, Microsoft Teams, Mattermost, Slack 초안 미리보기, Telegram을 포함하여 OpenClaw의 간결한 진행률 렌더러를 사용하는 초안/진행 채널에서 공유됩니다. 미리보기 수정을 완전히 비활성화하려면 `streaming.mode``off`로 설정합니다.
- Telegram 선택 인용 답은 예외입니다. `replyToMode``"off"`가 아니고 선택된 인용 텍스트가 있으면, OpenClaw는 해당 턴의 답변 미리보기 스트림을 건너뛰므로 도구 진행률 미리보기 줄을 렌더링할 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 답은 미리보기 스트리밍을 계속 유지합니다. 자세한 내용은 [Telegram 채널 문서](/ko/channels/telegram)를 참조하세요.
예:
진행 상황 줄은 계속 표시하되 원시 명령/exec 텍스트는 숨깁니다.
```json
{
@ -199,7 +216,26 @@ Matrix:
"streaming": {
"mode": "partial",
"preview": {
"toolProgress": false
"toolProgress": true,
"commandText": "status"
}
}
}
}
}
```
동일한 구조를 다른 간결한 진행 상황 채널 키 아래에 사용합니다. 예를 들어 `channels.discord`, `channels.matrix`, `channels.msteams`, `channels.mattermost` 또는 Slack 초안 미리보기에 사용할 수 있습니다. 진행 상황 초안 모드의 경우 동일한 정책을 `streaming.progress` 아래에 넣습니다.
```json
{
"channels": {
"telegram": {
"streaming": {
"mode": "progress",
"progress": {
"toolProgress": true,
"commandText": "status"
}
}
}
@ -209,7 +245,7 @@ Matrix:
## 관련 항목
- [진행 상황 초안](/ko/concepts/progress-drafts) — 긴 턴 동안 업데이트되는 표시 가능한 진행 중 작업 메시지
- [메시지](/ko/concepts/messages) — 메시지 수명 주기 전달
- [진행 상황 초안](/ko/concepts/progress-drafts) — 긴 턴 동안 업데이트되는 표시 가능한 작업 진행 중 메시지
- [메시지](/ko/concepts/messages) — 메시지 수명 주기 전달
- [재시도](/ko/concepts/retry) — 전달 실패 시 재시도 동작
- [채널](/ko/channels) — 채널별 스트리밍 지원

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,24 @@
---
read_when:
- 공개 릴리스 채널 정의를 찾는 중
- 릴리스 검증 또는 패키지 인 실행
- 버전 명명 규칙과 주기를 찾는 중
summary: 릴리스 레인, 운영자 체크리스트, 검증 박스, 버전 명명, 주기
- 릴리스 검증 또는 패키지 인 실행
- 버전 명명 방식 및 릴리스 주기 확인
summary: 릴리스 레인, 운영자 체크리스트, 검증 박스, 버전 명명 주기
title: 릴리스 정책
x-i18n:
generated_at: "2026-05-03T21:37:12Z"
generated_at: "2026-05-04T07:02:59Z"
model: gpt-5.5
provider: openai
source_hash: 566088d826e1e2bac21b11443b82b62cb73ed1fd9c508c3fb865149cf8a428ba
source_hash: ef50d3ef5d1e23b4e2c2b097fc4ca9f6d46bf8acb9aea0c9bca6d14e213b88b6
source_path: reference/RELEASING.md
workflow: 16
---
OpenClaw에는 세 가지 공개 릴리스 인이 있습니다.
OpenClaw에는 세 가지 공개 릴리스 인이 있습니다.
- stable: 기본적으로 npm `beta`에 게시되거나 명시적으로 요청하면 npm `latest`에 게시되는 태그된 릴리스
- beta: npm `beta`에 게시되는 프리릴리스 태그
- dev: `main`의 이동하는 헤드
- 안정: 기본적으로 npm `beta`에 게시하거나 명시적으로 요청된 경우 npm `latest`에 게시하는 태그 릴리스
- 베타: npm `beta`에 게시하는 프리릴리스 태그
- 개발: `main`의 이동하는 헤드
## 버전 명명
@ -28,141 +28,249 @@ OpenClaw에는 세 가지 공개 릴리스 라인이 있습니다.
- Git 태그: `vYYYY.M.D-N`
- 베타 프리릴리스 버전: `YYYY.M.D-beta.N`
- Git 태그: `vYYYY.M.D-beta.N`
- 월이나 일을 0으로 채우지 마세요
- 월 또는 일을 0으로 채우지 마세요
- `latest`는 현재 승격된 안정 npm 릴리스를 의미합니다
- `beta`는 현재 베타 설치 대상을 의미합니다
- 안정 및 안정 수정 릴리스는 기본적으로 npm `beta`에 게시됩니다. 릴리스 운영자는 명시적으로 `latest`를 대상으로 지정하거나, 검증된 베타 빌드를 나중에 승격할 수 있습니다
- 안정 및 안정 수정 릴리스는 기본적으로 npm `beta`에 게시됩니다. 릴리스 운영자는 `latest` 명시적으로 대상으로 지정하거나, 검증된 베타 빌드를 나중에 승격할 수 있습니다
- 모든 안정 OpenClaw 릴리스는 npm 패키지와 macOS 앱을 함께 제공합니다.
베타 릴리스는 일반적으로 먼저 npm/패키지 경로를 검증하고 게시하며,
mac 앱 빌드/서명/공증은 명시적으로 요청되지 않는 한 안정 릴리스용으로 남겨둡니다
베타 릴리스는 일반적으로 npm/패키지 경로를 먼저 검증하고 게시하며,
Mac 앱 빌드/서명/공증은 명시적으로 요청되지 않는 한 안정 릴리스용으로 남겨둡니다
## 릴리스 주기
- 릴리스는 베타 우선으로 진행됩니다
- 안정 릴리스는 최신 베타가 검증된 후에만 이어집니다
- 유지관리자는 일반적으로 현재 `main`에서 생성한 `release/YYYY.M.D` 브랜치에서 릴리스를 만들기 때문에,
릴리스 검증과 수정이 `main`의 새로운 개발을 막지 않습니다
- 베타 태그가 푸시되었거나 게시되었고 수정이 필요한 경우, 유지관리자는 이전 베타 태그를 삭제하거나 다시 만드는 대신
다음 `-beta.N` 태그를 만듭니다
- 자세한 릴리스 절차, 승인, 자격 증명, 복구 참고 사항은
- 유지관리자는 일반적으로 현재 `main`에서 만든 `release/YYYY.M.D` 브랜치에서 릴리스를 자르므로,
릴리스 검증과 수정이 `main`의 새 개발을 막지 않습니다
- 베타 태그가 푸시되었거나 게시된 뒤 수정이 필요한 경우, 유지관리자는 이전 베타 태그를 삭제하거나 다시 만들지 않고
다음 `-beta.N` 태그를 자릅니다
- 자세한 릴리스 절차, 승인, 자격 증명, 복구 노트는
유지관리자 전용입니다
## 릴리스 운영자 체크리스트
이 체크리스트는 릴리스 흐름의 공개 형태입니다. 비공개 자격 증명,
서명, 공증, dist-tag 복구, 긴급 롤백 세부 사항은 유지관리자 전용
릴리스 런북에 남겨둡니다.
서명, 공증, dist-tag 복구, 긴급 롤백 세부 정보는
유지관리자 전용 릴리스 런북에 남아 있습니다.
1. 현재 `main`에서 시작합니다. 최신 변경 사항을 가져오고, 대상 커밋이 푸시되었는지 확인하며,
1. 현재 `main`에서 시작합니다. 최신 내용을 pull하고, 대상 커밋이 푸시되었는지 확인하며,
현재 `main` CI가 브랜치를 만들기에 충분히 정상인지 확인합니다.
2. 실제 커밋 기록을 기반으로 `/changelog`를 사용해 최상단 `CHANGELOG.md` 섹션을 다시 작성하고,
항목을 사용자 지향으로 유지한 뒤 커밋하고, 푸시하고, 브랜치를 만들기 전에 한 번 더 리베이스/풀합니다.
2. 실제 커밋 기록을 바탕으로 `/changelog`로 최상단 `CHANGELOG.md` 섹션을 다시 작성하고,
항목은 사용자 대상 내용으로 유지한 뒤 커밋하고 푸시하며, 브랜치하기 전에
한 번 더 rebase/pull합니다.
3. `src/plugins/compat/registry.ts`
`src/commands/doctor/shared/deprecation-compat.ts`의 릴리스 호환성 기록을 검토합니다. 업그레이드 경로가 계속 보장될 때만 만료된
`src/commands/doctor/shared/deprecation-compat.ts`의 릴리스 호환성 기록을 검토합니다. 업그레이드 경로가 계속 보장되는 경우에만 만료된
호환성을 제거하거나, 의도적으로 유지하는 이유를 기록합니다.
4. 현재 `main`에서 `release/YYYY.M.D`를 만듭니다. 일반 릴리스 작업을
`main`에서 직접 수행하지 마세요.
5. 의도한 태그에 필요한 모든 버전 위치를 올리고,
게시 가능한 Plugin 패키지가 릴리스 버전과 호환성 메타데이터를 공유하도록 `pnpm plugins:sync`를 실행한 다음, 로컬 결정적 프리플라이트를 실행합니다.
`pnpm plugins:sync`를 실행하여 게시 가능한 Plugin 패키지가 릴리스
버전과 호환성 메타데이터를 공유하게 한 다음, 로컬 결정적 사전 점검을 실행합니다:
`pnpm check:test-types`, `pnpm check:architecture`,
`pnpm build && pnpm ui:build`, `pnpm plugins:sync:check`, 그리고
`pnpm build && pnpm ui:build`, `pnpm plugins:sync:check`,
`pnpm release:check`.
6. `preflight_only=true``OpenClaw NPM Release`를 실행합니다. 태그가 존재하기 전에는,
검증 전용 프리플라이트에 전체 40자 릴리스 브랜치 SHA를 사용할 수 있습니다.
성공한 `preflight_run_id`를 저장합니다.
7. 릴리스 브랜치, 태그, 또는 전체 커밋 SHA에 대해 `Full Release Validation`으로 모든 프리릴리스 테스트를 시작합니다.
이는 네 가지 큰 릴리스 테스트 박스인 Vitest, Docker, QA Lab, Package를 위한 단일 수동 진입점입니다.
8. 검증이 실패하면 릴리스 브랜치에서 수정하고, 수정이 입증되는 가장 작은 실패 파일, 라인, 워크플로 작업, 패키지 프로필, provider, 또는 model 허용 목록을 다시 실행합니다.
변경된 표면 때문에 이전 증거가 무효화될 때만 전체 엄브렐라를 다시 실행합니다.
9. 베타의 경우 `vYYYY.M.D-beta.N`을 태그한 다음, 일치하는 `release/YYYY.M.D` 브랜치에서 `OpenClaw Release Publish`를 실행합니다.
이 작업은 `pnpm plugins:sync:check`를 확인하고,
먼저 게시 가능한 모든 Plugin 패키지를 npm에 게시하며, 두 번째로 같은 세트를 ClawPack npm-pack tarball로 ClawHub에 게시한 다음,
일치하는 dist-tag로 준비된 OpenClaw npm 프리플라이트 아티팩트를 승격합니다. 게시 후에는 게시된 `openclaw@YYYY.M.D-beta.N` 또는
6. `preflight_only=true``OpenClaw NPM Release`를 실행합니다. 태그가 존재하기 전에는
전체 40자 릴리스 브랜치 SHA를 검증 전용
사전 점검에 사용할 수 있습니다. 성공한 `preflight_run_id`를 저장합니다.
7. 릴리스 브랜치, 태그 또는 전체 커밋 SHA에 대해 `Full Release Validation`으로
모든 프리릴리스 테스트를 시작합니다. 이는 네 개의 큰 릴리스 테스트 박스인
Vitest, Docker, QA Lab, Package를 위한 단일 수동 진입점입니다.
8. 검증이 실패하면 릴리스 브랜치에서 수정하고, 수정이 입증되는 가장 작은 실패
파일, 레인, 워크플로 작업, 패키지 프로필, 제공자 또는 모델 허용 목록을 다시 실행합니다.
변경된 표면 때문에 이전 증거가 오래된 경우에만 전체 우산 검증을 다시 실행합니다.
9. 베타의 경우 `vYYYY.M.D-beta.N` 태그를 지정한 다음, 일치하는
`release/YYYY.M.D` 브랜치에서 `OpenClaw Release Publish`를 실행합니다. 이는 `pnpm plugins:sync:check`를 검증하고,
모든 게시 가능한 Plugin 패키지를 먼저 npm에 게시한 뒤, 같은
세트를 두 번째로 ClawPack npm-pack tarball로 ClawHub에 게시하고, 그다음 일치하는 dist-tag로
준비된 OpenClaw npm 사전 점검 아티팩트를 승격합니다. 게시 후에는 게시된 `openclaw@YYYY.M.D-beta.N` 또는
`openclaw@beta` 패키지에 대해 게시 후 패키지
수락 검사를 실행합니다. 푸시되었거나 게시된 프리릴리스에 수정이 필요하면,
다음으로 일치하는 프리릴리스 번호를 만드세요. 이전 프리릴리스를 삭제하거나 다시 쓰지 마세요.
10. 안정 릴리스의 경우, 검증된 베타 또는 릴리스 후보가 필요한 검증 증거를 갖춘 후에만 계속합니다.
안정 npm 게시도 `OpenClaw Release Publish`를 통해 진행되며,
`preflight_run_id`로 성공한 프리플라이트 아티팩트를 재사용합니다. 안정 macOS 릴리스 준비 상태에는
패키징된 `.zip`, `.dmg`, `.dSYM.zip``main`의 업데이트된 `appcast.xml`도 필요합니다.
11. 게시 후에는 npm 게시 후 검증기, 게시 후 채널 증거가 필요할 때 선택적으로 독립 실행형
게시된-npm Telegram E2E, 필요 시 dist-tag 승격, 일치하는 전체 `CHANGELOG.md` 섹션의 GitHub 릴리스/프리릴리스 노트,
그리고 릴리스 공지 단계를 실행합니다.
수락 검사를 실행합니다. 푸시되었거나 게시된 프리릴리스에 수정이 필요하면
다음으로 일치하는 프리릴리스 번호를 자르세요. 이전
프리릴리스를 삭제하거나 다시 쓰지 마세요.
10. 안정 릴리스의 경우, 검증된 베타 또는 릴리스 후보에 필요한
검증 증거가 있을 때만 계속합니다. 안정 npm 게시 역시
`OpenClaw Release Publish`를 통해 진행하며,
`preflight_run_id`를 통해 성공한 사전 점검 아티팩트를 재사용합니다. 안정 macOS 릴리스 준비 상태에는
패키징된 `.zip`, `.dmg`, `.dSYM.zip``main`의 업데이트된 `appcast.xml`도 필요합니다.
11. 게시 후에는 npm 게시 후 검증기를 실행하고, 게시 후 채널 증거가 필요할 때 선택적 독립 실행형
게시된 npm Telegram E2E를 실행하며,
필요 시 dist-tag 승격, 일치하는 전체 `CHANGELOG.md` 섹션의 GitHub 릴리스/프리릴리스 노트,
릴리스 공지 단계를 수행합니다.
## 릴리스 프리플라이트
## 릴리스 사전 점검
- 릴리스 사전 점검 전에 `pnpm check:test-types`를 실행하여 더 빠른 로컬 `pnpm check` 게이트 밖에서도 테스트 TypeScript가 계속 적용되도록 합니다
- 릴리스 사전 점검 전에 `pnpm check:architecture`를 실행하여 더 넓은 import cycle 및 아키텍처 경계 검사가 더 빠른 로컬 게이트 밖에서도 통과하도록 합니다
- `pnpm release:check` 전에 `pnpm build && pnpm ui:build`를 실행하여 pack 검증 단계에 필요한 `dist/*` 릴리스 아티팩트와 Control UI 번들이 존재하도록 합니다
- 루트 버전 범프 후, 태그 지정 전에 `pnpm plugins:sync`를 실행합니다. 이 명령은 게시 가능한 Plugin 패키지 버전, OpenClaw 피어/API 호환성 메타데이터, 빌드 메타데이터, Plugin 변경 로그 스텁을 코어 릴리스 버전에 맞게 업데이트합니다. `pnpm plugins:sync:check`는 변경하지 않는 릴리스 가드입니다. 이 단계를 잊은 경우, 게시 워크플로는 레지스트리 변경 전에 실패합니다.
- 릴리스 승인 전에 수동 `Full Release Validation` 워크플로를 실행하여 모든 사전 릴리스 테스트 박스를 하나의 진입점에서 시작합니다. 이 워크플로는 브랜치, 태그 또는 전체 커밋 SHA를 받고, 수동 `CI`를 디스패치하며, 설치 스모크, 패키지 승인, Docker 릴리스 경로 스위트, 라이브/E2E, OpenWebUI, QA Lab 패리티, Matrix, Telegram 레인을 위한 `OpenClaw Release Checks`를 디스패치합니다. `release_profile=full``rerun_group=all`을 사용하면, 릴리스 검사에서 생성된 `release-package-under-test` 아티팩트를 대상으로 패키지 Telegram E2E도 실행합니다. 게시 후 같은 Telegram E2E가 게시된 npm 패키지도 검증해야 하는 경우 `npm_telegram_package_spec`을 제공합니다. 게시 후 Package Acceptance가 SHA로 빌드된 아티팩트 대신 배포된 npm 패키지를 대상으로 패키지/업데이트 매트릭스를 실행해야 하는 경우 `package_acceptance_package_spec`을 제공합니다. Telegram E2E를 강제하지 않고 비공개 증거 보고서가 검증 대상이 게시된 npm 패키지와 일치함을 증명해야 하는 경우 `evidence_package_spec`을 제공합니다.
- 더 빠른 로컬 `pnpm check` 게이트 밖에서도 테스트 TypeScript가
계속 포함되도록 릴리스 사전 검증 전에 `pnpm check:test-types`를 실행합니다
- 더 빠른 로컬 게이트 밖에서도 더 넓은 import
cycle 및 아키텍처 경계 검사가 통과되도록 릴리스 사전 검증 전에 `pnpm check:architecture`를 실행합니다
- pack
검증 단계에 필요한 예상 `dist/*` 릴리스 아티팩트와 Control UI 번들이 존재하도록
`pnpm release:check` 전에 `pnpm build && pnpm ui:build`를 실행합니다
- 루트 버전 올림 이후, 태그 지정 전에 `pnpm plugins:sync`를 실행합니다. 이 명령은
게시 가능한 Plugin 패키지 버전, OpenClaw 피어/API 호환성
메타데이터, 빌드 메타데이터, Plugin 변경 로그 스텁을 코어
릴리스 버전에 맞게 업데이트합니다. `pnpm plugins:sync:check`는 변경을 만들지 않는 릴리스 가드입니다.
이 단계를 잊으면 게시 워크플로는 레지스트리 변경 전에 실패합니다.
- 릴리스 승인 전에 수동 `Full Release Validation` 워크플로를 실행해
모든 사전 릴리스 테스트 박스를 하나의 진입점에서 시작합니다. 이 워크플로는 브랜치,
태그 또는 전체 커밋 SHA를 받고, 수동 `CI`를 디스패치하며,
설치 스모크, 패키지 승인, Docker
릴리스 경로 스위트, 라이브/E2E, OpenWebUI, QA Lab 패리티, Matrix, Telegram
레인을 위한 `OpenClaw Release Checks`를 디스패치합니다. `release_profile=full``rerun_group=all`을 사용하면 릴리스
검사에서 나온 `release-package-under-test` 아티팩트에 대해 패키지
Telegram E2E도 실행합니다. 동일한
Telegram E2E가 게시된 npm 패키지도 검증해야 하는 경우 게시 후
`npm_telegram_package_spec`을 제공합니다. Package Acceptance가 SHA로 빌드한 아티팩트가 아니라
출시된 npm 패키지에 대해 패키지/업데이트 매트릭스를 실행해야 하는 경우 게시 후
`package_acceptance_package_spec`을 제공합니다.
Telegram E2E를 강제하지 않고도 비공개 증거 보고서가 검증이 게시된 npm 패키지와 일치함을 증명해야 할 때는
`evidence_package_spec`을 제공합니다.
예:
`gh workflow run full-release-validation.yml --ref main -f ref=release/YYYY.M.D`
- 릴리스 작업이 계속되는 동안 패키지 후보에 대한 사이드 채널 증거가 필요할 때 수동 `Package Acceptance` 워크플로를 실행합니다. `openclaw@beta`, `openclaw@latest` 또는 정확한 릴리스 버전에는 `source=npm`을 사용하고, 현재 `workflow_ref` 하네스로 신뢰할 수 있는 `package_ref` 브랜치/태그/SHA를 pack하려면 `source=ref`를 사용하며, 필수 SHA-256이 있는 HTTPS tarball에는 `source=url`을 사용하거나, 다른 GitHub Actions 실행에서 업로드한 tarball에는 `source=artifact`를 사용합니다. 이 워크플로는 후보를 `package-under-test`로 해석하고, 해당 tarball을 대상으로 Docker E2E 릴리스 스케줄러를 재사용하며, `telegram_mode=mock-openai` 또는 `telegram_mode=live-frontier`로 같은 tarball에 대해 Telegram QA를 실행할 수 있습니다. 선택된 Docker 레인에 `published-upgrade-survivor`가 포함된 경우, 패키지 아티팩트가 후보가 되고 `published_upgrade_survivor_baseline`이 게시된 기준 버전을 선택합니다.
- 릴리스 작업이 계속되는 동안 패키지 후보에 대한 보조 채널 증거가 필요하면
수동 `Package Acceptance` 워크플로를 실행합니다. `openclaw@beta`,
`openclaw@latest` 또는 정확한 릴리스 버전에는 `source=npm`을 사용합니다. 현재
`workflow_ref` 하네스로 신뢰된 `package_ref` 브랜치/태그/SHA를 패키징하려면 `source=ref`를 사용합니다.
필수 SHA-256이 있는 HTTPS tarball에는 `source=url`을 사용합니다.
다른 GitHub
Actions 실행에서 업로드한 tarball에는 `source=artifact`를 사용합니다. 워크플로는 후보를
`package-under-test`로 해석하고, 해당
tarball에 대해 Docker E2E 릴리스 스케줄러를 재사용하며,
`telegram_mode=mock-openai` 또는 `telegram_mode=live-frontier`로 동일한 tarball에 대해 Telegram QA를 실행할 수 있습니다. 선택한 Docker 레인에
`published-upgrade-survivor`가 포함되면 패키지
아티팩트가 후보가 되고 `published_upgrade_survivor_baseline`
게시된 기준선을 선택합니다.
예: `gh workflow run package-acceptance.yml --ref main -f workflow_ref=main -f source=npm -f package_spec=openclaw@beta -f suite_profile=product -f published_upgrade_survivor_baseline=openclaw@2026.4.26 -f telegram_mode=mock-openai`
일반 프로필:
- `smoke`: 설치/채널/에이전트, Gateway 네트워크 및 구성 다시 로드 레인
- `smoke`: 설치/채널/에이전트, Gateway 네트워크, 구성 다시 로드 레인
- `package`: OpenWebUI 또는 라이브 ClawHub 없는 아티팩트 네이티브 패키지/업데이트/Plugin 레인
- `product`: 패키지 프로필에 MCP 채널, cron/subagent 정리, OpenAI 웹 검색 및 OpenWebUI 추가
- `product`: 패키지 프로필에 MCP 채널, Cron/하위 에이전트 정리,
OpenAI 웹 검색, OpenWebUI 추가
- `full`: OpenWebUI가 포함된 Docker 릴리스 경로 청크
- `custom`: 집중 재실행을 위한 정확한 `docker_lanes` 선택
- 릴리스 후보에 대한 전체 일반 CI 적용 범위만 필요할 때는 수동 `CI` 워크플로를 직접 실행합니다. 수동 CI 디스패치는 변경 범위 지정을 우회하고 Linux Node 샤드, 번들 Plugin 샤드, 채널 계약, Node 22 호환성, `check`, `check-additional`, 빌드 스모크, 문서 검사, Python Skills, Windows, macOS, Android, Control UI i18n 레인을 강제로 실행합니다.
- 릴리스 후보에 대한 전체 일반 CI
커버리지만 필요할 때는 수동 `CI` 워크플로를 직접 실행합니다. 수동 CI 디스패치는 변경 범위 지정을 우회하고
Linux Node 샤드, 번들 Plugin 샤드, 채널
계약, Node 22 호환성, `check`, `check-additional`, 빌드 스모크,
문서 검사, Python Skills, Windows, macOS, Android, Control UI i18n
레인을 강제로 실행합니다.
예: `gh workflow run ci.yml --ref release/YYYY.M.D`
- 릴리스 텔레메트리를 검증할 때 `pnpm qa:otel:smoke`를 실행합니다. 이 명령은 로컬 OTLP/HTTP 수신기를 통해 QA-lab을 실행하고, Opik, Langfuse 또는 다른 외부 수집기 없이 내보낸 trace span 이름, 제한된 속성, 콘텐츠/식별자 수정 처리를 검증합니다.
- 릴리스 텔레메트리를 검증할 때 `pnpm qa:otel:smoke`를 실행합니다. 이 명령은
로컬 OTLP/HTTP 수신기를 통해 QA-lab을 실행하고, Opik, Langfuse 또는 다른 외부 수집기 없이
내보낸 trace
span 이름, 제한된 속성, 콘텐츠/식별자 수정 처리를 검증합니다.
- 모든 태그 릴리스 전에 `pnpm release:check`를 실행합니다
- 태그가 존재한 후 변경을 수행하는 게시 순서에는 `OpenClaw Release Publish`를 실행합니다. `release/YYYY.M.D`에서 디스패치하고(`main`에서 도달 가능한 태그를 게시할 때는 `main`), 릴리스 태그와 성공한 OpenClaw npm `preflight_run_id`를 전달하며, 의도적으로 집중 복구를 실행하는 경우가 아니라면 기본 Plugin 게시 범위 `all-publishable`을 유지합니다. 이 워크플로는 Plugin npm 게시, Plugin ClawHub 게시, OpenClaw npm 게시를 직렬화하여 외부화된 Plugin보다 코어 패키지가 먼저 게시되지 않도록 합니다.
- 태그가 존재한 후 변경을 수행하는 게시 시퀀스에는 `OpenClaw Release Publish`를 실행합니다.
`release/YYYY.M.D`에서 디스패치하고(`main`에 도달 가능한 태그를 게시할 때는 `main`),
릴리스 태그와 성공한 OpenClaw npm
`preflight_run_id`를 전달하며, 의도적으로 집중 복구를 실행하는 경우가 아니면 기본 Plugin 게시 범위
`all-publishable`을 유지합니다. 이
워크플로는 Plugin npm 게시, Plugin ClawHub 게시, OpenClaw
npm 게시를 직렬화하여 외부화된
Plugin보다 코어 패키지가 먼저 게시되지 않도록 합니다.
- 릴리스 검사는 이제 별도의 수동 워크플로에서 실행됩니다:
`OpenClaw Release Checks`
- `OpenClaw Release Checks`는 릴리스 승인 전에 QA Lab mock 패리티 레인과 빠른 라이브 Matrix 프로필 및 Telegram QA 레인도 실행합니다. 라이브 레인은 `qa-live-shared` 환경을 사용하며, Telegram은 Convex CI 자격 증명 임대도 사용합니다. 전체 Matrix 전송, 미디어, E2EE 인벤토리를 병렬로 실행하려면 `matrix_profile=all``matrix_shards=true`로 수동 `QA-Lab - All Lanes` 워크플로를 실행합니다.
- Cross-OS 설치 및 업그레이드 런타임 검증은 공개 `OpenClaw Release Checks``Full Release Validation`의 일부이며, 이들은 재사용 가능 워크플로 `.github/workflows/openclaw-cross-os-release-checks-reusable.yml`을 직접 호출합니다
- 이 분리는 의도된 것입니다. 실제 npm 릴리스 경로는 짧고 결정적이며 아티팩트 중심으로 유지하고, 더 느린 라이브 검사는 자체 레인에 두어 게시를 지연하거나 차단하지 않도록 합니다
- 비밀을 포함하는 릴리스 검사는 `Full Release Validation`을 통해 또는 `main`/릴리스 워크플로 ref에서 디스패치하여 워크플로 로직과 비밀이 통제되도록 해야 합니다
- `OpenClaw Release Checks`는 해석된 커밋이 OpenClaw 브랜치 또는 릴리스 태그에서 도달 가능한 한 브랜치, 태그 또는 전체 커밋 SHA를 받습니다
- `OpenClaw NPM Release` 검증 전용 사전 점검은 푸시된 태그 없이도 현재 전체 40자 워크플로 브랜치 커밋 SHA를 받습니다
- `OpenClaw Release Checks`는 릴리스 승인 전에 QA Lab mock 패리티 레인과 빠른
라이브 Matrix 프로필 및 Telegram QA 레인도 실행합니다. 라이브
레인은 `qa-live-shared` 환경을 사용하고, Telegram은 Convex CI
자격 증명 임대도 사용합니다. 전체 Matrix
전송, 미디어, E2EE 인벤토리를 병렬로 확인하려면
`matrix_profile=all``matrix_shards=true`로 수동 `QA-Lab - All Lanes` 워크플로를 실행합니다.
- Cross-OS 설치 및 업그레이드 런타임 검증은 공개
`OpenClaw Release Checks``Full Release Validation`의 일부이며, 이들은 재사용 가능한 워크플로
`.github/workflows/openclaw-cross-os-release-checks-reusable.yml`을 직접 호출합니다
- 이 분리는 의도적입니다. 실제 npm 릴리스 경로는 짧고,
결정적이며 아티팩트 중심으로 유지하고, 더 느린 라이브 검사는 게시를 지연하거나 차단하지 않도록
자체 레인에 둡니다
- 비밀을 포함하는 릴리스 검사는 `Full Release
Validation`을 통해 또는 `main`/릴리스 워크플로 ref에서 디스패치하여 워크플로 로직과
비밀이 통제되도록 해야 합니다
- `OpenClaw Release Checks`는 해석된 커밋이 OpenClaw 브랜치 또는 릴리스 태그에서 도달 가능하다면
브랜치, 태그 또는 전체 커밋 SHA를 받습니다
- `OpenClaw NPM Release` 검증 전용 사전 검증도 푸시된 태그 없이 현재
전체 40자 워크플로 브랜치 커밋 SHA를 받습니다
- 해당 SHA 경로는 검증 전용이며 실제 게시로 승격할 수 없습니다
- SHA 모드에서 워크플로는 패키지 메타데이터 검사에만 `v<package.json version>`을 합성합니다. 실제 게시에는 여전히 실제 릴리스 태그가 필요합니다
- 두 워크플로 모두 실제 게시 및 승격 경로는 GitHub 호스팅 러너에서 유지하고, 변경하지 않는 검증 경로는 더 큰 Blacksmith Linux 러너를 사용할 수 있습니다
- 해당 워크플로는 `OPENAI_API_KEY``ANTHROPIC_API_KEY` 워크플로 비밀을 모두 사용하여
`OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`
를 실행합니다
- npm 릴리스 사전 점검은 더 이상 별도의 릴리스 검사 레인을 기다리지 않습니다
- 승인 전에 `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`
(또는 일치하는 beta/correction 태그)를 실행합니다
- npm 게시 후, 새로운 임시 prefix에서 게시된 레지스트리 설치 경로를 검증하려면
- SHA 모드에서 워크플로는 패키지 메타데이터 검사에만 `v<package.json version>`을 합성합니다.
실제 게시에는 여전히 실제 릴리스 태그가 필요합니다
- 두 워크플로 모두 실제 게시 및 승격 경로는 GitHub 호스팅
러너에서 유지하고, 변경하지 않는 검증 경로는 더 큰
Blacksmith Linux 러너를 사용할 수 있습니다
- 해당 워크플로는
`OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`
`OPENAI_API_KEY``ANTHROPIC_API_KEY` 워크플로 비밀과 함께 실행합니다
- npm 릴리스 사전 검증은 더 이상 별도 릴리스 검사 레인을 기다리지 않습니다
- 승인 전에
`RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`
(또는 일치하는 베타/수정 태그)를 실행합니다
- npm 게시 후,
`node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D`
(또는 일치하는 beta/correction 버전)를 실행합니다
- beta 게시 후, 공유 임대 Telegram 자격 증명 풀을 사용하여 게시된 npm 패키지에 대해 설치된 패키지 온보딩, Telegram 설정 및 실제 Telegram E2E를 검증하려면 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live`를 실행합니다. 로컬 메인테이너의 일회성 실행은 Convex 변수를 생략하고 세 개의 `OPENCLAW_QA_TELEGRAM_*` env 자격 증명을 직접 전달할 수 있습니다.
- 메인테이너는 수동 `NPM Telegram Beta E2E` 워크플로를 통해 GitHub Actions에서 같은 게시 후 검사를 실행할 수 있습니다. 이는 의도적으로 수동 전용이며 모든 merge마다 실행되지 않습니다.
- 메인테이너 릴리스 자동화는 이제 사전 점검 후 승격 방식을 사용합니다:
(또는 일치하는 베타/수정 버전)를 실행해 새 임시 prefix에서 게시된 레지스트리
설치 경로를 검증합니다
- 베타 게시 후, 공유 임대 Telegram 자격 증명
풀을 사용해 게시된 npm 패키지에 대해 설치 패키지 온보딩, Telegram 설정, 실제 Telegram E2E를 검증하려면
`OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live`를 실행합니다.
로컬 유지관리자 일회성 실행은 Convex 변수를 생략하고 세 개의
`OPENCLAW_QA_TELEGRAM_*` env 자격 증명을 직접 전달할 수 있습니다.
- 유지관리자 머신에서 전체 게시 후 베타 스모크를 실행하려면 `pnpm release:beta-smoke -- --beta betaN`을 사용합니다. 이 헬퍼는 Parallels npm 업데이트/새 대상 검증을 실행하고, `NPM Telegram Beta E2E`를 디스패치하며, 정확한 워크플로 실행을 폴링하고, 아티팩트를 다운로드한 뒤 Telegram 보고서를 출력합니다.
- 유지관리자는 GitHub Actions에서 수동
`NPM Telegram Beta E2E` 워크플로를 통해 동일한 게시 후 검사를 실행할 수 있습니다. 이는 의도적으로 수동 전용이며
모든 병합마다 실행되지 않습니다.
- 유지관리자 릴리스 자동화는 이제 사전 검증 후 승격을 사용합니다:
- 실제 npm 게시에는 성공한 npm `preflight_run_id`가 필요합니다
- 실제 npm 게시는 성공한 사전 점검 실행과 같은 `main` 또는 `release/YYYY.M.D` 브랜치에서 디스패치되어야 합니다
- 안정 npm 릴리스는 기본적으로 `beta`를 사용합니다
- 실제 npm 게시는 성공한 사전 검증 실행과 동일한 `main` 또는
`release/YYYY.M.D` 브랜치에서 디스패치되어야 합니다
- 안정 npm 릴리스의 기본값은 `beta`입니다
- 안정 npm 게시는 워크플로 입력을 통해 명시적으로 `latest`를 대상으로 할 수 있습니다
- 토큰 기반 npm dist-tag 변경은 이제 보안을 위해 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`에 있습니다. `npm dist-tag add`에는 여전히 `NPM_TOKEN`이 필요하지만 공개 저장소는 OIDC 전용 게시를 유지하기 때문입니다
- 공개 `macOS Release`는 검증 전용입니다. 태그가 릴리스 브랜치에만 있고 워크플로가 `main`에서 디스패치되는 경우 `public_release_branch=release/YYYY.M.D`를 설정합니다
- 실제 비공개 mac 게시에는 성공한 비공개 mac `preflight_run_id``validate_run_id`가 필요합니다
- 실제 게시 경로는 다시 빌드하지 않고 준비된 아티팩트를 승격합니다
- `YYYY.M.D-N` 같은 안정 correction 릴리스의 경우, 게시 후 검증기는 `YYYY.M.D`에서 `YYYY.M.D-N`으로의 같은 임시 prefix 업그레이드 경로도 확인하여 릴리스 correction이 이전 전역 설치를 기본 안정 페이로드에 조용히 남겨두지 못하게 합니다
- npm 릴리스 사전 점검은 tarball에 `dist/control-ui/index.html`과 비어 있지 않은 `dist/control-ui/assets/` 페이로드가 모두 포함되어 있지 않으면 닫힌 상태로 실패하므로, 빈 브라우저 대시보드를 다시 배포하지 않습니다
- 게시 후 검증은 게시된 Plugin entrypoint와 패키지 메타데이터가 설치된 레지스트리 레이아웃에 존재하는지도 확인합니다. 누락된 Plugin 런타임 페이로드를 배포하는 릴리스는 postpublish 검증기에 실패하며 `latest`로 승격될 수 없습니다.
- `pnpm test:install:smoke`는 후보 업데이트 tarball에 npm pack `unpackedSize` 예산도 적용하므로, 설치 프로그램 e2e가 릴리스 게시 경로 전에 의도치 않은 pack 비대를 포착합니다
- 릴리스 작업이 CI 계획, 확장 타이밍 매니페스트 또는 확장 테스트 매트릭스를 건드린 경우, 승인 전에 `.github/workflows/plugin-prerelease.yml`의 planner 소유 `plugin-prerelease-extension-shard` 매트릭스 출력을 다시 생성하고 검토하여 릴리스 노트가 오래된 CI 레이아웃을 설명하지 않도록 합니다
- 안정 macOS 릴리스 준비에는 updater 표면도 포함됩니다:
- GitHub 릴리스에는 패키징된 `.zip`, `.dmg`, `.dSYM.zip`이 최종적으로 포함되어야 합니다
- 게시 후 `main``appcast.xml`은 새 안정 zip을 가리켜야 합니다
- 패키징된 앱은 non-debug bundle id, 비어 있지 않은 Sparkle feed URL, 그리고 해당 릴리스 버전의 표준 Sparkle build floor 이상인 `CFBundleVersion`을 유지해야 합니다
- 토큰 기반 npm dist-tag 변경은 이제 보안을 위해
`openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`에 있습니다. 이는
`npm dist-tag add`에는 여전히 `NPM_TOKEN`이 필요하고, 공개
저장소는 OIDC 전용 게시를 유지하기 때문입니다
- 공개 `macOS Release`는 검증 전용입니다. 태그가 릴리스 브랜치에만 있고
워크플로가 `main`에서 디스패치되는 경우
`public_release_branch=release/YYYY.M.D`를 설정합니다
- 실제 비공개 mac 게시에는 성공한 비공개 mac
`preflight_run_id``validate_run_id`가 필요합니다
- 실제 게시 경로는 아티팩트를 다시 빌드하는 대신 준비된 아티팩트를 승격합니다
- `YYYY.M.D-N` 같은 안정 수정 릴리스의 경우, 게시 후 검증기는
동일한 임시 prefix 업그레이드 경로도 `YYYY.M.D`에서 `YYYY.M.D-N`으로 확인하여
릴리스 수정이 오래된 전역 설치를 기본 안정 payload에 조용히 남겨두지 못하게 합니다
- npm 릴리스 사전 검증은 tarball에
`dist/control-ui/index.html`과 비어 있지 않은 `dist/control-ui/assets/` payload가 모두 포함되지 않으면 닫힌 상태로 실패하여
빈 브라우저 대시보드를 다시 출시하지 않도록 합니다
- 게시 후 검증은 게시된 Plugin 진입점과
패키지 메타데이터가 설치된 레지스트리 레이아웃에 존재하는지도 확인합니다. 누락된 Plugin 런타임 payload를 포함해 출시된 릴리스는 postpublish 검증기에 실패하며
`latest`로 승격될 수 없습니다.
- `pnpm test:install:smoke`는 후보 업데이트 tarball에 대해 npm pack `unpackedSize` 예산도 강제하므로
설치 프로그램 e2e가 릴리스 게시 경로 전에 의도치 않은 pack 비대를 잡아냅니다
- 릴리스 작업이 CI 계획, extension 타이밍 manifest 또는
extension 테스트 매트릭스를 건드렸다면, 승인 전에
`.github/workflows/plugin-prerelease.yml`의 플래너 소유
`plugin-prerelease-extension-shard` 매트릭스 출력을 다시 생성하고 검토하여 릴리스 노트가
오래된 CI 레이아웃을 설명하지 않도록 합니다
- 안정 macOS 릴리스 준비 상태에는 업데이트 표면도 포함됩니다:
- GitHub 릴리스에는 패키징된 `.zip`, `.dmg`, `.dSYM.zip`이 최종 포함되어야 합니다
- `main``appcast.xml`은 게시 후 새 안정 zip을 가리켜야 합니다
- 패키징된 앱은 비디버그 번들 ID, 비어 있지 않은 Sparkle feed
URL, 그리고 해당 릴리스 버전의 표준 Sparkle 빌드 하한 이상인 `CFBundleVersion`을 유지해야 합니다
## 릴리스 테스트 박스
`Full Release Validation`은 운영자가 하나의 진입점에서 모든 사전 릴리스 테스트를 시작하는 방법입니다. 빠르게 움직이는 브랜치에서 고정된 커밋 증거가 필요하면, 모든 하위 워크플로가 대상 SHA에 고정된 임시 브랜치에서 실행되도록 helper를 사용합니다:
`Full Release Validation`은 운영자가 모든 사전 릴리스 테스트를
하나의 진입점에서 시작하는 방법입니다. 빠르게 움직이는 브랜치에서 고정된 커밋 증거가 필요하면,
모든 하위 워크플로가 대상
SHA에 고정된 임시 브랜치에서 실행되도록 헬퍼를 사용합니다:
```bash
pnpm ci:full-release --sha <full-sha>
```
helper는 `release-ci/<sha>-...`를 푸시하고, 해당 브랜치에서 `ref=<sha>``Full Release Validation`을 디스패치하며, 모든 하위 워크플로의 `headSha`가 대상과 일치하는지 검증한 다음 임시 브랜치를 삭제합니다. 이렇게 하면 실수로 더 새로운 `main` 하위 실행을 증명하는 일을 피할 수 있습니다.
헬퍼는 `release-ci/<sha>-...`를 푸시하고, 해당 브랜치에서 `ref=<sha>``Full Release Validation`
디스패치하며, 모든 하위 워크플로 `headSha`
대상과 일치하는지 확인한 다음 임시 브랜치를 삭제합니다. 이를 통해 실수로 더 최신
`main` 하위 실행을 증명하는 일을 피할 수 있습니다.
릴리스 브랜치 또는 태그 검증의 경우, 신뢰할 수 있는 `main` 워크플로 ref에서 실행하고 릴리스 브랜치 또는 태그를 `ref`로 전달합니다:
릴리스 브랜치 또는 태그 검증의 경우, 신뢰된 `main` 워크플로
ref에서 실행하고 릴리스 브랜치 또는 태그를 `ref`로 전달합니다:
```bash
gh workflow run full-release-validation.yml \
@ -174,19 +282,19 @@ gh workflow run full-release-validation.yml \
-f evidence_package_spec=openclaw@YYYY.M.D-beta.N
```
워크플로는 대상 ref를 확인하고, `target_ref=<release-ref>`로 수동 `CI`를 디스패치하며, `OpenClaw Release Checks`를 디스패치하고, 패키지 대상 검사에 사용할 부모 `release-package-under-test` 아티팩트를 준비하며, `release_profile=full`이고 `rerun_group=all`이거나 `npm_telegram_package_spec`이 설정된 경우 독립 실행형 패키지 Telegram E2E를 디스패치합니다. 그런 다음 `OpenClaw Release Checks`는 설치 스모크, 교차 OS 릴리스 검사, 라이브/E2E Docker 릴리스 경로 커버리지, Telegram 패키지 QA가 포함된 패키지 승인, QA Lab 패리티, 라이브 Matrix, 라이브 Telegram으로 확장 실행됩니다. 전체 실행은 `Full Release Validation` 요약에서 `normal_ci``release_checks`가 성공으로 표시될 때만 허용됩니다. full/all 모드에서는 `npm_telegram` 자식도 성공해야 합니다. full/all이 아닌 경우 게시된 `npm_telegram_package_spec`이 제공되지 않는 한 건너뜁니다. 최종 검증기 요약에는 각 자식 실행의 가장 느린 작업 테이블이 포함되어 릴리스 관리자가 로그를 다운로드하지 않고도 현재 핵심 경로를 확인할 수 있습니다.
전체 단계 매트릭스, 정확한 워크플로 작업 이름, stable 프로필과 full 프로필의 차이, 아티팩트, 집중 재실행 핸들은 [전체 릴리스 검증](/ko/reference/full-release-validation)을 참하세요.
자식 워크플로는 `Full Release Validation`을 실행하는 신뢰할 수 있는 ref, 일반적으로 `--ref main`에서 디스패치됩니다. 대상 `ref`가 더 오래된 릴리스 브랜치나 태그를 가리키는 경우에도 마찬가지입니다. 별도의 Full Release Validation workflow-ref 입력은 없습니다. 워크플로 실행 ref를 선택하여 신뢰할 수 있는 하네스를 선택하세요.
이동하는 `main`에서 정확한 커밋 증명을 위해 `--ref main -f ref=<sha>`를 사용하지 마세요. 원시 커밋 SHA는 워크플로 디스패치 ref가 될 수 없으므로 `pnpm ci:full-release --sha <sha>`를 사용 고정된 임시 브랜치를 생성하세요.
워크플로는 대상 ref를 해석하고, `target_ref=<release-ref>`로 수동 `CI`를 디스패치하며, `OpenClaw Release Checks`를 디스패치하고, 패키지 대상 검사용 상위 `release-package-under-test` 아티팩트를 준비하며, `release_profile=full`이고 `rerun_group=all`이거나 `npm_telegram_package_spec`이 설정된 경우 독립 실행형 패키지 Telegram E2E를 디스패치합니다. 그런 다음 `OpenClaw Release Checks`는 설치 스모크, 교차 OS 릴리스 검사, 라이브/E2E Docker 릴리스 경로 커버리지, Telegram 패키지 QA가 포함된 Package Acceptance, QA Lab 패리티, 라이브 Matrix, 라이브 Telegram으로 확장됩니다. 전체 실행은 `Full Release Validation` 요약에서 `normal_ci``release_checks`가 성공으로 표시될 때만 허용됩니다. full/all 모드에서는 `npm_telegram` 하위 항목도 성공해야 합니다. full/all 외부에서는 게시된 `npm_telegram_package_spec`이 제공되지 않는 한 건너뜁니다. 최종 검증자 요약에는 각 하위 실행의 가장 느린 작업 표가 포함되어 있어, 릴리스 관리자가 로그를 다운로드하지 않고도 현재 주요 경로를 확인할 수 있습니다.
전체 단계 매트릭스, 정확한 워크플로 작업 이름, stable 프로필과 full 프로필의 차이, 아티팩트, 집중 재실행 핸들은 [전체 릴리스 검증](/ko/reference/full-release-validation)을 참하세요.
하위 워크플로는 `Full Release Validation`을 실행하는 신뢰된 ref에서 디스패치되며, 대상 `ref`가 이전 릴리스 브랜치나 태그를 가리키더라도 일반적으로 `--ref main`입니다. 별도의 Full Release Validation workflow-ref 입력은 없습니다. 워크플로 실행 ref를 선택하여 신뢰 하네스를 선택하세요.
이동 중인 `main`에서 정확한 커밋 증명에 `--ref main -f ref=<sha>`를 사용하지 마세요. 원시 커밋 SHA는 워크플로 디스패치 ref가 될 수 없으므로, `pnpm ci:full-release --sha <sha>`를 사용하여 고정된 임시 브랜치를 생성하세요.
라이브/제공자 범위를 선택하려면 `release_profile`을 사용하세요.
라이브/프로바이더 범위를 선택하려면 `release_profile`을 사용하세요.
- `minimum`: 가장 빠른 릴리스 핵심 OpenAI/코어 라이브 및 Docker 경로
- `stable`: 릴리스 승인을 위한 minimum에 stable 제공자/백엔드 커버리지 추가
- `full`: stable에 광범위한 권고 제공자/미디어 커버리지 추가
- `stable`: minimum에 릴리스 승인을 위한 stable 프로바이더/백엔드 커버리지 추가
- `full`: stable에 광범위한 자문 프로바이더/미디어 커버리지 추가
`OpenClaw Release Checks`는 신뢰할 수 있는 워크플로 ref를 사용해 대상 ref를 한 번 `release-package-under-test`로 확인하고, 해당 아티팩트를 릴리스 경로 Docker 검사와 패키지 승인 모두에서 재사용합니다. 이렇게 하면 모든 패키지 대상 박스가 동일한 바이트를 사용하고 반복적인 패키지 빌드를 피할 수 있습니다.
교차 OS OpenAI 설치 스모크는 repo/org 변수가 설정된 경우 `OPENCLAW_CROSS_OS_OPENAI_MODEL`을 사용하고, 그렇지 않으면 `openai/gpt-5.4`를 사용합니다. 이 레인은 가장 느린 기본 모델을 벤치마킹하는 것이 아니라 패키지 설치, 온보딩, Gateway 시작, 라이브 에이전트 턴 하나를 증명하기 때문입니다. 더 넓은 라이브 제공자 매트릭스는 모델별 커버리지를 위한 위치로 유지됩니다.
`OpenClaw Release Checks`는 신뢰된 워크플로 ref를 사용하여 대상 ref를 한 번 `release-package-under-test`로 해석하고, 릴리스 경로 Docker 검사와 Package Acceptance 모두에서 해당 아티팩트를 재사용합니다. 이렇게 하면 모든 패키지 대상 박스가 동일한 바이트를 사용하고 반복적인 패키지 빌드를 피할 수 있습니다.
교차 OS OpenAI 설치 스모크는 repo/org 변수가 설정된 경우 `OPENCLAW_CROSS_OS_OPENAI_MODEL`을 사용하고, 그렇지 않으면 `openai/gpt-5.4`를 사용합니다. 이 레인은 가장 느린 기본 모델을 벤치마킹하는 것이 아니라 패키지 설치, 온보딩, gateway 시작, 라이브 agent 턴 1회를 증명하기 때문입니다. 더 넓은 라이브 프로바이더 매트릭스는 모델별 커버리지를 위한 위치로 유지됩니다.
릴리스 단계에 따라 다음 변형을 사용하세요.
@ -218,22 +326,23 @@ gh workflow run full-release-validation.yml \
-f npm_telegram_provider_mode=mock-openai
```
집중 수정 후 첫 재실행으로 전체 엄브렐라를 사용하지 마세요. 하나의 박스가 실패하면 다음 증명에는 실패한 자식 워크플로, 작업, Docker 레인, 패키지 프로필, 모델 제공자, 또는 QA 레인을 사용하세요. 수정이 공유 릴리스 오케스트레이션을 변경했거나 이전의 전체 박스 증거를 오래된 것으로 만든 경우에만 전체 엄브렐라를 다시 실행하세요. 엄브렐라의 최종 검증기는 기록된 자식 워크플로 실행 ID를 다시 확인하므로, 자식 워크플로가 성공적으로 재실행된 후에는 실패한 부모 `Verify full validation` 작업만 재실행하세요.
집중 수정 후 첫 재실행으로 전체 엄브렐라를 사용하지 마세요. 하나의 박스가 실패하면 다음 증명에는 실패한 하위 워크플로, 작업, Docker 레인, 패키지 프로필, 모델 프로바이더 또는 QA 레인을 사용하세요. 수정이 공유 릴리스 오케스트레이션을 변경했거나 이전의 전체 박스 증거를 더 이상 신뢰할 수 없게 만든 경우에만 전체 엄브렐라를 다시 실행하세요. 엄브렐라의 최종 검증자는 기록된 하위 워크플로 실행 ID를 다시 확인하므로, 하위 워크플로가 성공적으로 재실행된 후에는 실패한 상위 `Verify full validation` 작업만 다시 실행하세요.
제한된 복구에는 엄브렐라에 `rerun_group`을 전달하세요. `all`은 실제 릴리스 후보 실행이고, `ci`는 일반 CI 자식만 실행하며, `plugin-prerelease`는 릴리스 전용 Plugin 자식만 실행하고, `release-checks`는 모든 릴리스 박스를 실행합니다. 더 좁은 릴리스 그룹은 `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, `npm-telegram`입니다. 집중 `npm-telegram` 재실행에는 `npm_telegram_package_spec`이 필요합니다. `release_profile=full`인 full/all 실행은 release-checks 패키지 아티팩트를 사용합니다.
제한된 복구에는 엄브렐라에 `rerun_group`을 전달하세요. `all`은 실제 릴리스 후보 실행이고, `ci`는 일반 CI 하위 항목만 실행하며, `plugin-prerelease`는 릴리스 전용 Plugin 하위 항목만 실행하고, `release-checks`는 모든 릴리스 박스를 실행합니다. 더 좁은 릴리스 그룹은 `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, `npm-telegram`입니다.
집중 `npm-telegram` 재실행에는 `npm_telegram_package_spec`이 필요합니다. `release_profile=full`인 full/all 실행은 release-checks 패키지 아티팩트를 사용합니다.
### Vitest
Vitest 박스는 수동 `CI` 자식 워크플로입니다. 수동 CI는 의도적으로 변경 범위 지정을 우회하고 릴리스 후보에 대해 일반 테스트 그래프를 강제합니다. Linux Node 샤드, 번들 Plugin 샤드, 채널 계약, Node 22 호환성, `check`, `check-additional`, 빌드 스모크, 문서 검사, Python Skills, Windows, macOS, Android, Control UI i18n이 포함됩니다.
Vitest 박스는 수동 `CI` 하위 워크플로입니다. 수동 CI는 의도적으로 변경 범위 지정은 우회하고 릴리스 후보에 대해 일반 테스트 그래프를 강제합니다. Linux Node 샤드, 번들 Plugin 샤드, 채널 계약, Node 22 호환성, `check`, `check-additional`, 빌드 스모크, 문서 검사, Python skills, Windows, macOS, Android, Control UI i18n이 포함됩니다.
"소스 트리가 전체 일반 테스트 스위트를 통과했는가?"에 답하려면 이 박스를 사용하세요. 이는 릴리스 경로 제품 검증과 같지 않습니다. 보관할 증거:
이 박스는 "소스 트리가 전체 일반 테스트 스위트를 통과했는가?"에 답하는 데 사용하세요. 릴리스 경로 제품 검증과는 다릅니다. 보관할 증거:
- 디스패치된 `CI` 실행 URL을 보여주는 `Full Release Validation` 요약
- 정확한 대상 SHA에서 성공한 `CI` 실행
- 회귀를 조사할 때 CI 작업에서 실패했거나 느린 샤드 이름
- 실행에 성능 분석이 필요할 때 `.artifacts/vitest-shard-timings.json` 같은 Vitest 타이밍 아티팩트
- 정확한 대상 SHA에서 초록색인 `CI` 실행
- 회귀를 조사할 때 CI 작업 실패했거나 느린 샤드 이름
- 실행에 성능 분석이 필요한 경우 `.artifacts/vitest-shard-timings.json` 같은 Vitest 타이밍 아티팩트
릴리스에 결정론적인 일반 CI가 필요하지만 Docker, QA Lab, 라이브, 교차 OS, 또는 패키지 박스가 필요하지 않은 경우에만 수동 CI를 직접 실행하세요.
릴리스에 결정론적인 일반 CI가 필요하지만 Docker, QA Lab, 라이브, 교차 OS 또는 패키지 박스는 필요하지 않은 경우에만 수동 CI를 직접 실행하세요.
```bash
gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D
@ -241,51 +350,52 @@ gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D
### Docker
Docker 박스는 `openclaw-live-and-e2e-checks-reusable.yml`과 릴리스 모드 `install-smoke` 워크플로를 통해 `OpenClaw Release Checks` 안에 있습니다. 이는 소스 수준 테스트만이 아니라 패키징된 Docker 환경을 통해 릴리스 후보를 검증합니다.
Docker 박스는 `openclaw-live-and-e2e-checks-reusable.yml`을 통해 `OpenClaw Release Checks` 안에 있으며, 릴리스 모드 `install-smoke` 워크플로도 포함됩니다. 소스 수준 테스트만이 아니라 패키징된 Docker 환경을 통해 릴리스 후보를 검증합니다.
릴리스 Docker 커버리지에는 다음이 포함됩니다.
- 느린 Bun 전역 설치 스모크가 활성화된 전체 설치 스모크
- 대상 SHA별 루트 Dockerfile 스모크 이미지 준비/재사용, QR, root/gateway, installer/Bun 스모크 작업은 별도 install-smoke 샤드로 실행
- 대상 SHA별 루트 Dockerfile 스모크 이미지 준비/재사용. QR, 루트/gateway, 설치 프로그램/Bun 스모크 작업은 별도 install-smoke 샤드로 실행
- 저장소 E2E 레인
- 릴리스 경로 Docker 청크: `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services`, `plugins-runtime-install-a`, `plugins-runtime-install-b`, `plugins-runtime-install-c`, `plugins-runtime-install-d`, `plugins-runtime-install-e`, `plugins-runtime-install-f`, `plugins-runtime-install-g`, `plugins-runtime-install-h`
- 요청 `plugins-runtime-services` 청크 내부의 OpenWebUI 커버리지
- 요청된 경우 `plugins-runtime-services` 청크 내부의 OpenWebUI 커버리지
- `bundled-plugin-install-uninstall-0`부터 `bundled-plugin-install-uninstall-23`까지 분할된 번들 Plugin 설치/제거 레인
- 릴리스 검사가 라이브 스위트를 포함할 때 라이브/E2E 제공자 스위트 및 Docker 라이브 모델 커버리지
- 릴리스 검사가 라이브 스위트를 포함할 때 라이브/E2E 프로바이더 스위트 및 Docker 라이브 모델 커버리지
재실행하기 전에 Docker 아티팩트를 사용하세요. 릴리스 경로 스케줄러는 레인 로그, `summary.json`, `failures.json`, 단계 타이밍, 스케줄러 계획 JSON, 재실행 명령이 포함된 `.artifacts/docker-tests/`를 업로드합니다. 집중 복구에는 모든 릴리스 청크를 재실행하는 대신 재사용 가능한 라이브/E2E 워크플로에서 `docker_lanes=<lane[,lane]>`을 사용하세요. 생성된 재실행 명령에는 가능한 경우 이전 `package_artifact_run_id`와 준비된 Docker 이미지 입력이 포함되므로 실패한 레인이 동일한 tarball과 GHCR 이미지를 재사용할 수 있습니다.
재실행하기 전에 Docker 아티팩트를 사용하세요. 릴리스 경로 스케줄러는 레인 로그, `summary.json`, `failures.json`, 단계 타이밍, 스케줄러 계획 JSON, 재실행 명령이 포함된 `.artifacts/docker-tests/`를 업로드합니다. 집중 복구에는 모든 릴리스 청크를 다시 실행하는 대신 재사용 가능한 live/E2E 워크플로에서 `docker_lanes=<lane[,lane]>`을 사용하세요. 생성된 재실행 명령에는 사용 가능한 경우 이전 `package_artifact_run_id`와 준비된 Docker 이미지 입력이 포함되므로, 실패한 레인이 동일한 tarball과 GHCR 이미지를 재사용할 수 있습니다.
### QA Lab
QA Lab 박스도 `OpenClaw Release Checks`의 일부입니다. 이는 Vitest 및 Docker 패키지 메커니즘과 별개인 에이전트 동작 및 채널 수준 릴리스 게이트입니다.
QA Lab 박스도 `OpenClaw Release Checks`의 일부입니다. Vitest 및 Docker 패키지 메커니즘과 별개인 agentic 동작 및 채널 수준 릴리스 게이트입니다.
릴리스 QA Lab 커버리지에는 다음이 포함됩니다.
- 에이전트 패리티 팩을 사용해 OpenAI 후보 레인을 Opus 4.6 기준선과 비교하는 mock 패리티 레인
- agentic 패리티 팩을 사용해 OpenAI 후보 레인을 Opus 4.6 기준선과 비교하는 mock 패리티 레인
- `qa-live-shared` 환경을 사용하는 빠른 라이브 Matrix QA 프로필
- Convex CI 자격 증명 임대를 사용하는 라이브 Telegram QA 레인
- 릴리스 텔레메트리에 명시적 로컬 증명이 필요할 때 `pnpm qa:otel:smoke`
- 릴리스 텔레메트리에 명시적 로컬 증명이 필요한 경우 `pnpm qa:otel:smoke`
"릴리스가 QA 시나리오와 라이브 채널 흐름에서 올바르게 동작하는가?"에 답하려면 이 박스를 사용하세요. 릴리스를 승인할 때 패리티, Matrix, Telegram 레인의 아티팩트 URL을 보관하세요. 전체 Matrix 커버리지는 기본 릴리스 핵심 레인이 아니라 수동 샤딩 QA-Lab 실행으로 계속 사용할 수 있습니다.
이 박스는 "릴리스가 QA 시나리오와 라이브 채널 흐름에서 올바르게 동작하는가?"에 답하는 데 사용하세요. 릴리스를 승인할 때 패리티, Matrix, Telegram 레인의 아티팩트 URL을 보관하세요. 전체 Matrix 커버리지는 기본 릴리스 핵심 레인이 아니라 수동 샤딩 QA-Lab 실행으로 계속 사용할 수 있습니다.
### 패키지
패키지 박스는 설치 가능한 제품 게이트입니다. 이는 `Package Acceptance`와 resolver `scripts/resolve-openclaw-package-candidate.mjs`를 기반으로 합니다. resolver는 후보를 Docker E2E가 소비하는 `package-under-test` tarball로 정규화하고, 패키지 인벤토리를 검증하며, 패키지 버전과 SHA-256을 기록하고, 워크플로 하네스 ref를 패키지 소스 ref와 분리해 유지합니다.
Package 박스는 설치 가능한 제품 게이트입니다. `Package Acceptance`와 해석기 `scripts/resolve-openclaw-package-candidate.mjs`가 뒷받침합니다. 해석기는 후보를 Docker E2E가 소비하는 `package-under-test` tarball로 정규화하고, 패키지 인벤토리를 검증하며, 패키지 버전과 SHA-256을 기록하고, 워크플로 하네스 ref를 패키지 소스 ref와 분리해 유지합니다.
지원되는 후보 소스:
- `source=npm`: `openclaw@beta`, `openclaw@latest`, 또는 정확한 OpenClaw 릴리스 버전
- `source=ref`: 선택한 `workflow_ref` 하네스로 신뢰할 수 있는 `package_ref` 브랜치, 태그, 또는 전체 커밋 SHA를 패킹
- `source=ref`: 선택한 `workflow_ref` 하네스로 신뢰`package_ref` 브랜치, 태그 또는 전체 커밋 SHA를 패키징
- `source=url`: 필수 `package_sha256`이 있는 HTTPS `.tgz` 다운로드
- `source=artifact`: 다른 GitHub Actions 실행에서 업로드한 `.tgz` 재사용
`OpenClaw Release Checks``source=artifact`, 준비된 릴리스 패키지 아티팩트, `suite_profile=custom`, `docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update`, `published_upgrade_survivor_baselines=all-since-2026.4.23`, `published_upgrade_survivor_scenarios=reported-issues`, `telegram_mode=mock-openai`패키지 승인을 실행합니다. 패키지 승인은 마이그레이션, 업데이트, 오래된 Plugin 종속성 정리, 오프라인 Plugin 픽스처, Plugin 업데이트, Telegram 패키지 QA를 동일하게 확인된 tarball에 대해 유지합니다. 업그레이드 매트릭스는 `2026.4.23`부터 `latest`까지 npm에 게시된 모든 stable 기준선을 포괄합니다. 이미 출시된 후보에는 `source=npm`으로 패키지 승인을 사용하고, 게시 전 SHA 기반 로컬 npm tarball에는 `source=ref`/`source=artifact`를 사용하세요. 이는 이전에 Parallels가 필요했던 대부분의 패키지/업데이트 커버리지를 대체하는 GitHub 네이티브 방식입니다. 교차 OS 릴리스 검사는 OS별 온보딩, 설치 관리자, 플랫폼 동작에 여전히 중요하지만, 패키지/업데이트 제품 검증은 패키지 승인을 우선해야 합니다.
`OpenClaw Release Checks``source=artifact`, 준비된 릴리스 패키지 아티팩트, `suite_profile=custom`, `docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update`, `published_upgrade_survivor_baselines=all-since-2026.4.23`, `published_upgrade_survivor_scenarios=reported-issues`, `telegram_mode=mock-openai`Package Acceptance를 실행합니다. Package Acceptance는 동일하게 해석된 tarball에 대해 마이그레이션, 업데이트, 오래된 Plugin 종속성 정리, 오프라인 Plugin fixture, Plugin 업데이트, Telegram 패키지 QA를 유지합니다. 업그레이드 매트릭스는 `2026.4.23`부터 `latest`까지 npm에 게시된 모든 stable 기준선을 포함합니다. 이미 배포된 후보에는 `source=npm`으로 Package Acceptance를 사용하고, 게시 전 SHA 기반 로컬 npm tarball에는 `source=ref`/`source=artifact`를 사용하세요. 이는 이전에 Parallels가 필요했던 대부분의 패키지/업데이트 커버리지를 대체하는 GitHub 네이티브 방식입니다. 교차 OS 릴리스 검사는 OS별 온보딩, 설치 프로그램, 플랫폼 동작에 여전히 중요하지만, 패키지/업데이트 제품 검증에는 Package Acceptance를 우선해야 합니다.
업데이트 및 Plugin 검증을 위한 표준 체크리스트는 [업데이트 및 Plugin 테스트](/ko/help/testing-updates-plugins)입니다. Plugin 설치/업데이트, doctor 정리, 또는 게시된 패키지 마이그레이션 변경을 증명하는 로컬, Docker, 패키지 승인, 또는 release-check 레인을 결정할 때 사용하세요. 모든 stable `2026.4.23+` 패키지에서 게시된 업데이트 마이그레이션을 포괄적으로 수행하는 것은 Full Release CI의 일부가 아니라 별도의 수동 `Update Migration` 워크플로입니다.
업데이트 및 Plugin 검증을 위한 표준 체크리스트는 [업데이트 및 Plugin 테스트](/ko/help/testing-updates-plugins)입니다. Plugin 설치/업데이트, doctor 정리 또는 게시된 패키지 마이그레이션 변경을 어떤 로컬, Docker, Package Acceptance 또는 release-check 레인이 증명하는지 결정할 때 사용하세요.
모든 stable `2026.4.23+` 패키지에서 수행하는 철저한 게시 업데이트 마이그레이션은 별도의 수동 `Update Migration` 워크플로이며, Full Release CI의 일부가 아닙니다.
레거시 package-acceptance 완화는 의도적으로 시간 제한이 있습니다. `2026.4.25`까지의 패키지는 이미 npm에 게시된 메타데이터 공백에 대해 호환성 경로를 사용할 수 있습니다. tarball에 누락된 private QA 인벤토리 항목, 누락된 `gateway install --wrapper`, tarball 파생 git 픽스처에 누락된 패치 파일, 누락된 영속 `update.channel`, 레거시 Plugin 설치 기록 위치, 누락된 marketplace 설치 기록 영속성, `plugins update` 중 config 메타데이터 마이그레이션이 포함됩니다. 게시된 `2026.4.26` 패키지는 이미 출시된 로컬 빌드 메타데이터 스탬프 파일에 대해 경고할 수 있습니다. 이후 패키지는 최신 패키지 계약을 충족해야 하며, 동일한 공백은 릴리스 검증에 실패합니다.
기존 package-acceptance 관대함은 의도적으로 시간 제한이 있습니다. `2026.4.25`까지의 패키지는 npm에 이미 게시된 메타데이터 공백에 대해 호환성 경로를 사용할 수 있습니다. tarball에서 누락된 비공개 QA 인벤토리 항목, 누락된 `gateway install --wrapper`, tarball에서 파생된 git fixture의 누락된 패치 파일, 누락된 영구 `update.channel`, 기존 Plugin 설치 기록 위치, 누락된 marketplace 설치 기록 영속성, `plugins update` 중 config 메타데이터 마이그레이션이 여기에 포함됩니다. 게시된 `2026.4.26` 패키지는 이미 배포된 로컬 빌드 메타데이터 스탬프 파일에 대해 경고할 수 있습니다. 이후 패키지는 현대적인 패키지 계약을 충족해야 하며, 동일한 공백은 릴리스 검증에 실패합니다.
릴리스 질문이 실제 설치 가능한 패키지에 관한 것이라면 더 넓은 패키지 승인 프로필을 사용하세요.
릴리스 질문이 실제 설치 가능한 패키지에 관한 것이라면 더 넓은 Package Acceptance 프로필을 사용하세요.
```bash
gh workflow run package-acceptance.yml \
@ -297,26 +407,26 @@ gh workflow run package-acceptance.yml \
-f published_upgrade_survivor_baseline=openclaw@2026.4.26
```
일반 패키지 프로필:
일반적인 패키지 프로필:
- `smoke`: 빠른 패키지 설치/채널/에이전트, Gateway 네트워크, 구성
다시 로드 레인
- `smoke`: 빠른 패키지 설치/채널/에이전트, Gateway 네트워크 및 config
reload 레인
- `package`: 라이브 ClawHub 없이 설치/업데이트/Plugin 패키지 계약을 확인합니다. 이것이 릴리스 검사
기본값입니다.
- `product`: `package`에 MCP 채널, cron/subagent 정리, OpenAI 웹
검색, OpenWebUI를 더한 항목
기본값입니다
- `product`: `package`에 MCP 채널, cron/하위 에이전트 정리, OpenAI 웹
검색 및 OpenWebUI를 추가합니다
- `full`: OpenWebUI가 포함된 Docker 릴리스 경로 청크
- `custom`: 집중 재실행을 위한 정확한 `docker_lanes` 목록
패키지 후보 Telegram 증명을 위해 Package Acceptance에서 `telegram_mode=mock-openai` 또는
패키지 후보 Telegram 검증에는 Package Acceptance에서 `telegram_mode=mock-openai` 또는
`telegram_mode=live-frontier`를 활성화하세요. 워크플로는 확인된
`package-under-test` tarball을 Telegram 레인으로 전달합니다. 독립 실행형
Telegram 워크플로는 게시 후 검사를 위해 게시된 npm 명세도 계속 허용합니다.
`package-under-test` 타르볼을 Telegram 레인에 전달합니다. 독립 실행형
Telegram 워크플로는 게시 후 검사를 위해 여전히 게시된 npm 사양을 받습니다.
## 릴리스 게시 자동화
`OpenClaw Release Publish`는 일반적인 변경 적용 게시 진입점입니다. 이 워크플로는
릴리스에 필요한 순서대로 trusted-publisher 워크플로를 오케스트레이션합니다.
`OpenClaw Release Publish`는 일반적인 변경 게시 진입점입니다. 이 워크플로는
릴리스에 필요한 순서대로 신뢰할 수 있는 게시자 워크플로를 오케스트레이션합니다.
1. 릴리스 태그를 체크아웃하고 해당 커밋 SHA를 확인합니다.
2. 태그가 `main` 또는 `release/*`에서 도달 가능한지 확인합니다.
@ -337,7 +447,7 @@ gh workflow run openclaw-release-publish.yml \
-f npm_dist_tag=beta
```
기본 beta dist-tag로 안정 릴리스 게시:
기본 beta dist-tag로 안정 버전 게시:
```bash
gh workflow run openclaw-release-publish.yml \
@ -347,7 +457,7 @@ gh workflow run openclaw-release-publish.yml \
-f npm_dist_tag=beta
```
`latest`로 직접 안정 승격하는 것은 명시적입니다.
`latest`로 직접 안정 버전을 승격하는 것은 명시적입니다.
```bash
gh workflow run openclaw-release-publish.yml \
@ -360,79 +470,81 @@ gh workflow run openclaw-release-publish.yml \
하위 수준 `Plugin NPM Release``Plugin ClawHub Release` 워크플로는
집중 복구 또는 재게시 작업에만 사용하세요. 선택한 Plugin 복구의 경우
`plugin_publish_scope=selected``plugins=@openclaw/name`
`OpenClaw Release Publish`에 전달하거나, OpenClaw 패키지를 게시하면 안 되는 경우
`OpenClaw Release Publish`에 전달하거나, OpenClaw 패키지가 게시되면 안 되는 경우
자식 워크플로를 직접 디스패치하세요.
## NPM 워크플로 입력
`OpenClaw NPM Release`는 운영자가 제어하는 다음 입력을 허용합니다.
`OpenClaw NPM Release`는 운영자가 제어하는 다음 입력을 받습니다.
- `tag`: `v2026.4.2`, `v2026.4.2-1` 또는
`v2026.4.2-beta.1` 같은 필수 릴리스 태그입니다. `preflight_only=true`일 때는 검증 전용 preflight를 위해 현재의
전체 40자 워크플로 브랜치 커밋 SHA도 사용할 수 있습니다.
- `preflight_only`: 검증/빌드/패키지만 수행하려면 `true`, 실제 게시 경로에는 `false`
- `preflight_run_id`: 실제 게시 경로에서 필요하며, 워크플로가 성공한 preflight 실행에서 준비된 tarball을 재사용하도록 합니다.
- `npm_dist_tag`: 게시 경로의 npm 대상 태그입니다. 기본값은 `beta`입니다.
- `tag`: 필수 릴리스 태그입니다. 예: `v2026.4.2`, `v2026.4.2-1` 또는
`v2026.4.2-beta.1`. `preflight_only=true`인 경우, 검증 전용 프리플라이트를 위해 현재
전체 40자 워크플로 브랜치 커밋 SHA도 사용할 수 있습니다
- `preflight_only`: 검증/빌드/패키지만 수행하려면 `true`, 실제 게시 경로는 `false`
- `preflight_run_id`: 실제 게시 경로에서 필요합니다. 워크플로가 성공한 프리플라이트 실행에서
준비된 타르볼을 재사용하도록 합니다
- `npm_dist_tag`: 게시 경로의 npm 대상 태그입니다. 기본값은 `beta`입니다
`OpenClaw Release Publish`는 운영자가 제어하는 다음 입력을 허용합니다.
`OpenClaw Release Publish`는 운영자가 제어하는 다음 입력을 받습니다.
- `tag`: 필수 릴리스 태그입니다. 이미 존재해야 합니다.
- `preflight_run_id`: 성공한 `OpenClaw NPM Release` preflight 실행 ID입니다.
`publish_openclaw_npm=true`일 때 필요합니다.
- `tag`: 필수 릴리스 태그입니다. 이미 존재해야 합니다
- `preflight_run_id`: 성공한 `OpenClaw NPM Release` 프리플라이트 실행 ID입니다.
`publish_openclaw_npm=true`일 때 필요합니다
- `npm_dist_tag`: OpenClaw 패키지의 npm 대상 태그
- `plugin_publish_scope`: 기본값은 `all-publishable`입니다. 집중 복구 작업에만
`selected`를 사용하세요.
- `plugins`: `plugin_publish_scope=selected`일 때 쉼표로 구분 `@openclaw/*` 패키지 이름
- `publish_openclaw_npm`: 기본값은 `true`입니다. 워크플로를 Plugin 전용 복구 오케스트레이터로 사용할 때만
`false`로 설정하세요.
`selected`를 사용하세요
- `plugins`: `plugin_publish_scope=selected`일 때 쉼표로 구분 `@openclaw/*` 패키지 이름
- `publish_openclaw_npm`: 기본값은 `true`입니다. 워크플로를 Plugin 전용 복구 오케스트레이터로
사용할 때만 `false`로 설정하세요
`OpenClaw Release Checks`는 운영자가 제어하는 다음 입력을 허용합니다.
`OpenClaw Release Checks`는 운영자가 제어하는 다음 입력을 받습니다.
- `ref`: 검증할 브랜치, 태그 또는 전체 커밋 SHA입니다. 시크릿을 사용하는 검사는
- `ref`: 검증할 브랜치, 태그 또는 전체 커밋 SHA입니다. 시크릿이 필요한 검사는
확인된 커밋이 OpenClaw 브랜치 또는 릴리스 태그에서 도달 가능해야 합니다.
규칙:
- 안정 및 수정 태그는 `beta` 또는 `latest` 중 하나로 게시할 수 있습니다.
- 베타 사전 릴리스 태그는 `beta`로만 게시할 수 있습니다.
- `OpenClaw NPM Release`에서 전체 커밋 SHA 입력은 `preflight_only=true`일 때만 허용됩니다.
- `OpenClaw Release Checks` `Full Release Validation`은 항상 검증 전용입니다.
- 실제 게시 경로는 preflight 중에 사용한 것과 동일한 `npm_dist_tag`를 사용해야 합니다.
워크플로는 게시를 계속하기 전에 해당 메타데이터를 확인합니다.
- 안정 버전 및 수정 태그는 `beta` 또는 `latest` 중 하나로 게시할 수 있습니다
- 베타 프리릴리스 태그는 `beta`로만 게시할 수 있습니다
- `OpenClaw NPM Release`의 경우 전체 커밋 SHA 입력은 `preflight_only=true`일 때만 허용됩니다
- `OpenClaw Release Checks` `Full Release Validation`은 항상 검증 전용입니다
- 실제 게시 경로는 프리플라이트 중 사용한 것과 동일한 `npm_dist_tag`를 사용해야 합니다.
워크플로는 게시가 계속되기 전에 해당 메타데이터를 확인합니다
## 안정 npm 릴리스 순서
안정 npm 릴리스를 만들 때:
1. `preflight_only=true``OpenClaw NPM Release`를 실행합니다.
- 태그가 존재하기 전에는 preflight 워크플로의 검증 전용 드라이 런을 위해 현재 전체 워크플로 브랜치 커밋
SHA를 사용할 수 있습니다.
2. 일반적인 beta-first 흐름에는 `npm_dist_tag=beta`를 선택하고, 의도적으로 직접 안정 게시를 원하는 경우에만
`latest`를 선택합니다.
1. `preflight_only=true``OpenClaw NPM Release`를 실행합니다
- 태그가 존재하기 전에는 프리플라이트 워크플로의 검증 전용 드라이런을 위해 현재 전체 워크플로 브랜치 커밋
SHA를 사용할 수 있습니다
2. 일반적인 beta 우선 흐름에는 `npm_dist_tag=beta`를 선택하고, 직접 안정 버전 게시를 의도한 경우에만
`latest`를 선택합니다
3. 하나의 수동 워크플로에서 일반 CI와 라이브 프롬프트 캐시, Docker, QA Lab,
Matrix, Telegram 범위를 함께 원할 때 릴리스 브랜치, 릴리스 태그 또는 전체
커밋 SHA에서 `Full Release Validation`을 실행합니다.
Matrix, Telegram 커버리지를 원할 때는 릴리스 브랜치, 릴리스 태그 또는 전체
커밋 SHA에서 `Full Release Validation`을 실행합니다
4. 결정론적인 일반 테스트 그래프만 의도적으로 필요한 경우, 대신 릴리스 ref에서
수동 `CI` 워크플로를 실행합니다.
5. 성공한 `preflight_run_id`를 저장합니다.
수동 `CI` 워크플로를 실행합니다
5. 성공한 `preflight_run_id`를 저장합니다
6. 동일한 `tag`, 동일한 `npm_dist_tag`, 저장된 `preflight_run_id`
`OpenClaw Release Publish`를 실행합니다. 이 워크플로는 OpenClaw npm 패키지를 승격하기 전에 외부화된 Plugin을 npm과 ClawHub에 게시합니다.
7. 릴리스가 `beta`에 올라갔다면 비공개
`OpenClaw Release Publish`를 실행합니다. 이 워크플로는 OpenClaw npm 패키지를 승격하기 전에
외부화된 Plugin을 npm과 ClawHub에 게시합니다
7. 릴리스가 `beta`에 배포된 경우, 비공개
`openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`
워크플로를 사용 해당 안정 버전을 `beta`에서 `latest`로 승격합니다.
8. 릴리스가 의도적으로 `latest`에 직접 게시되었고 `beta`도 즉시 동일한 안정 빌드를 따라야 한다면,
동일한 비공개 워크플로를 사용해 두 dist-tag가 모두 안정 버전을 가리키도록 하거나, 예약된
자체 복구 동기화가 나중에 `beta`를 이동하도록 둡니다.
워크플로를 사용하여 해당 안정 버전을 `beta`에서 `latest`로 승격합니다
8. 릴리스가 의도적으로 `latest`에 직접 게시되었고 `beta`도 즉시 동일한 안정 빌드를 따라야 하는 경우,
동일한 비공개 워크플로를 사용해 두 dist-tag가 모두 안정 버전을 가리키도록 하거나,
예약된 자가 복구 동기화가 나중에 `beta`를 이동하게 둡니다
dist-tag 변경은 여전히 `NPM_TOKEN`이 필요하기 때문에 보안을 위해 비공개 저장소에 있으며,
dist-tag 변경은 여전히 `NPM_TOKEN`이 필요하므로 보안을 위해 비공개 저장소에 있습니다.
공개 저장소는 OIDC 전용 게시를 유지합니다.
이렇게 하면 직접 게시 경로와 beta-first 승격 경로가 모두 문서화되고 운영자가 볼 수 있습니다.
이렇게 하면 직접 게시 경로와 beta 우선 승격 경로가 모두 문서화되고 운영자에게 표시됩니다.
관리자가 로컬 npm 인증으로 대체해야 하는 경우, 모든 1Password
CLI(`op`) 명령은 전용 tmux 세션 안에서만 실행하세요. 메인 에이전트 셸에서 `op`
직접 호출하지 마세요. tmux 안에 두면 프롬프트,
알림, OTP 처리를 관찰할 수 있고 반복되는 호스트 알림을 방지할 수 있습니다.
유지관리자가 로컬 npm 인증으로 대체해야 하는 경우, 모든 1Password
CLI(`op`) 명령은 전용 tmux 세션 안에서만 실행하세요. 기본 에이전트 셸에서 `op`
직접 호출하지 마세요. tmux 안에 두면 프롬프트, 경고 및 OTP 처리를 관찰할 수 있고
반복적인 호스트 경고를 방지할 수 있습니다.
## 공개 참조
@ -446,8 +558,9 @@ CLI(`op`) 명령은 전용 tmux 세션 안에서만 실행하세요. 메인 에
- [`scripts/package-mac-dist.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/package-mac-dist.sh)
- [`scripts/make_appcast.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/make_appcast.sh)
관리자는 실제 실행 지침에
[`openclaw/maintainers/release/README.md`](https://github.com/openclaw/maintainers/blob/main/release/README.md)의 비공개 릴리스 문서를 사용합니다.
유지관리자는 실제 런북에
[`openclaw/maintainers/release/README.md`](https://github.com/openclaw/maintainers/blob/main/release/README.md)의
비공개 릴리스 문서를 사용합니다.
## 관련