b3os · diff
git:20260801.9cc5479 to git:20260801.b29b4b5
94 added, 464 removed. Audit B to B.
---
name: b3os
- description: b3rys TEAM OS(b3os) — 여러 AI를 한 팀으로 운영하는 멀티런타임 AI 팀 OS — 를 공개 저장소에서 clone·설치하고, 팀 기본정보를 채팅으로 세팅한 뒤 첫 팀원 1명을 영입(텔레그램 연결)해서 그 팀원에게 넘겨주는(handoff) 온보딩 스킬. Claude가 clone → install.sh → 대시보드 기동 → (채팅으로) 팀명·팀장ID·팀장이름 세팅 → 첫 팀원 런타임 추천·영입·인증·활성화 → 라우터 ON 까지 대신 몰아주고, 사람만 할 수 있는 것(BotFather 토큰·활성화 승인·페어링)만 직접 요청한다. 첫 팀원이 응답하면 설치는 끝 — 이후 추가 영입·운영은 그 팀원이 이어받는다. 사용 시점 — 설치·세팅: "b3os 설치해줘", "b3os 세팅", "AI 팀 세팅해줘", "AI 팀 만들어줘", "b3rys 팀 만들어줘", "b3rys-team-os setup/install", "이 repo 설치하고 팀 세팅해줘(github.com/b3rys/b3rys-team-os)", "b3os 언인스톨/삭제"; 팀방·그룹 협업 세팅: "b3os 팀방 세팅 어떻게 해", "b3os 그룹방 세팅/연동", "팀 라우터(System OP) 붙여줘", "그룹방에서 팀 협업되게 해줘"; 운영·문제해결(트러블슈팅): "b3os 안 떠요/안 돼요", "team-os 상태/복구/재시작", "b3os 봇이 응답 안 해요", "b3os 리부팅 후 안 올라와요", "b3os 문제/에러/트러블슈팅", "b3os 업데이트/버전 올려줘"; 기본 시스템 잡·서비스 안내: "b3os 시스템 잡 목록", "b3os가 뭘 자동으로 돌려?", "b3os 백그라운드 서비스 뭐 있어", "b3os 기본 운영 서비스" 등을 언급할 때. macOS 권장(팀원 활성화가 launchd 기반). 운영·복구 상세는 references/b3os-ops-primer.md 참조.
+ description: b3rys TEAM OS(b3os) — 여러 AI를 한 팀으로 운영하는 멀티런타임 AI 팀 OS — 를 공개 저장소에서 clone·설치하고, 팀 기본정보를 채팅으로 세팅한 뒤 첫 팀원 1명을 영입(텔레그램 연결)해서 그 팀원에게 넘겨주는(handoff) 온보딩 스킬. clone → install.sh → 대시보드 기동 → 팀명·팀장ID·팀장이름 세팅 → 첫 팀원 런타임 추천·영입·인증·활성화까지 Claude가 몰아주고, 사람만 할 수 있는 것(BotFather 토큰·활성화 승인·페어링)만 요청한다. 첫 팀원이 응답하면 설치는 끝 — 이후 추가 영입·운영은 그 팀원이 이어받는다. 사용 시점 — 설치·세팅: "b3os 설치해줘", "b3os 세팅", "AI 팀 세팅해줘", "AI 팀 만들어줘", "b3rys 팀 만들어줘", "b3rys-team-os setup/install", "b3os 언인스톨/삭제"; 팀방·그룹 협업: "b3os 팀방 세팅 어떻게 해", "b3os 그룹방 세팅/연동", "팀 라우터(System OP) 붙여줘"; 운영·문제해결: "b3os 안 떠요", "team-os 상태/복구/재시작", "b3os 봇이 응답 안 해요", "b3os 리부팅 후 안 올라와요", "b3os 업데이트/버전 올려줘"; 런타임 교체: "팀원 런타임 바꿔줘"; 시스템 잡: "b3os가 뭘 자동으로 돌려?" 등을 언급할 때. macOS 권장(팀원 활성화가 launchd 기반). 각 단계 상세는 references/ 의 해당 파일을 그때 펼쳐 읽는다.
trigger: first-time b3os install · recruiting a member · team setup
---
# b3os — b3rys TEAM OS 온보딩 스킬
- **여러 AI를 한 명씩 따로 쓰지 말고, 한 팀으로.** 이 스킬은 공개 저장소
+ **여러 AI를 한 명씩 따로 쓰지 말고, 한 팀으로.** 공개 저장소
[`github.com/b3rys/b3rys-team-os`](https://github.com/b3rys/b3rys-team-os)를 clone → 설치 → 대시보드 기동 →
- 팀 기본정보 세팅 → **첫 팀원 1명 영입(텔레그램 연결)** 까지 몰아주고, 그 팀원에게 넘긴다.
+ 팀 기본정보 세팅 → **첫 팀원 1명 영입** 까지 몰아주고, 그 팀원에게 넘긴다.
> **이 스킬의 목표 = 사용자를 "첫 팀원"까지 데려다주고 손을 뗀다(handoff).**
- > 모든 운영을 이 스킬이 계속 떠안지 않는다. 첫 팀원이 응답하면 **추가 영입·운영은 그 팀원이 이어받는다.**
- > 이 스킬은 **self-contained** — 저장소를 직접 clone 하므로 로컬에 미리 받아둘 필요가 없다.
-
- ## 핵심 디자인
+ > 첫 팀원이 응답하면 **추가 영입·운영은 그 팀원이 이어받는다.**
- - **Conversational** — 사용자가 "b3os 설치해줘" 하면 Claude가 아래 단계를 셸/API로 직접 실행. 팀 기본정보도
- **화면에 가서 입력하라고 미루지 않고 채팅으로 물어본다.** 사용자는 **사람만 할 수 있는 것**(BotFather 토큰,
- 활성화 y/n 승인, 페어링)만 답한다.
- - **런타임 선택 모드** — `claude_channel`을 기본 선택·추천한다. `hermes_agent`와 `openclaw`는 동등한 ChatGPT BYO 선택지로 항상 보여주되, 설치+인증 readiness가 안 되면 disabled 상태와 `references/runtime-setup.md` CTA를 보여준다. 이 세 가지 외 내부 런타임은 온보딩에 노출하지 않는다.
- - **인증은 런타임을 고른 그 순간에만 점검** — 구독 여부를 미리 캐묻지 않는다. 고른 런타임의 CLI·로그인만 그때 확인.
- - **사람 게이트 존중** — 봇 토큰·활성화 승인·페어링 코드는 사람 몫. Claude가 대신 만들거나 우회하지 않는다.
+ **핵심 디자인** — ①**대화로 진행**: 팀 기본정보도 화면에 미루지 않고 채팅으로 묻는다 ②**사람 게이트 존중**: 봇 토큰·활성화 승인·페어링은 사람 몫, 대신 만들거나 우회하지 않는다 ③**인증은 런타임을 고른 그 순간에만** 점검하고 구독을 미리 캐묻지 않는다 ④**인증은 구독(OAuth)이 기본** — API 키는 사용자가 명시적으로 원할 때만.
## ⚠️ 시작 전 안전 고지 (사용자에게 먼저 보여줄 것)
> b3os는 **본인 전용 장비(personal machine)에만** 설치하세요. 대시보드·API는 `127.0.0.1` 로컬 단독 사용을
> 전제로 하며 **앱 레벨 인증이 없습니다.** 공용/공개 서버에 그대로 노출하지 마세요. 외부 접근이 필요하면
> Cloudflare Access 같은 **엣지 인증을 반드시 앞단에** 두세요.
macOS 권장(팀원 활성화가 launchd 기반이라 현재 macOS 전용, Linux는 대시보드까지만).
- ## 전체 흐름 (Claude가 위에서 아래로 실행)
+ ## 전체 흐름 (위에서 아래로 실행)
```
[0] 안전 고지 + 설치 위치 확인
- ↓
- [1] Prerequisites 확인·설치 (brew·git·bun — 공통만. 런타임별 인증은 [5]에서 그때)
- ↓
- [2] clone → bash install.sh (bun·의존성·빌드·.env + 활성화 승인 y/n) ← 사람: y/n 답
- ↓
- [3] bun run start → http://localhost:7878/team ▸ Settings 페이지가 열림 (bun PATH 주의)
- ↓
- [4] 팀 기본정보 세팅 = 채팅으로 물어봄 (팀명·팀장ID·팀장이름 필수 · 미션은 안 물어봄=기본값)
- └ PUT /team/api/settings {team_name, lead_id, owner_name} (미션은 안 물어봄=TEAM-OS 기본값)
- ※ 이거 안 하면 영입이 setup_incomplete(400)으로 막힘 — 하드 선행조건
- ↓
- [5] 첫 팀원 영입 = claude_channel 추천 + BYO 런타임 선택 → 고른 런타임만 인증 preflight
- ├─ 런타임 선택 → 그 런타임 CLI·로그인 점검 (present→진행 / missing→설치·로그인 안내)
- ├─ BotFather로 봇 생성 → 토큰 ← 사람: 토큰(Claude Code 입력 OK)
- ├─ recruit → provision(토큰) → activate → (페어링 승인) ← 사람: 봇에 DM/승인
- └─ telegram 플러그인 user-scope 1회 설치 (claude 런타임)
- ↓
- [6] 첫 팀원 1:1 DM 확인: 봇에 메시지 → 응답(또는 6자리 코드) 오면 합류 완료 ← 1:1 DM은 라우터 무관
- ↓
- [6.5] (권장) System OP 세팅 물어봄 — ★팀 운영 알림을 텔레그램으로 받으려면 필요★:
- digest·승인(approve)·상태(/status)·칸반(/board) 같은 팀op 메뉴/알림과 그룹방 라우팅은 op 봇이 처리한다.
- └ BotFather로 op 봇 생성 → 대시보드 Settings ▸ 시스템 OP 에 capture 토큰 + (그룹 쓸 거면 그룹 chat_id) + 라우터 ON.
- └ "지금 팀 운영 알림·승인 받게 op 붙일까요?" 물어보되 강요 안 함 — 건너뛰면 나중에 "b3os 팀방 세팅"으로 언제든. (1:1 멤버 리포트는 op 없이도 옴.)
- ↓
- [7] ★HANDOFF — "이제 팀원 [이름]과 대화하세요." 추가 영입·운영은 팀원이 이어받음
- ↓
- [8] (선택) 팀원 더 추가 = [5] 루프 반복 (각 런타임은 자기 구독 재사용)
- ```
-
- > ⭐ **첫 영입 팀원은 자동으로 팀 coordinator 역할 + full context 능력을 부여받는다** — coordinator = 담당 미배정·모호 메시지의 기본 담당(라우팅 fallback·PM 조율), full context = 팀방 최근 메시지 조회(최대 10건 / 6시간 이내). 그래서 [7] handoff 대상인 첫 팀원이 팀 기본 리드로서 운영을 이어받는다. (이후 팀원엔 기본 미부여, 첫 리드 퇴사 시 다음 팀원에게 자동 승계.)
-
- 각 상세는 아래. 영입(5)의 세부 API/UI/페어링은 `references/recruit.md`, 첫 팀원이 이어받을 운영 지식은
- `references/b3os-ops-primer.md`, 막히면 `references/troubleshooting.md`, **b3os 가 백그라운드에서 돌리는 기본 시스템 잡·서비스 목록은 `references/system-jobs.md`**("무엇이 자동으로 도는지" 물으면 이걸로 안내).
-
- ## 스케줄/리마인더 운영 메모
-
- 턴기반 팀원(openclaw·hermes 등 wake 로만 움직이는 런타임)이 "5분 뒤 알려줘" 같은 지연 작업을 받으면 현재 턴에서 기다리면 안 된다. 정규 동작은
- b3os 스케줄러 API로 예약 row를 만들고 즉시 답하는 것이다 (릴리즈에 실린 서버 엔드포인트 — 별도 스크립트 불필요):
-
- ```bash
- curl -s -X POST http://localhost:$PORT/team/api/schedules/reminder \
- -H 'content-type: application/json' \
- -H "x-actor-id: <your_agent_id>" \
- -d '{"target_agent_id":"<your_agent_id>","body":"[예약 알림] ...","delay_seconds":300}'
- ```
-
- 스케줄러가 수락 가능 상태가 아니면 이 명령/API는 실패해야 한다. 그 경우 "예약했습니다"라고 말하지 말고,
- 현재 one-shot 예약 기능이 아직 활성화되지 않았다고 짧게 보고한다.
-
- > `direct_to_gd`(내부 라우팅 플래그명): 예약 payload 에 true면 리마인더 결과를 **팀 리드(팀장)의 대화창으로 직접 보고**한다는 뜻. 필드명은 내부 규약이라 그대로 두되, 동작은 "리드에게 직접"으로 이해하면 된다.
-
- 예약 owner는 body가 아니라 인증 actor(`x-actor-id` 헤더, 환경에 `OP_MESSAGE_TOKEN` 있으면 `x-op-token`도)로 결정된다.
- 일반 팀원은 자기 agent id만 target 으로 예약·조회·취소할 수 있고(다른 agent 대상은 lead 경로만), `created_by` 위조는 거부된다.
- `run_at`(ISO 시각) 또는 `delay_seconds` 중 ★정확히 하나★. `direct_to_gd:true` 면 결과를 팀 리드에게 직접 보고(비리드 actor엔 quota 적용).
- 취소 = `POST /team/api/schedules/<id>/cancel`. 스케줄러가 수락 불가 상태면 이 API는 실패한다 — 그땐 "예약했다"고 말하지 말고 짧게 보고.
-
- ---
-
- ## 🔌 서버가 안 떠 있을 때 (복구) + 상시가동 — **전부 선택**
-
- > **먼저 알아둘 것: 아무것도 안 해도 된다.** b3os 는 `bun run start` 로 띄워 쓰는 게 기본이고,
- > 아래 등록을 **하지 않아도 모든 기능이 정상 동작한다.** 설치·영입 단계에서 이걸 묻지도, 강요하지도 않는다.
- > macOS 전용이다(Windows 미지원).
-
- ### 서버가 안 떠 있다 (대시보드가 안 열린다 / 맥앱이 "b3os 스킬로 복구하세요"라고 안내한다)
-
- 맥앱은 서버가 죽으면 대시보드를 띄울 수 없다(서버가 화면을 내려주기 때문). 그래서 앱은 여기로 안내한다.
-
- ```bash
- cd "$B3OS"
- bun run service status # 상시가동으로 등록돼 있는지 확인
- ```
-
- - **등록 안 됨(기본)** → 그냥 다시 띄우면 된다: `bun run start`
- - **등록됨** → `bun run service restart`
-
- ### (선택) 재부팅해도 계속 돌게 하기
-
- 사용자가 **원할 때만** 안내한다. 먼저 권하지 않는다.
-
- ```bash
- cd "$B3OS"
- bun run service install # 등록 + 즉시 기동
- bun run service status # 확인
- bun run service uninstall # 되돌리기(등록 해제)
- ```
-
- 등록하면 얻는 것: **재부팅 자동복구** · **터미널/앱을 닫아도 서버 생존** · 맥앱의 **[서버 재시작] 버튼 활성화**.
-
- > **알아둘 점** — macOS 는 사용자 서비스(LaunchAgent)를 **부팅이 아니라 로그인 시점**에 올린다.
- > 그래서 등록해 두더라도 **재부팅 후 로그인을 한 번 해야** 뜬다(자동 로그인을 켜두면 그마저 불필요).
- >
- > 라벨은 `com.$USER.team-collab` 이다(`TEAMOS_LAUNCHD_PREFIX` 로 변경 가능). 멤버 봇 라벨과 같은 규칙이라,
- > 서버·멤버가 한 벌로 관리된다.
-
- ---
-
- ## 🛑 긴급 ALL-STOP (에이전트 폭주·이상 시)
-
- 에이전트가 폭주하거나(대량 메시지·외부 API 무한호출·통제 불능) 이상이면, **전부 즉시 중지**하고 복구한다. 긴급 시 **Claude Code + 대시보드/API 가 최후의 통제 지점** — 봇·런타임이 다 죽어도 서버가 살아 있으면 되살릴 수 있다.
-
- **① 유입 차단 (가장 빠름 · 재시작 불필요)** — 라우터를 끄면 팀원이 새 메시지를 **받지 못한다**:
- ```bash
- curl -s -X PATCH http://localhost:7878/team/api/system-op \
- -H 'content-type: application/json' -d '{"router_enabled":false}'
- ```
- UI: Settings ▸ 시스템 OP 라우터 토글.
-
- **② 전원 정지**:
- ```bash
- curl -s -X POST http://localhost:7878/team/api/members/stop-all
+ [1] Prerequisites (brew·git — 공통만. 런타임별 인증은 [5]에서)
+ [2] clone → bash install.sh ← 사람: 활성화 y/n
+ [3] bun run start → http://localhost:7878/team
+ [4] 팀 기본정보 = 채팅으로 물어봄 (팀명·팀장ID·팀장이름) ※ 안 하면 영입이 400
+ [5] 첫 팀원 영입 (런타임 선택 → preflight → recruit) ← 사람: 봇 토큰·페어링
+ [6] 1:1 DM 확인 — 응답 오면 합류 완료
+ [7] ★HANDOFF — "이제 팀원과 대화하세요" ← 여기서 이 스킬의 일은 끝
+ [8] (선택) 팀원 더 추가 · 팀방(그룹) 협업 · 런타임 교체
```
- UI: 대시보드 빨강 **All-Stop** 버튼(더블 컨펌).
- → 각 팀원의 세션/poller 를 내린다. **복구 코디 역할(coordinator) 팀원은 자동 제외**된다 — 복구 창구를 남기기 위해서다(정말 끄려면 그 팀원만 개별 정지).
- → b3os 서버(대시보드·API)는 유지된다 = 복구 surface.
- **③ 개별 정지**: 대시보드 팀원 Settings ▸ 정지(서킷브레이커), 또는
- `POST /team/api/members/<id>/enabled` 본문 `{"enabled":false}`.
-
- > 위 정지·재시작 API 는 **실행 인가**(`APPROVAL_EXECUTION_ENABLED=1`)가 켜져 있어야 동작한다. 꺼져 있으면 "팀장 인가 필요" 를 돌려준다.
-
- **복구**:
- - 라우터 다시 ON: 위 PATCH 를 `{"router_enabled":true}` 로.
- - 팀원 기동: 대시보드에서 개별 기동, 또는 `POST /team/api/members/restart-all`.
- - 폭주 원인이 특정 팀원이면 **그 팀원만 정지 유지** + 나머지 기동.
- - 상태 확인은 `references/b3os-ops-primer.md` §9(상태 확인)·인수테스트를 쓴다.
-
- ## [0] 설치 위치 안내 + 확인
+ > ⭐ **첫 영입 팀원은 자동으로 팀 coordinator + full context 를 받는다** — 담당 미배정·모호 메시지의 기본 담당(라우팅 fallback·PM 조율)이자 팀방 최근 맥락 수신자다. 그래서 [7] handoff 대상이 된다. (이후 팀원엔 기본 미부여, 첫 리드 퇴사 시 자동 승계.)
- **클론 전에 설치 위치를 먼저 사용자에게 알린다** (기본 = 홈 폴더 `$HOME/b3rys-team-os`). 다음을 그대로 보여준다:
+ ## [0] 설치 위치
- > 📁 **~/(home)에 `b3rys-team-os` 를 설치합니다. 다른 위치를 원하면 알려주세요.**
+ 기본은 홈 폴더다. **클론 전에 먼저 알린다** — "📁 `~/b3rys-team-os` 에 설치합니다. 다른 위치를 원하면 알려주세요."
```bash
- [[ "$(uname)" == "Darwin" ]] || echo "⚠ macOS 아님 — 대시보드까지만 됩니다(팀원 활성화는 launchd/macOS 전용)."
- export B3OS="$HOME/b3rys-team-os" # 기본 설치 위치(홈). 사용자가 다른 위치를 원하면 이 값만 바꾼다.
- echo "설치 위치: $B3OS"
+ [[ "$(uname)" == "Darwin" ]] || echo "⚠ macOS 아님 — 대시보드까지만 됩니다."
+ export B3OS="$HOME/b3rys-team-os"
```
- 사용자 전용 맥인지 한 번 확인한다(위 안전 고지). 이후 이 폴더를 `$B3OS` 로 부른다.
-
- ## [1] Prerequisites — 공통만 (런타임별 인증은 [5]에서)
-
- 여기선 **어떤 런타임을 고르든 공통으로 필요한 것**만 확인·설치한다. 런타임별 CLI·로그인은 **[5]에서 런타임을
- 고른 그 순간에** 점검한다(구독을 미리 캐묻지 않기 위해).
+ ## [1] Prerequisites — 공통만
```bash
- # bun 과 (macOS)tmux·Homebrew 는 install.sh 가 자동 준비. git 은 repo clone 에 이미 필요.
- # 이 스킬 경로(직접 clone·활성화)에서는 아래처럼 brew·git 도 없으면 여기서 챙긴다.
command -v brew >/dev/null || /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
command -v git >/dev/null || brew install git
- # bun 수동 설치가 필요하면: curl -fsSL https://bun.sh/install | bash
+ # bun·tmux 는 install.sh 가 자동 준비. 수동이 필요하면: curl -fsSL https://bun.sh/install | bash
```
- 빠진 게 있으면 위 명령으로 설치하고, 설치가 안 되면 무엇이 막혔는지 사용자에게 정확히 알린다.
-
## [2] Clone + 설치
```bash
- : "${B3OS:=$HOME/b3rys-team-os}" # [0]에서 안내한 기본 위치(홈). 다른 위치면 [0]에서 이미 바뀜.
- # 멱등: 사용자가 이미 직접 clone 하고 스킬을 부른 경우 첫 명령에서 막히지 않게 가드.
- if [ -d "$B3OS/.git" ]; then echo "이미 clone됨 — 재사용: $B3OS"; else git clone https://github.com/b3rys/b3rys-team-os.git "$B3OS"; fi
- cd "$B3OS"
- bash install.sh
+ : "${B3OS:=$HOME/b3rys-team-os}"
+ if [ -d "$B3OS/.git" ]; then echo "이미 clone됨 — 재사용"; else git clone https://github.com/b3rys/b3rys-team-os.git "$B3OS"; fi
+ cd "$B3OS" && bash install.sh
```
- `install.sh`가 하는 일: ① bun 확인/설치 ② `bun install` ③ `bun run build`(대시보드) ④ `.env` 준비
- (`.env.example` 복사) ⑤ **활성화 스위치 프롬프트** ⑥ typecheck.
+ `install.sh` = bun 확인/설치 → `bun install` → `bun run build` → `.env` 준비 → **활성화 스위치 프롬프트** → typecheck.
- > **★ 사람 승인 (활성화 스위치)** — `install.sh`가
- > *"이 장비에서 팀원(봇) 활성화를 허용할까요? 본인 전용 맥이면 y. [y/N]"* 를 묻는다.
- > 이건 `.env` 에 `APPROVAL_EXECUTION_ENABLED=1` 을 켜서 **서버가 봇 런타임을 실제로 기동**하도록 인가하는
- > 스위치다. **본인 전용 맥일 때만 `y`.** Claude는 이 값을 사용자 대신 임의로 넣지 말고 사용자에게 y/n을
- > 물어라. (헤드리스로 프롬프트에 답할 수 없으면, 사용자에게 `y` 입력을 요청하거나 설치 후
- > `.env` 에 `APPROVAL_EXECUTION_ENABLED=1` 을 추가하고 서버 재시작하도록 안내.)
+ > **★ 사람 승인 (활성화 스위치)** — *"이 장비에서 팀원(봇) 활성화를 허용할까요? [y/N]"* 은 `.env` 의
+ > `APPROVAL_EXECUTION_ENABLED=1` 을 켜서 **서버가 봇을 실제로 기동**하도록 인가하는 스위치다.
+ > **본인 전용 맥일 때만 `y`.** 이 값을 사용자 대신 임의로 넣지 말고 사용자에게 묻는다.
## [3] 대시보드 기동 + 확인
```bash
cd "$B3OS"
- bun run start >/tmp/b3os-server.log 2>&1 & # 서버 기동 (DB 자동 생성). ★백그라운드로★ — 포그라운드로 띄우면 이후 단계가 막힌다. 로그는 /tmp/b3os-server.log.
- ```
-
- > **★ bun PATH 주의** — `install.sh`가 방금 bun을 새로 깔았다면 현재 셸 PATH에 아직 없다.
- > `command not found: bun` 이면 새 터미널을 열거나 `source ~/.zshrc`(bash면 `~/.bashrc`) 후 재실행,
- > 또는 `export PATH="$HOME/.bun/bin:$PATH"` 로 즉시 해결.
-
- > **★ 포트 주의 (기본 7878, 이 문서 URL 은 전부 예시)** — 서버가 `포트 7878 이미 사용 중` 이라고 종료하면,
- > `.env` 의 `TEAM_HTTP_PORT` 를 다른 값(예: 7900)으로 바꾸고 다시 `bun run start` 한다. ★그 뒤로는 아래 모든
- > `localhost:7878` URL 의 포트를 그 값으로 바꿔서 안내·호출한다★ (실포트 = `grep '^TEAM_HTTP_PORT=' "$B3OS/.env" | cut -d= -f2`, 없으면 7878).
-
- 기동 확인(응답 오면 OK):
- ```bash
+ bun run start >/tmp/b3os-server.log 2>&1 & # ★백그라운드로★ — 포그라운드면 이후 단계가 막힌다
PORT=$(grep '^TEAM_HTTP_PORT=' "$B3OS/.env" 2>/dev/null | cut -d= -f2); PORT=${PORT:-7878}
- # 콜드 부팅 여유로 ~12s 재시도
- for i in $(seq 1 6); do
- curl -sf "http://localhost:$PORT/health" >/dev/null 2>&1 && { echo " ✅ 서버 up (포트 $PORT)"; ok=1; break; }
- sleep 2
- done
- [ -z "${ok:-}" ] && echo " ⚠ 서버가 안 뜸 — 로그 확인: tail -30 /tmp/b3os-server.log (포트 충돌이면 .env 의 TEAM_HTTP_PORT 를 다른 값으로 바꾸고 재시작)"
+ for i in $(seq 1 6); do curl -sf "http://localhost:$PORT/health" >/dev/null 2>&1 && { echo "✅ 서버 up ($PORT)"; break; }; sleep 2; done
```
- 사용자에게 브라우저로 **http://localhost:$PORT/team** (실포트, 기본 7878)을 열라고 안내한다. 이 페이지가 뜨면 **Settings(설정)
- 탭**을 열어 두게 한다 — 다음 단계(팀 기본정보)를 화면에서 눈으로 확인하며 진행할 수 있다.
-
- > 이대로 쓰면 된다. (재부팅해도 계속 돌게 하는 **선택** 옵션은 위 「🔌 서버가 안 떠 있을 때 + 상시가동」 참고 —
- > **안 해도 되고, 여기서 묻지 않는다.**)
+ 사용자에게 **http://localhost:$PORT/team** 을 열고 **Settings 탭**을 띄워두게 한다.
- ## [4] 팀 기본정보 세팅 — **채팅으로 물어본다** (화면에 미루지 않음)
+ > **★ bun PATH** — `command not found: bun` 이면 `export PATH="$HOME/.bun/bin:$PATH"` 또는 새 터미널.
+ > **★ 포트** — `7878 이미 사용 중` 이면 `.env` 의 `TEAM_HTTP_PORT` 를 바꾸고, **이후 모든 URL 의 포트를 그 값으로** 안내한다.
+ > 안 뜨면 `tail -30 /tmp/b3os-server.log`.
- **영입을 열려면 팀명·팀장ID·팀장이름(owner_name) 세 가지가 먼저 있어야 한다** — 하나라도 없으면 recruit가 `setup_incomplete`(400, missing 맵에 빠진 필드 표시)으로 막힌다(하드 선행조건).
- "대시보드 가서 입력하세요"라고 넘기지 말고, **Claude가 채팅에서 직접 물어본다:**
+ ## [4] 팀 기본정보 — 채팅으로 물어본다
- > ★예시는 제네릭 자리표시자다 — 사용자에게 실제 값을 **물어보기만** 하고, 예시로는 아래 제네릭(`acme`/`teamleader`/`Alex`)을 **그대로** 보여준다. ★사용자의 실명·팀명·chat_id 등 개인정보를 예시로 쓰지 말고, 이메일·계정·대화 컨텍스트에서 실명을 **유추해서 넣지도 마라.**★ 실제 값은 사용자가 직접 준 것만 쓴다.
+ **팀명·팀장ID·팀장이름 세 가지가 먼저 있어야 영입이 열린다**(없으면 recruit 가 `setup_incomplete` 400 — 하드 선행조건). "대시보드 가서 입력하세요"로 넘기지 말고 채팅에서 직접 묻는다.
- 1. **팀명** (필수, ≤20자) — 예: "acme"
- 2. **팀장 ID** (필수, `lead_id`) — 영문 slug(소문자/숫자/`-`/`_`, 1~40자). 멘션·라우팅에서 팀장을 가리키는 식별자. 예: `teamleader`
- 3. **팀장 이름** (필수, `owner_name`, ≤40자, 사람 이름) — 페르소나·룰의 `{{OWNER}}` 자리표시자를 채운다. 반드시 물어본다(사용자가 준 이름을 넣되, 예시로는 실명 대신 `Alex` 같은 제네릭을 보여준다). 예: `Alex`
- 4. (선택) **팀장 텔레그램 chat_id**(`owner_chat_id`, 숫자) — 그룹 캡처·라우팅용, 그리고 ★hermes DM 페어링 게이트 통과용 allowlist 시드값★. ★인바운드 DM 게이트는 런타임별로 다르다★(openclaw=pair-approve 페어링, hermes=DM 페어링 게이트 있음→activate가 owner_chat_id를 allowlist에 시드해 팀장은 통과 — 아래 🔐 참조). ★첫 claude 팀원 페어링 시 자동으로 채워진다.★
- - **claude_channel 은 이 값이 필요 없다** — claude 는 봇 DM 접근을 access.json 페어링(6자리 코드 승인)으로 관리한다(owner_chat_id 로 안 채워짐). claude 만 쓸 거면 생략.
- - **외부/BYO 런타임을 첫 팀원으로 영입할 땐** 이 값을 받아 넣는다. 팀장이 모르면 "텔레그램 @userinfobot 에게 DM하면 알려준다"고 안내.
+ 1. **팀명** (≤20자) 2. **팀장 ID** (`lead_id`, 영문 slug 1~40자) 3. **팀장 이름** (`owner_name`, ≤40자) 4. (선택) **팀장 텔레그램 chat_id** (`owner_chat_id`, 숫자 — BYO 런타임을 첫 팀원으로 쓸 때만. claude 는 불필요)
- 받은 값으로 **`/settings` API 한 번 호출한다** (미션은 물어보지 않는다 — TEAM-OS.md §1 의 기본 미션을 그대로 쓴다):
+ > ★예시는 제네릭 자리표시자(`acme`/`teamleader`/`Alex`)를 **그대로** 보여준다. 사용자의 실명·팀명을 예시로 쓰거나 이메일·대화 맥락에서 **유추해 넣지 마라.** 실제 값은 사용자가 직접 준 것만 쓴다. **미션은 묻지 않는다**(TEAM-OS 기본값).
```bash
- # 팀명 + 팀장ID + 팀장이름 (owner_chat_id는 선택)
- curl -s -X PUT http://localhost:$PORT/team/api/settings \
- -H 'content-type: application/json' \
+ curl -s -X PUT http://localhost:$PORT/team/api/settings -H 'content-type: application/json' \
-d '{"team_name":"acme","lead_id":"teamleader","owner_name":"Alex"}'
- # 응답에 "setup_complete": true 면 영입 가능 — 팀명·팀장ID·팀장이름 셋 다 채워져야 true. (team_name>20자·lead_id 형식오류면 400)
- # 외부/BYO 런타임을 첫 팀원으로 영입할 거면 owner_chat_id도 같이. claude 는 access.json 페어링으로 접근을 관리하므로 owner_chat_id 불필요(생략):
- # -d '{"team_name":"acme","lead_id":"teamleader","owner_name":"Alex","owner_chat_id":"123456789"}' # 숫자만, 빈값 허용
+ # 응답 "setup_complete": true 면 영입 가능
```
- > **왜 채팅으로?** 팀명·팀장ID·팀장이름은 사용자가 이미 머릿속에 답을 아는 짧은 질문이다. 화면 이동 없이
- > 대화에서 받아 API로 넣으면 마찰이 적다. 사용자가 "직접 화면에서 넣을게" 하면 Settings 탭에서 넣도록 코치만 한다.
- > ★미션은 물어보지 않는다★ — TEAM-OS.md §1 의 기본 미션을 그대로 쓴다(대시보드에도 미션 편집칸 없음).
-
- ## [5] 첫 팀원 영입 — 런타임 추천 + 나열 + 런타임별 인증 preflight
-
- > ★★이 단계에 들어오면 **먼저 `references/recruit.md` 를 펼쳐 읽고** 진행한다★★ — SKILL 요약(§5-3)만 보고 즉흥으로 "이름·역할" 몇 개만 묻지 말 것. 물어볼 필드(id 포함)·질문 문구·배치 폼·기본값 처리가 recruit.md 에 다 있다.
-
- > **첫 팀원은 자동으로 "팀 리드"가 됩니다 — 사용자에게 한 줄로 알려준다.**
- >
- > "첫 팀원은 **팀 리드**가 되어, 팀원들의 메시지 맥락을 함께 봅니다. (담당자가 정해지지 않은 일도 이 팀원이 맡습니다)"
- >
- > 내부적으로는 첫 영입 멤버에게 `coordinator`(기본 담당자) + `full_context`(팀방 대화 맥락 수신)가 자동 부여된다.
- > 이후 영입되는 팀원은 자기에게 온 메시지만 본다. 팀 리드가 팀을 나가면 남은 팀원 중 한 명이 같은 역할을 승계한다.
-
- ### 5-1. 런타임 추천 + 나열
-
- **세 가지 공개 선택지를 먼저 보여준다. 기본 선택은 Claude이고, ChatGPT 사용자는 Hermes/OpenClaw BYO를 고를 수 있다:**
-
- - **Claude 구독자 → `claude_channel`** — 기존 Claude 로그인을 그대로 재사용(추가 구독·키 없이 바로). Claude Code에서 이 스킬을 실행 중이면 특히 매끄럽다.
- - **ChatGPT 구독자 → `hermes_agent` 또는 `openclaw`** — ChatGPT 구독을 **OAuth**로 재사용(API 키 아님). 둘 다 BYO 고급 런타임이라 CLI·인증을 먼저 갖춘다(`references/runtime-setup.md`; hermes 는 `hermes auth add openai-codex --type oauth`). ★hermes·openclaw 는 ChatGPT 구독자용이 기본 — claude 로 붙이는 용도가 아니다.★
- - **모르거나 첫 팀원이면 → `claude_channel`** 이 가장 짧은 경로(AI가 설치·인증까지 몰아줄 수 있음).
-
- > ★인증은 항상 **구독(OAuth) 기본, API 키 아님**. 자동발견된 `*_API_KEY` 는 사용자가 명시적으로 원할 때만.★
-
- 그리고 공개 표면의 목록을 보여준다:
-
- | # | runtime | 한 줄 설명 | 난이도 | 설치 주체 |
- |---|---|---|---|---|
- | 1 | `claude_channel` | 로컬 Claude Code 세션 연결(tmux 봇). 기존 Claude 로그인 재사용 | 쉬움 | **AI 자동** (사람은 CLI 로그인만) |
- | 2 | `openclaw` | OpenClaw gateway/session | 고급 | **BYO** — CLI+게이트웨이+인증 에이전트 **미리 준비** |
- | 3 | `hermes_agent` | Hermes 프로필 게이트웨이 | 고급 | **BYO** — CLI+인증 프로필 **미리 준비** |
-
- > **첫 팀원은 `claude_channel` 권장.** AI가 설치·인증 안내까지 가장 안정적으로 몰아줄 수 있는 공개 기본 경로다.
- > **`openclaw`·`hermes_agent` 는 "BYO(bring-your-own) 고급 런타임"** — 각자 CLI·게이트웨이·구독 인증·인증된 에이전트 1개가 **미리 갖춰져 있어야** 하며 b3os가 대신 설치하지 않는다. 준비 안 됐으면 preflight에서 막히니, **그럴 땐 `references/runtime-setup.md`의 설치·인증 절차를 안내하거나 `claude_channel`로 되돌린다.**
- > UI에서는 준비되지 않은 BYO도 숨기지 않는다. disabled 사유와 연동 CTA를 보여주고, 재확인 후 같은 옵션이 enabled 되는 흐름으로 안내한다. 내부/coming-soon 항목은 만들지 않는다.
- > **사용자가 위 3개 목록에 없는 런타임(예: 다른 AI 앱·CLI)을 요청하면** — 공개 지원 런타임은 `claude_channel`·`openclaw`·`hermes_agent` 3개뿐이라고 정직히 안내한다(영입 API가 그 외 런타임은 400으로 거부). 목록에 없는 것을 영입 선택지로 제시하지 말고, `claude_channel`(권장)로 안내한다.
-
- > 💡 **어떤 런타임이든 '첫 영입'은 Claude Code 세션에서 진행하는 걸 권장한다.** Claude Code는 preflight·준비물 설치·인증 안내·(고급 런타임은) API 영입까지 셸로 직접 몰아줄 수 있어(대시보드는 설치·인증을 못 함), openclaw·hermes 팀원도 **Claude Code에서 이 스킬로 영입**하는 게 가장 매끄럽다. 영입이 끝나 그 팀원이 응답하기 시작하면, 이후 추가 영입·운영은 그 팀원이 이어받는다.
-
- > 🔐 **발신자 게이트 — claude 와 외부/BYO 런타임은 다르다:**
- > - **claude_channel (기본축)**: 봇 DM 접근 허용은 access.json allowlist 로 관리된다. ★첫 claude 팀원은 봇 DM의 6자리 페어링 코드를 사람이 승인하는 게 **정상 경로**★ — 활성화로 봇이 뜨면 봇에 "안녕" → 봇이 6자리 코드로 응답 → 사람이 승인하면 이후 대화된다. 2번째부터의 claude 팀원은 첫 팀원의 allowlist(`allowFrom`)를 **자동 승계**(seedClaudeAccess가 기존 claude 멤버 access.json을 참조)해 페어링 없이 바로 대화된다. **완료 검증 = 봇 DM에 답(또는 6자리 코드)이 오는지**로 본다 — `owner_chat_id`로 검증하지 않는다(페어링은 access.json에 쓰고 owner_chat_id를 채우지 않는다).
- > - **openclaw**: 인바운드 DM 게이트 = ★pair-approve 페어링★(대시보드 [접근 승인]). 승인 전에는 응답 안 함 = 그게 게이트다. `owner_chat_id`가 openclaw DM을 막는 값이 아니다.
- > - **hermes**(v0.18): 인바운드 DM = ★텔레그램 페어링 게이트가 있다★(`hermes pairing`). 게이트웨이가 미승인 사용자에게 코드를 요구한다. b3os activate 가 ★팀장 chat_id(`owner_chat_id`)를 게이트웨이 allowlist(`TELEGRAM_ALLOWED_USERS`, plist EnvironmentVariables)에 동적 시드★하므로 **팀장은 코드 없이 바로 대화된다**. 팀장 외 사용자는 `hermes pairing approve <platform> <code>` 네이티브 페어링으로 승인. owner_chat_id 미확보면 시드 skip → 팀장도 수동 페어링 필요.
- > - **`owner_chat_id`(팀장 chat_id)**: 그룹 캡처·라우팅에 쓰며, ★hermes 는 이 값을 게이트웨이 allowlist 로 시드해 팀장 DM 을 연다★(openclaw 는 pair-approve 가 게이트라 owner_chat_id 로 열리지 않음). claude 페어링(access.json)과도 별개다. ★첫 claude 팀원 페어링 시 자동으로 채워진다(도출→persist).★
-
- ### 5-2. 런타임을 고른 순간 → 그 런타임만 인증 preflight
-
- **구독을 미리 캐묻지 않는다.** 고른 런타임의 CLI·로그인만 그때 확인한다.
-
- > **★인증은 "구독 모델"(OAuth)이 기본 — API 키가 아니다.★** claude/openclaw/hermes 모두 **이미 쓰는 구독을 OAuth 로그인으로 재사용**하는 게 기본 경로다(claude_channel 을 권한 이유와 동일). 어떤 구독으로 붙일지는 **사용자에게 물어본다**("Claude / ChatGPT / … 중 어느 구독?"). 환경에 `OPENAI_API_KEY` 같은 키가 이미 있어도, 사용자가 API 키를 원한다고 하지 않았으면 **구독(OAuth)으로 안내**하고 자동발견된 API 키 항목은 쓰지 않는다. API 키 방식은 **사용자가 명시적으로 원할 때만**의 예외 경로다. (BYO 런타임 인증 상세 = `references/runtime-setup.md`)
+ 필드 검증·에러 상세 = `references/recruit.md` Step A.
- - **`claude_channel` (쉬움, 대개 이미 로그인됨)**
- ```bash
- command -v claude >/dev/null || npm install -g @anthropic-ai/claude-code
- command -v tmux >/dev/null || brew install tmux
- claude --version && tmux -V
- ```
- 미로그인이면 활성화 preflight가 막고 안내한다 → "터미널에서 `claude` 한 번 실행해 로그인해 주세요".
- - **`openclaw` (고급)**: openclaw CLI + **인증된 에이전트 1개**(auth 복제 소스) + `python3`. 게이트웨이/세션
- 세팅이 필요 — 사용자에게 **고급**임을 알리고 `references/runtime-setup.md`를 따른다.
- - **`hermes_agent` (고급)**: hermes CLI + **base 프로필 1개**(auth 시드) + `python3`. 프로필 게이트웨이
- 세팅이 필요 — **고급**임을 알리고 `references/runtime-setup.md`를 따른다.
+ ## [5] 첫 팀원 영입
- > 있으면 바로 진행(present→proceed), 없으면 그 런타임의 설치·로그인만 안내(missing→guide). 다른 런타임 얘기로
- > 사용자를 헷갈리게 하지 않는다.
+ > ★★이 단계에 들어오면 **먼저 `references/recruit.md` 를 펼쳐 읽고** 진행한다★★ — 물어볼 필드·질문 문구·복사용 폼·기본값이 거기 다 있다. "이름·역할" 몇 개만 묻고 넘어가지 말 것.
- ### 5-3. 영입 API 순서 (요약)
+ **① 런타임 선택** — `claude_channel`(권장·쉬움) / `openclaw`·`hermes_agent`(ChatGPT 구독 BYO 고급). 목록·권장 이유·고른 순간의 preflight 명령 = `references/runtime-setup.md`.
- > 활성 공식 팀원은 최대 **15명**이다. 비공식/테스트 agent와 정지(off) 팀원은 제외하며, 상한 도달 시 기존 팀원을 정지하거나 퇴사 처리한 뒤 영입한다.
+ **② 사용자에게 먼저 다 묻는다** — **id**(영문 slug, ★display_name 과 별개이며 빠뜨리기 쉽다★) · **display_name** · **role** · **멘션명(별칭)** · **runtime+모델** · **persona**(선택).
- > ★★영입 전에 사용자에게 아래를 **먼저 다 물어본다 — 하나도 빼먹지 마라**★★ (recruit.md 를 안 펼치더라도 여기서 전부 묻는다. "이름·역할"만 묻고 넘어가지 말 것):
- > 1. **id** — 영문 소문자 slug(예: `alex`). 멘션·라우팅 키. ★display_name 과 별개이며 반드시 물어본다(빠뜨리기 쉬움).★
- > 2. **display_name** — 표시이름(예: `Alex`).
- > 3. **role** — 역할 한 줄(예: "백엔드 개발자").
- > 4. **멘션명(별칭)** — `@`로 부를 이름, 쉼표로 여러 개. 안 정하면 `[id, 표시이름]`이 기본(그래도 물어는 본다).
- > 5. **runtime + 모델** — ★구독으로 고른다★: **Claude 구독 → `claude_channel`** / **ChatGPT 구독 → `hermes_agent` 또는 `openclaw`**.
- > 6. **persona** — 성격·말투·전문성 한두 줄(선택). 주면 SOUL.md 로 저장.
- >
- > ★설명만 늘어놓지 말고, recruit.md 의 **'복사-붙여넣기 예제 폼'**(• 팀원 ID: … • 이름: … • 멘션명: … • Persona: … • 봇토큰: …)을 같이 보여줘서 사용자가 **복사해 값만 바꿔** 주게 한다.★
- > ★첫 팀원이 응답까지 성공한 뒤엔, "런타임까지 아시면 여러 명 한꺼번에"라며 recruit.md 의 **'배치 영입 폼'**(팀원별 id·이름·멘션명·persona·런타임/모델·봇토큰)을 안내한다.★ 정확한 질문 문구·예제·기본값·검증 = **`references/recruit.md` Step B 를 이 단계 진입 시 반드시 펼쳐 읽는다.**
+ **③ API 순서**
```
- POST /team/api/members/recruit {id, display_name, role, runtime, persona?} → ot_id
- ── 사람: BotFather에서 봇 생성 → 토큰을 Claude Code에 입력(본인 머신이라 OK) ──
- POST /team/api/ot/<ot_id>/provision {bot_token} # 토큰 0600 저장 + 런타임 로그인 preflight
- POST /team/api/ot/<ot_id>/activate # 런타임 기동(APPROVAL 필요)
- ── claude 런타임: telegram 플러그인 user-scope 1회 설치 ──
- ── 사람: 봇에 DM → 페어링 코드 승인 (claude_channel/openclaw만) ──
+ POST /team/api/members/recruit {id, display_name, role, runtime, persona?} → ot_id
+ ── 사람: BotFather 로 봇 생성 → 토큰 ──
+ POST /team/api/ot/<ot_id>/provision {bot_token} # 토큰 0600 저장 + 런타임 로그인 preflight
+ POST /team/api/ot/<ot_id>/activate # 런타임 기동 (APPROVAL 필요)
+ ── 사람: 봇에 DM → 페어링 승인 (런타임별로 다름) ──
```
- > **★ 사람만 할 수 있는 것**: ① BotFather 봇 생성 + 토큰(@BotFather → `/newbot`) ② 봇에 첫 DM 보내고
- > 페어링 코드 승인. 토큰은 **사용자가 Claude Code에 입력**하면 Claude가 provision 호출로 넘긴다(본인 머신·본인
- > 봇·revocable이라 실용적으로 안전). 더 조심하려면 대시보드 보안입력칸에 직접. Claude는 받은 토큰을 화면에 다시 출력하지 않는다.
+ > **★ 사람만 할 수 있는 것**: ①BotFather 봇 생성+토큰 ②봇에 첫 DM 보내고 페어링 승인. 토큰은 사용자가 Claude Code 에 입력하면 provision 으로 넘긴다. **받은 토큰을 화면에 다시 출력하지 않는다.**
- > **팀원 작업공간 위치** — 영입된 팀원의 작업공간(페르소나 `SOUL.md` + 규칙 `CLAUDE.md`/`AGENTS.md` + `TEAM-OS.md` 심링크)은
- > `$B3RYS_HOME/members/<팀원id>/` 에 생성됩니다(install.sh가 `B3RYS_HOME=$HOME/b3os` 세팅 → `~/b3os/members/<팀원id>/`, **repo 밖 자체완결 루트**).
+ - 활성 공식 팀원은 최대 **15명**.
+ - 팀원 작업공간 = `~/b3os/members/<팀원id>/` (repo 밖 자체완결 루트).
+ - **페이로드·OT 단계·토큰 안전전달·런타임별 페어링 게이트 = `references/recruit.md` (Step B~G) 필수 참조.**
- **상세 페이로드·OT 단계·토큰 안전전달·런타임별 페어링 = `references/recruit.md` 반드시 참조.**
+ ## [6] 1:1 DM 확인 — 합류 완료
- ## [6] 첫 팀원과 1:1 DM 확인 (합류 완료 — 라우터와 무관)
+ ★1:1 DM 은 라우터와 무관하다★(라우터는 그룹 ingress 전용). 폰에서 첫 팀원 봇에게 "안녕"을 보낸다.
- ★1:1 DM 은 라우터와 무관하다★(라우터는 그룹 ingress 전용). 폰에서 첫 팀원 봇에게 **1:1 DM**으로 "안녕" 보낸다:
- - **claude 첫 팀원**이면 봇이 **6자리 페어링 코드**로 응답한다. 승인(DM 허용)은 ★Claude Code 가 `~/.claude/channels/telegram-<id>/access.json` 의 `allowFrom` 에 본인 텔레그램 DM chat_id 를 추가하고 `dmPolicy` 를 `allowlist` 로 바꾸면★ 된다(activate 가 출력하는 안내 [F]와 동일 — 항상 작동, 외부 스킬 불필요). `setup-claude-telegram-bot` 스킬이 설치돼 있으면 `promote-pending.sh <id> <code>` 도 가능. ★주의: 대시보드 [접근 승인]·`pair-approve` 는 **openclaw 전용**이라 claude 엔 no-op(`skipped:true` 거짓성공)이다 — claude 페어링엔 쓰지 말 것.★ 승인하면 합류 완료. ★6자리 코드가 오는 것 자체가 봇이 살아있다는 신호★. (2번째 팀원부터는 첫 팀원 allowlist 를 승계해 페어링 없이 바로 답한다.)
- - **응답(또는 6자리 코드)이 오면 첫 팀원 합류 완료** — 첫 팀원은 DM만으로 충분하다.
+ - **응답(또는 6자리 페어링 코드)이 오면 합류 완료.** claude 첫 팀원은 코드가 오는 게 정상 — 승인하면 대화된다.
- 대시보드 **Topology** 에서 팀원·런타임·채널이 초록인지 확인.
- - 아무 응답도 없으면 → `references/troubleshooting.md` (1:1 무응답은 라우터가 아니라 **페어링 승인/플러그인/poller** 문제다).
-
- > **라우터 ON 은 여기서 필요 없다.** 라우터는 여러 팀원을 한 텔레그램 **그룹**에 모아 System OP 봇으로 라우팅하는 ★그룹(팀방) 협업용★이다(아래 선택 단계 "System OP 봇"). 1:1 DM만 쓸 거면 건너뛴다.
-
- ### ★ 첫 작업 시켜보기 (팀의 가치를 바로 체험 — handoff 로 이어짐)
-
- 응답을 확인했으면, 사용자에게 **첫 팀원에게 실제로 일 하나를 시켜보라고 권한다:**
-
- > 💬 **팀원에게 첫 작업을 시켜보세요** — 예: "[팀원 이름], 간단한 거 하나 해줘".
- > 팀원이 응답하고, 대시보드 **Tasks 칸반**에 카드로 뜨는 걸 확인하면
- > **'AI 팀에게 일 맡기고 추적하는' 느낌**이 옵니다.
-
- 특정 작업 API를 만들 필요 없다 — 그냥 팀원에게 **자연스럽게 말을 걸도록** 안내하면 된다. 이 체험이 곧
- 아래 handoff(§7)의 시작이다.
+ - 무응답이면 → `references/troubleshooting.md` (라우터가 아니라 **페어링 승인/플러그인/poller** 문제다).
+ - 런타임별 승인 방법·완료 판정 = `references/recruit.md` Step G·H. ★claude 에 `pair-approve` 를 쓰면 안 된다(openclaw 전용, 거짓성공)★
- ---
+ **첫 작업 시켜보기** — 응답을 확인했으면 "[팀원 이름], 간단한 거 하나 해줘"처럼 **실제로 일을 시켜보라고 권한다.** 대시보드 **Tasks 칸반**에 카드가 뜨는 걸 보면 팀의 가치가 바로 전달된다. 이 체험이 곧 handoff 의 시작이다.
## [7] ★HANDOFF — 첫 팀원에게 넘긴다 (여기서 이 스킬의 일은 끝)
- 첫 팀원이 응답하면 **설치는 끝이고, 이제 그 팀원과 일하는 단계**다. 사용자에게 이렇게 안내하고 **손을 뗀다:**
-
- > 🎉 **AI 팀의 첫 팀원 [이름]이 합류했어요! 이제부터는 팀원과 직접 대화하세요:**
- > - **텔레그램/대시보드에서 `@[이름]` 멘션으로 작업 지시** (예: "@alex 이 코드 리뷰해줘")
- > - **추가 영입·운영·문제해결은 팀원 [이름]에게 물어보세요** — "다음 팀원 어떻게 영입해?" 하면 팀원이 도와줍니다.
+ > 🎉 **첫 팀원 [이름]이 합류했어요! 이제부터는 팀원과 직접 대화하세요:**
+ > - **`@[이름]` 멘션으로 작업 지시** (예: "@alex 이 코드 리뷰해줘")
+ > - **추가 영입·운영·문제해결은 팀원에게** — "다음 팀원 어떻게 영입해?" 하면 팀원이 도와줍니다.
> - 대시보드 **Tasks 칸반**으로 진행 추적, **Topology**로 연결 상태 확인.
- 즉 b3os는 "설치하면 끝"이 아니라 **"첫 팀원을 세워서 그 팀원에게 넘기는 것"** — 이 시점부터 사용자는 자기 AI
- 팀의 팀장이 되고, 이 스킬이 아니라 **팀원**이 이후를 이끈다.
-
- ### ★ 핸드오프가 실제로 작동하려면 — b3os 자체가 팀 스킬이다
-
- 첫 팀원이 "다음 팀원 어떻게 영입해?" 같은 **세팅·운영 질문**을 받으면, **b3os 스킬을 그때 불러서** 답한다.
- b3os는 팀 스킬 인덱스(`docs/B3OS_SKILLS.md`)에 등록된 **팀 스킬**이고, 이 스킬의
- `references/recruit.md`·`references/b3os-ops-primer.md`·`references/troubleshooting.md` **자체가 운영
- 지식**이다. 팀원 페르소나에 운영 절차를 미리 밀어 넣을(주입) 필요가 없다 — **필요할 때만 온디맨드로
- 로드**하는 progressive disclosure(점진적 노출)라 페르소나가 비대해지지 않는다.
-
- > **왜 코드 주입이 아니라 스킬인가** — 예전엔 ops-primer를 `bundle` 응답이나 `buildPersona`로 팀원
- > 워크스페이스에 자동 주입하는 **저장소 코드 변경**을 고려했으나, 설계상 **b3os를 팀 스킬로 두는 쪽**으로
- > 정했다. 팀원은 설치·운영 질문이 올 때 이 스킬(recruit.md / b3os-ops-primer.md / troubleshooting.md)을
- > 참조하면 되고(온디맨드), b3rys-team-os 저장소 코드는 건드리지 않는다. 영입 시
- > `GET /team/api/ot/<ot_id>/bundle` 이 **TEAM-OS 미션·현재상태·능력 카탈로그·팀 스킬 목록·persona**를
- > 첫 팀원에게 전달하는 자동 주입은 그대로 두고, **"어떻게 영입/퇴사/라우터/삭제하나" 같은 운영 절차만
- > 스킬로 분리**해 그때그때 로드한다.
-
- ## [8] (선택) 팀원 더 추가 — 영입 루프 반복
-
- 첫 팀원 이후 "팀원 더 추가할까요?" 물어보고, 원하면 **[5]를 그대로 반복**한다(런타임 선택 → 그 런타임 preflight
- → recruit → provision → activate → 페어링). 런타임별 참고:
-
- - **claude 팀원 여러 명** — 한 머신의 Claude 로그인 **하나를 공유**한다(각자 봇 토큰만 다름). telegram 플러그인은 user-scope 1회면 끝.
- - **openclaw 팀원** — 공유 게이트웨이. 새 에이전트마다 페어링(pair-approve) 필요.
- - **hermes 팀원** — 프로필별 게이트웨이. base 프로필(`HERMES_BASE_PROFILE`, 기본 `b3os`)은 auth 소스라 퇴사/삭제 대상이 아님.
-
- > 다만 **추가 영입도 첫 팀원이 이어받는 게 이상적**이다(§7 handoff). 이 스킬은 "첫 팀원까지"가 기본 임무이고,
- > [8]은 사용자가 스킬에게 계속 맡기고 싶을 때의 편의 경로다.
-
- ---
-
- ## [9] 런타임 교체(runtime swap) — 기존 팀원의 런타임만 바꾸기 (메모리 보존)
-
- 이미 합류한 팀원을 **퇴사 없이** 다른 공개 런타임(`claude_channel`/`openclaw`/`hermes_agent`)으로 옮긴다.
- 워크스페이스(`MEMORY.md`·`memory/*.md`·`TODO.md`·git)는 **팀원 id로 키잉**돼 있어 런타임이 바뀌어도 그대로
- 남는다 — **퇴사(DELETE)와 달리 워크스페이스를 `.archived`로 옮기지 않는다.** 그러니 "런타임만 바꾸고 싶다"는
- 요청에 절대 퇴사(DELETE)+재영입(recruit) 경로를 쓰지 않는다(그 경로는 메모리를 archive로 이동시켜버린다).
-
- ```
- STEP A. 요청 파싱 — "[팀원]을 [런타임]으로 바꿔줘" → target을 claude_channel/openclaw/hermes_agent 로 정규화.
- 별칭·오타면(예: "오픈클로"→openclaw, "클로드"→claude) 확인 질문.
- ↓
- STEP B. ★preflight — 대상 런타임의 CLI·인증을 실제로 확인 (present→진행 / missing→안내, 아래 참조)
- ↓
- STEP C. present → POST /team/api/members/<id>/swap-runtime {target_runtime, confirm_name} 호출
- → 단계별 진행(teardown→registry→persona→activate) 관찰 → poller 정상까지 확인
- ↓
- STEP D. missing → 무리하게 설치 시도하지 말고 안내 (claude=설치 가능 / openclaw·hermes=BYO 사전준비)
- ↓
- STEP E. "교체 완료 + 메모리 보존됨" 보고 (auto-memory 소실 경고는 아래 참조)
- ```
-
- - **preflight가 스킬의 강한 부분** — 대상 런타임의 CLI·인증을 그 자리에서 직접 확인한다(바이너리
- `which`/고정경로, 인증 파일은 **존재 여부만**([ -s ] 또는 `ls`) — **값은 절대 열람하지 않는다**). [5-2]와
- 같은 present→proceed / missing→guide 원칙. `claude_channel`은 CLI 설치가 쉬우니 설치·로그인
- 명령을 **팀장이 이 서버 Mac 터미널에서 직접 실행**하도록 구체적으로 안내한다(경로만 안내, 토큰·키 값은
- 화면에 출력하지 않는다). `openclaw`/`hermes_agent`는 게이트웨이·인증 에이전트가 **미리 준비**돼 있어야
- 하는 BYO 고급 런타임이라 — 준비 안 됐으면 [5-1]과 동일하게 **무리해서 설치 시도하지 말고**(할루시 위험)
- `claude_channel` 대안을 권하거나 팀장에게 사전 준비를 요청한다. 재확인 후 재시도.
- - **`confirm_name`은 필수** — 팀원의 `display_name`과 정확히 일치해야 한다(퇴사의 오발 방지 안전장치와
- 동일 패턴). 이 안전장치 없이는 서버가 거부한다.
- - **파괴적 self-mod — 반드시 팀장 승인 후 진행.** 런타임 교체는 봇 프로세스 재시작·브리지 파일 교체를
- 동반하는 서비스 중단성 작업이다(TEAM-OS §4). **dry-run(preflight 결과 + 계획 표시)을 먼저 보여주고,
- 팀장이 "가" 또는 터미널/`/approve`로 승인한 뒤에만** 실제 `swap-runtime` 호출을 실행한다. 서버도
- `APPROVAL_EXECUTION_ENABLED=1`(활성화 스위치, [2] 참조)가 아니면 교체를 거부한다.
- - **메모리 보존 범위를 사용자에게 명시**: 워크스페이스(`MEMORY.md`·`memory/*.md`·`TODO.md`·`README.md`·git)는
- 그대로 유지된다. 단 **auto-memory(Claude 전용, `~/.claude/projects/.../memory/`)는 워크스페이스 밖에
- 있고 Claude 런타임에서만 주입된다** — `claude_channel`에서 다른 런타임으로 바꾸면 이 자동 기억은 **파일은
- 디스크에 남지만 다음 세션에 주입되지 않는다.** 교체 전 이 점을 미리 경고한다.
- - 상세 절차(엔드포인트 계약·단계별 로그·에러 코드·롤백 동작)는 `references/b3os-ops-primer.md`
- **"팀원 런타임 교체(runtime swap)"** 절 참조.
-
- ---
-
- ## (선택) 팀방(그룹) 협업 셋업 — System OP 봇
-
- > **이름 정리** — 이 봇은 문서·UI 곳곳에서 **System OP 봇 = 팀 라우터 = capture 봇**으로 불린다(같은 하나). 대시보드 라벨은 **"시스템 OP"**, 토큰 입력칸은 **"capture 봇 토큰"**. 아래는 전부 이 한 봇 얘기다.
-
- 첫 팀원은 **1:1 DM**으로 충분하다(그룹·System OP 봇 불필요). 하지만 **여러 팀원을 한 텔레그램 그룹에 모아
- 함께 대화**하고 싶으면 **System OP 봇**을 붙인다 — 이 봇이 팀 텔레그램 **그룹의 입구(ingress, 수신 경로)**
- 역할을 해서 그룹 메시지를 담당 팀원(에이전트)에게 라우팅한다. 즉 System OP 봇은 **그룹 협업을 켜는
- 스위치**이지 모니터링 알림 봇이 아니다. (그래서 이 단계가 "첫 팀원(DM)" 다음에 오는 선택 단계다.)
-
- > **★왜 필요한가 / 안 해도 되는 것 (헷갈리기 쉬움 — 정확히):★**
- > - **필요한 경우**: ①팀 텔레그램 **그룹방에서 여러 팀원이 자동으로** 대화에 끼어들게 하고 싶을 때 ②`/status`·`/board`·`/digest`·`/approve` 같은 **팀 운영 명령/알림**을 텔레그램으로 쓰고 싶을 때.
- > - **★필요 없는 경우 (router OFF / System OP 미설정이어도 그대로 동작):★** ①**1:1 DM** — 각 팀원 자기 봇에 직접 말 걸기 ②**팀원끼리 협업(handoff·버스)** — 한 팀원이 다른 팀원에게 위임·요청하는 것. 이 둘은 System OP·라우터와 **무관하게 동작한다**(라우터는 오직 '그룹방 자동응답'만 켜고 끈다).
- > - 그래서 팀방을 안 만들어도 팀은 돌아간다 — System OP 는 "그룹방 자동협업 + 운영 알림"을 원할 때만 붙이는 **선택** 레이어다.
-
- **System OP 봇이 하는 일 (정확히):**
- - **그룹 ingress** — 팀 텔레그램 그룹을 읽어 각 메시지를 담당 팀원에게 라우팅.
- - **온디맨드(on-demand) 명령** — 그룹/DM에서 물으면 그때 답하는 명령: `/status`(팀 상태) ·
- `/board`(칸반) · `/digest`(요약) · `/approve`(민감 실행 승인) · `/onoff`(라우터/기능 토글).
-
- > **⚠️ System OP 봇은 "시스템 오퍼레이터"입니다 — 대화모드 OFF.** 팀원처럼 잡담·대화하지 않습니다.
- > 그룹을 연결(ingress/라우팅)하고 **명령**(`/status` `/board` `/digest` `/approve` `/onoff`)에만 답할 뿐입니다.
- > 그러니 사용자에게 이 봇을 **팀원처럼 "말 걸 수 있는" 대상으로 안내하지 마세요** — 대화는 팀원(에이전트)에게, OP 봇은 명령에.
-
- **셋업 (사람: 봇 1개 + 그룹 chat_id + op 봇을 그룹 관리자로). 각 단계에 "왜 / 흔한 실패 / 확인법"을 붙였다:**
-
- 1. **op 봇 생성** — BotFather로 **System OP 전용 봇**을 하나 더 만들어 토큰을 받는다(팀원 봇과 **별개**의 봇). *(왜: op 봇은 팀원이 아니라 그룹 입구·운영 명령 전용. · 확인: `/newbot` 이 준 토큰을 받으면 됨 — 토큰 값은 화면·로그에 다시 노출하지 않는다.)*
-
- 2. **그룹 생성 + 봇 초대 (★op 봇은 관리자로★)** — 팀원들을 넣을 **텔레그램 그룹**을 만들고 **op 봇 + 각 팀원 봇**을 초대하되, **op 봇은 관리자(admin)로 추가**한다(3번 이유). 팀원 봇은 일반 멤버로 충분하다 — 그룹 대화를 읽는 건 op 봇 하나다. *(확인: 그룹 멤버 목록에 op 봇이 관리자로, 팀원 봇이 멤버로 보이면 됨.)*
-
- 3. **★op 봇을 그룹 관리자(admin)로 올리기 — 가장 자주 빠뜨리는 단계, 안 하면 라우팅이 통째로 안 된다★** — 그룹 설정 ▸ 관리자 ▸ op 봇을 관리자로 추가. 2번에서 초대할 때 바로 관리자로 넣으면 이 단계를 따로 안 밟아도 된다.
- - **왜**: 텔레그램 봇은 기본적으로 그룹에서 **자기에게 온 명령(`/cmd`)·자기 멘션·자기 답장만** 받고 **일반 그룹 메시지는 못 받는다**(privacy mode, BotFather 기본값 = Enabled). 그러면 capture 봇이 그룹 대화를 못 읽어 라우팅(멘션 없는 지시·다른 팀원 멘션)이 전혀 동작하지 않는다. **관리자는 이 제한을 받지 않아** 전체 메시지를 받는다.
- - **대안**: @BotFather → `/setprivacy` → op 봇 선택 → **Disable** 로도 같은 효과를 낸다. 관리자로 못 올리는 그룹이거나 BotFather 설정을 선호할 때 쓴다.
- - **흔한 실패**: 이 단계를 건너뛰면 아래 4-b 자동감지가 `no_group_seen` 으로 그룹을 못 찾고, 라우터를 켜도 그룹에서 아무도 응답하지 않는다.
- - **확인**: 4-b 자동감지가 그룹을 찾아내면 = 캡처가 실제로 되고 있다는 증거.
+ b3os는 "설치하면 끝"이 아니라 **"첫 팀원을 세워서 그 팀원에게 넘기는 것"** 이다. 이 시점부터 사용자는 자기 AI 팀의 팀장이 되고, 이 스킬이 아니라 **팀원**이 이후를 이끈다.
- 4. **대시보드 Settings ▸ 시스템 OP (System OP)** 에서 —
- - **(4-a) capture 봇 토큰 입력** → **봇 연결 확인** 버튼을 누르면 봇 username 이 떠서 토큰 유효성이 검증된다(내부: `POST /system-op/check` = 텔레그램 `getMe`). *(적용 시점: 대시보드가 저장 후 "즉시 적용" 또는 "재시작 시 적용"을 표시해준다 — 표시대로 따른다.)*
- - **(4-b) 그룹 chat_id 설정 (자동감지 권장)** — op 봇이 그룹에 든 상태에서 그룹에 **아무 메시지나 하나** 올린 뒤, **Claude Code에게 "우리 그룹 chat_id 알려줘"** 라고 하면 자동으로 찾아 설정한다(내부: `POST /system-op/detect-group` — capture 워커가 이미 본 그룹을 조회하고, **그룹이 하나면 자동 지정**·둘 이상이면 목록을 주고 고르게 한다). `no_group_seen` 이 뜨면 → op 봇이 그룹에 있는지 + **3번 op 봇이 그룹 관리자인지**(또는 privacy Disable) + 그룹에 메시지를 하나 보냈는지 확인 후 재시도. 수동으로 넣어도 된다 — 그룹에 잠깐 **@userinfobot**(또는 @RawDataBot)을 초대하면 chat_id(대개 `-100…`)를 알려준다.
- - **(4-c) Router ON** (시스템 OP 토글 또는 `.env` `ROUTER_ENABLED=true`). ★라우터 토글은 즉시 반영★(재시작 불필요).
+ **핸드오프가 작동하는 이유** — b3os 는 팀 스킬 인덱스(`docs/B3OS_SKILLS.md`)에 등록된 팀 스킬이고, 이 스킬의 `references/*` 자체가 운영 지식이다. 첫 팀원은 세팅·운영 질문을 받으면 **그때 이 스킬을 불러서** 답한다 — 페르소나에 운영 절차를 미리 밀어 넣을 필요가 없다(온디맨드 로딩).
- 5. **동작 확인** — 그룹에 `@팀원` 멘션 또는 `/status` → 응답이 오면 팀방 협업 준비 완료. 응답이 없으면: ①라우터가 ON 인지 ②op 봇이 그룹 관리자인지(3번, 또는 privacy Disable) ③그룹 chat_id 가 맞게 잡혔는지 순으로 본다.
+ ## [8] 그다음 — 전부 선택
- **헬스 모니터링은 대시보드에서만 본다 (정직하게):**
- - b3os는 에이전트 위험/복구 감지·라이브 상태 같은 **헬스 모니터링을 자동으로** 돌리지만, 그 결과는
- **대시보드(Topology/Team 탭)에서만** 보인다. **b3os는 텔레그램으로 헬스 알림을 push 하지 않는다.**
- - 공개 빌드에는 **auto-heal(자동복구)도, 예약 digest 자동 푸시도 없다** — 그건 별도 내부 전용
- 스크립트/launchd이고 **공개 저장소에서 제외**돼 있다. (`/digest` 명령은 물었을 때 답하는 온디맨드일 뿐,
- 주기적으로 알아서 보내주지 않는다.)
- - 그러니 **"뭔가 깨지면 텔레그램으로 알려준다"고 안내하지 말 것** — 공개 빌드에선 사실이 아니다. 상태는
- **대시보드에서 확인**하고, System OP 봇은 **ingress + 온디맨드 명령**만 한다고 정직하게 안내한다.
+ | 하고 싶은 것 | 어디를 편다 |
+ |---|---|
+ | 팀원 더 추가 | [5] 를 그대로 반복 · `references/recruit.md` |
+ | 팀방(그룹)에서 여러 팀원이 함께 대화 | `references/group-room-setup.md` (System OP 봇) |
+ | 기존 팀원의 런타임만 교체 (메모리 보존) | `references/b3os-ops-primer.md` §2 |
+ | 안 뜬다 / 봇 무응답 / 리부팅 후 복구 | `references/troubleshooting.md` · ops-primer §10 |
+ | 긴급 전원 정지(폭주) · 상시가동 등록 | `references/b3os-ops-primer.md` §12·§13 |
+ | 뭐가 자동으로 도는지 · 지연 작업 예약 | `references/system-jobs.md` |
+ | 업데이트 · 퇴사 · 라우터 토글 | `references/b3os-ops-primer.md` |
- ---
+ - **claude 팀원 여러 명** — 한 머신의 Claude 로그인 **하나를 공유**한다(각자 봇 토큰만 다름).
+ - **런타임 교체는 퇴사+재영입으로 하지 않는다** — 퇴사(DELETE)는 워크스페이스를 `.archived` 로 옮겨 **메모리를 잃는다.** `swap-runtime` 은 팀원 id 로 키잉된 워크스페이스를 그대로 둔다. 교체는 서비스 중단성 self-mod 라 **팀장 승인 후** 진행하고, `confirm_name` 이 `display_name` 과 정확히 일치해야 한다.
## 삭제 (uninstall)
- 사용자가 "b3os 언인스톨/삭제해줘" 하면:
```bash
- cd "$B3OS" && bash uninstall.sh # 확인 프롬프트 → 팀원 전원 오프보드 → 서버 정지 → 데이터 삭제
- # bash uninstall.sh --yes # 확인 생략(자동화)
- # bash uninstall.sh --keep-data # 오프보드+정지만, team.db/.env/데이터 보존
+ cd "$B3OS" && bash uninstall.sh # 전원 오프보드 → 서버 정지 → 데이터 삭제
+ # --yes(확인 생략) · --keep-data(오프보드+정지만, team.db/.env 보존)
```
- 마지막에 스크립트가 안내하는 `rm -rf "$B3OS"` 로 repo 폴더까지 지우면 끝.
- (uninstall.sh는 설정된 base hermes 프로필(`HERMES_BASE_PROFILE`, 기본 `b3os`)을 보존하고, 알려진 경로만 안전하게 지운다.)
+ 마지막에 스크립트가 안내하는 `rm -rf "$B3OS"` 로 repo 폴더까지 지우면 끝. base hermes 프로필은 보존된다.
+
## 참고 파일
- - `references/recruit.md` — 영입 상세: API 페이로드·OT 단계(register→provision→preflight→bundle→join)·
- telegram 플러그인 user-scope 설치·페어링 코드 승인·토큰 안전전달·런타임별 차이(claude/openclaw/hermes).
- - `references/runtime-setup.md` — OpenClaw/Hermes BYO 런타임 설치·인증 절차와 preflight 재확인.
- - `references/b3os-ops-primer.md` — **첫 팀원이 이어받을 운영 요약**: 추가 영입·퇴사·**런타임 교체(swap)**·
- 라우터 토글·트러블슈팅·삭제. 핸드오프(§7) 이후 팀원이 세팅·운영 질문을 받으면 이 스킬을 통해
- **온디맨드로 참조**하는 운영 레퍼런스(코드 주입 아님).
- - `references/troubleshooting.md` — 봇 무응답·활성화 실패·활성화 비허용·bun PATH 등 4대 트러블슈팅.
+ | 파일 | 언제 편다 |
+ |---|---|
+ | `references/recruit.md` | 영입 상세 — API 페이로드·OT 단계·토큰 전달·런타임별 페어링 |
+ | `references/runtime-setup.md` | 런타임 고르기·preflight·OpenClaw/Hermes BYO 설치·인증 |
+ | `references/group-room-setup.md` | 팀방(그룹) 협업 — System OP 봇 셋업 |
+ | `references/b3os-ops-primer.md` | 운영 전반 — 추가 영입·퇴사·런타임 교체·라우터·복구·ALL-STOP·상시가동·업데이트 |
+ | `references/troubleshooting.md` | 봇 무응답·활성화 실패·bun PATH |
+ | `references/system-jobs.md` | 기본 시스템 잡 목록·지연 작업 예약 |
## 안전 원칙 (항상)
- - **토큰 값 다시 출력 금지** — 받은 BotFather/봇 토큰을 화면·로그·커밋에 다시 노출하지 않는다(provision 호출에만 사용).
- - **활성화 승인·페어링 코드는 사람 몫** — Claude가 대신 승인하거나 우회하지 않는다. (b3os는 승인 PIN을
- 강제하지 않는다 — 민감 실행은 대시보드에서 사람이 승인하면 바로 실행된다.)
- - **본인 전용 장비 전제** — 공용/공개 노출 금지(엣지 인증 없이).
- - 저장소가 공개 repo이므로, clone 후 로컬 `.env`·`team.db`·토큰은 커밋 대상이 아니다(이미 gitignore).
+ - **토큰 값 다시 출력 금지** — 받은 봇 토큰을 화면·로그·커밋에 노출하지 않는다(provision 호출에만 사용).
+ - **활성화 승인·페어링 코드는 사람 몫** — 대신 승인하거나 우회하지 않는다.
+ - **본인 전용 장비 전제** — 엣지 인증 없이 공용/공개 노출 금지.
+ - 공개 repo 이므로 로컬 `.env`·`team.db`·토큰은 커밋 대상이 아니다(이미 gitignore).