.env
(git 제외)와 배포자 개인 SSH 설정에서만 관리합니다.
01배포
배포는 개발 담당자의 로컬 머신에서 deploy.sh로 실행합니다(운영 서버에서 직접 빌드하지 않음).
bash deploy.sh # 이미지 빌드 + 운영 서버 배포 bash deploy.sh --build-only # 배포 이미지(deploy_images.tar)와 version.txt만 로컬에 생성
필요한 환경변수(쉘)
| 변수 | 의미 | 기본값 |
|---|---|---|
COSMOS_HOST | 배포 대상 서버 주소 | 저장소에 기록하지 않음 — 배포자가 직접 지정 |
COSMOS_SSH_PORT | SSH 포트 | 배포자가 직접 지정 |
COSMOS_USER | SSH 접속 계정 | 배포자가 직접 지정 |
COSMOS_PATH | 서버의 배포 디렉터리 | 배포자가 직접 지정 |
COSMOS_SSH_KEY | SSH 개인키 경로. 기본 이름(id_rsa 등)이 아니면 ssh가 자동으로 못 찾아 비밀번호 프롬프트로 폴백된다 | $HOME/.ssh/cosmos_deploy |
COSMOS_DEPLOYED_BY | 배포 이력에 남길 배포자 이름 | whoami 결과 |
값은 셸 세션에 export COSMOS_HOST=... 형태로 두거나, 반복 배포한다면 개인 셸 프로필(~/.bashrc 등)에 저장해 두는 걸 권장합니다 — 저장소 파일에는 넣지 않습니다.
배포 스크립트가 하는 일
build_prod.sh로 이미지 빌드 →deploy_images.tar,version.txt생성- 서버의
vault/,logs/디렉터리를 만들고 컨테이너 실행 계정(uid 10001)으로 소유권 설정 - 배포 전 서버의 현재
version.txt를version.prev.txt로 백업(롤백 대비) - 이미지·버전·환경설정·compose 파일·롤백 스크립트를 서버로 전송
- 서버에서
run_on_server.sh실행 — 컨테이너 재기동 - 배포 이력을 서버의
deploy_history.log에 한 줄 추가(시각·버전·배포자·커밋해시·커밋 메시지)
vault/·logs/가
root 소유로 남아 있으면 팀 노트 저장 시 PermissionError로 500 오류가 납니다.
deploy.sh가 매 배포마다 자동으로 chown하지만, 수동으로 디렉터리를
새로 만든 경우엔 직접 확인하세요.
02롤백
rollback.sh는 서버에서 실행합니다(로컬이 아님). 버전 문자열을 외울 필요가 없도록
deploy_history.log를 사람이 읽을 수 있는 표로 보여줍니다.
bash rollback.sh # 이력을 보여주고, 있으면 바로 직전 버전으로 되돌림 bash rollback.sh --list # 되돌리지 않고 이력만 확인 bash rollback.sh <VERSION> # 이력에서 확인한 특정 버전으로 되돌림
03환경변수
.env(저장소에는 .env.example만 커밋됨)에서 관리합니다. 값을 바꾼 뒤에는 컨테이너 재시작이 필요합니다
(팀별 모델/도구 설정처럼 DB에 저장되는 값은 예외 — 재시작 없이 반영).
| 변수 | 구분 | 설명 |
|---|---|---|
ANTHROPIC_API_KEY | 필수 | Claude API 키 |
ANTHROPIC_MODEL | 선택 | 기본 응답 모델(기본값 claude-sonnet-5) |
HERMES_LIGHT_MODEL | 선택 | 자동학습 판단 등 가벼운 호출에 쓰는 모델(기본값 claude-haiku-4-5) |
DATABASE_URL | 로그인 시스템에 필수 | PostgreSQL 접속 문자열. 비어 있으면 경량(솔로) 모드로만 동작 |
HERMES_SOLO_MODE | 선택 | 1이면 DB·로그인 없이 단독 실행(개인용). 회사 배포에서는 절대 켜지 않음 |
HERMES_ADMIN_USER / HERMES_ADMIN_PASSWORD | 최초 1회 | 서버 최초 기동 시 그룹장 계정 자동 생성용. 이후 계정 관리는 /admin에서 |
HERMES_MONTHLY_CREDIT_BUDGET_USD | 선택 | 월 사용 한도(USD). 미설정 시 예산 배너 없음 |
HERMES_BUDGET_WARN_RATIO | 선택 | 경고 배너가 뜨는 사용률(기본 0.8 = 80%) |
HERMES_USD_KRW_RATE_FALLBACK | 선택 | 환율 조회 실패 시 쓸 대체 환율(기본 1400) |
HERMES_WEB_SEARCH_MAX_USES | 선택 | 대화 1턴당 웹검색 최대 횟수(기본 3, 0이면 비활성화) |
HERMES_AUTONOMOUS_ENABLED | 선택 | 자율 감시 폴러 킬스위치(기본 켜짐). 0이면 폴러 자체가 기동하지 않음 |
HERMES_AUTONOMOUS_POLL_TICK_SEC | 선택 | 폴러가 확인 주기를 검사하는 간격(기본 60초) |
HERMES_DAILY_TOKEN_WARN_THRESHOLD | 선택 | 대시보드 "24시간 토큰" 경고 임계치 |
HERMES_MAX_HISTORY | 선택 | 대화 맥락으로 유지할 최대 메시지 수(기본 20) |
DISCORD_BOT_TOKEN | 선택 | 보관용 디스코드 봇(python -m hermes.bot) 사용 시에만 |
04DB 운영 원칙
- 테이블·컬럼은 앱이 자동으로 만듭니다.
db.py의CREATE TABLE IF NOT EXISTS/ALTER TABLE ADD COLUMN IF NOT EXISTS문 목록이 서버 기동 시(db.init()) 순서대로, 문 단위로 예외를 삼키며 실행됩니다. 즉 배포 후 재기동만 하면 스키마가 최신 상태로 맞춰집니다. - 스키마·search_path는 최초 1회 사람이 직접 준비합니다.
CREATE SCHEMA IF NOT EXISTS cosmos와ALTER ROLE ... SET search_path = cosmos, extensions, public는 README의 "DB 사전 준비" 참고. 기동 로그에[db.init] 스키마 문 실행 실패가 보이면 이게 안 된 상태입니다. - 직접 DDL을 실행하지 않습니다. 컬럼 추가·변경이 필요하면
db.py의 마이그레이션 목록에 추가하고 배포로 반영합니다 — 운영 DB에 수동으로ALTER TABLE을 치지 않습니다(재현 불가능한 상태 방지). - 대량 UPDATE/DELETE는 사전 승인 없이 실행하지 않습니다. 필요하면 SQL과 적용·롤백·검증 방법을 먼저 정리해 검토받습니다.
05자율 감시(watch) 운영
서버가 사용자 질문 없이도 스스로 상황을 확인하고 초안을 만드는 기능입니다. 항상 읽기 전용이고, 실행은
승인 후에만 이뤄집니다(file/hermes_autonomous_design.md 참고).
감시 가능한 대상(고정 4종)
| source_query | 내용 |
|---|---|
new_documents | 새로 업로드된 사내 문서 |
error_spike | 최근 실패한 모델 호출(에러) 급증 |
pending_document_reviews | 검토 대기 중인 제출 문서 |
pending_user_signups | 가입 승인 대기 중인 신규 사용자 |
이 4종은 backend/hermes/autonomous.py의 SOURCES 딕셔너리에 하드코딩돼 있습니다.
새로운 감시 대상이 필요하면 코드에 읽기 전용 조회 함수를 추가해야 하며, 자유 SQL 경로는 설계 원칙상 만들지 않습니다.
채팅에서 새 감시 항목 제안받기
팀원이 채팅에서 "이런 게 생기면 알려줘"라고 요청하면 propose_watch 도구가 /admin·
/dashboard의 승인 대기함에 새 감시 항목 제안으로 등록합니다. 위 4종 중 하나로만 제안할 수 있고,
그룹장이 승인해야 실제 hermes_event_watch 행이 만들어집니다. 이미 같은 팀에 같은 종류의
watch가 있으면 승인해도 조용히 스킵되고(중복 방지) 화면에 안내됩니다.
watch별 자동승인 화이트리스트
/dashboard의 "자율 폴러 현황"에서 그룹장이 특정 watch의 자동승인을 켜면, 그 watch가 이후 만드는
초안은 승인 대기 없이 즉시 승인 처리됩니다.
06승인 대기함 운영
/admin·/dashboard의 승인 대기함에는 세 종류가 섞여 들어옵니다.
| source | 누가 만드는가 | 승인 시 실제로 일어나는 일 |
|---|---|---|
autonomous | 자율 감시 폴러 | 상태만 "승인"으로 표시(발송·반영은 사람이 직접) |
code_change | 채팅 중 propose_code_change 도구 | 상태만 표시. 실제 코드 반영은 개발자가 검토 후 별도로 수행 |
watch_request | 채팅 중 propose_watch 도구 | 상태 표시 + 실제로 watch가 생성됨(예외 — §5 참고) |
팀장은 자기 팀 요청만, 그룹장은 전 팀을 볼 수 있습니다. 반려에는 부수 효과가 없습니다.
07비용·예산 모니터링
/dashboard의 "이번 달 예상 비용"은 호출 시점 환율을 각 호출마다 곱해 누적한 값입니다 — 현재 환율을 총 사용량에 일괄로 곱하는 방식이 아닙니다. 팀별 차트도 동일합니다.HERMES_MONTHLY_CREDIT_BUDGET_USD를 설정하면 사용률HERMES_BUDGET_WARN_RATIO(기본 80%)에서 경고 배너, 100%에서 그룹장을 제외한 사용자의 새 요청이 차단됩니다.- 비용 집계는 60초 캐시라 한도 도달 후 최대 1분까지 차단이 지연될 수 있습니다.
- 팀 위임(
delegate_to_team) 호출 비용은 사용량에 기록되지만, 위임이 실패한 건은 기록되지 않습니다 — 실제 청구와 대시보드 수치가 미세하게 다를 수 있는 지점입니다.
08에러 이력 처리
/dashboard의 에러 이력에서 팀별 모델 호출 실패를 시간순(미해결 우선)으로 봅니다.
/admin요약 배너의 "마지막 에러"는 이 이력의 미해결 최신 건과 연동됩니다.- 건별로 해결 처리할 수 있고, 처리자·처리 시각이 함께 기록됩니다.
- 동일 원인이 반복되면(예: 크레딧 부족) 근본 원인을 먼저 해소하고 나서 일괄로 해결 처리하는 편이 이력을 깔끔하게 유지합니다.
09트러블슈팅
| 증상 | 원인 | 조치 |
|---|---|---|
| 배포 후 화면이 안 바뀜 | 브라우저가 캐시된 구버전 정적 파일을 계속 씀 | 강력 새로고침. 주요 페이지 라우트는 Cache-Control: no-store로 응답하지만
CDN·프록시 캐시가 있다면 별도 확인 |
| 채팅에서 노트 저장 시 HTTP 500 | vault/가 root 소유라 컨테이너 실행 계정(uid 10001)이 못 씀 |
서버에서 chown -R 10001:10001 vault logs. 이후 배포부터는 deploy.sh가 자동 처리 |
| 배포 시 SSH가 비밀번호를 물어봄 | 개인키가 기본 파일명이 아니라 ssh가 자동으로 못 찾음 | COSMOS_SSH_KEY로 키 경로를 명시(deploy.sh가 -i로 넘김).
서버의 authorized_keys에 공개키가 등록돼 있는지도 확인 |
기동 로그에 [db.init] 스키마 문 실행 실패 |
DB에 cosmos 스키마 또는 search_path가 준비 안 됨 |
§4 DB 운영 원칙의 사전 준비 SQL을 DB에 직접 적용 |
| 예산을 다 썼는데도 그룹장이 계속 쓸 수 있음 | 의도된 동작 | 한도를 잘못 설정했을 때 그룹장까지 잠기는 걸 막기 위한 예외. 필요하면 한도 자체를 조정 |
| watch 승인을 눌렀는데 아무 변화가 없어 보임 | 이미 같은 팀·감시대상 조합의 watch가 존재(유니크 제약으로 조용히 스킵) | 정상 동작. 화면에 "이미 등록돼 있어 새로 만들지 않았습니다" 안내가 뜸 — 기존 watch의 주기·프롬프트를 바꾸려면 DB에서 직접 확인 필요(현재 편집 UI 없음) |