~/우성현

← 모든 프로젝트

asahi — 동아리 AI 개발 에이전트

동아리 디스코드에 상주하며 부원들의 개발 작업을 돕는 AI 에이전트. 봇과 실행 워커를 나누고 권한·보안 경계를 둔 구조입니다

기간
2026.07 – 현재
역할
개발·운영 (동아리 창립 회장) · AI 코딩 에이전트 협업
저장소
semicollon-club/asahi
스택
  • TypeScript
  • Node.js
  • Claude Agent SDK
  • MCP
  • discord.js
  • WebSocket
  • PostgreSQL
  • Vitest

핵심 수치

2026-09-30 기준 · 기여·릴리스 수치는 매일 자동 갱신

문제

부원이 디스코드에서 AI 에이전트에게 개발 작업을 시키면, 그 메시지가 동아리 공용 미니PC의 파일·셸 작업으로 이어집니다. 부원은 디스코드만으로 동아리 저장소를 내려받고 브랜치를 올리고 PR을 낼 수 있습니다. 채널의 메시지가 공용 기계의 명령 실행으로 이어지는 구조이므로, 자격증명을 어디에 두고 누가 어떤 도구를 쓸 수 있게 할지를 설계로 정해야 했습니다.

접근

  • 디스코드 연결·DB·모델 자격증명은 봇이 갖고, 파일·셸 작업은 워커가 대신 실행합니다. 워커는 봇이 여는 WebSocket 허브에 아웃바운드로 접속하며, 보관하는 자격증명은 자기 토큰 하나뿐입니다(DB 접속 정보도 Claude 구독 토큰도 갖지 않습니다). 봇은 이 토큰을 sha256 해시로만 저장하고 접속마다 대조합니다.
  • 권한을 좁히는 장치를 겹쳐 뒀습니다. 파일 도구는 봇의 허용 폴더 목록과 워커의 작업 폴더 검사, 두 번을 통과해야 합니다. DB 조회는 정적 SQL 검사를 거친 뒤 Postgres 읽기 전용 트랜잭션에서 실행합니다. GitHub 작업에는 봇이 발급하는 최대 1시간짜리 GitHub App 토큰을 쓰고, PR 생성·발행 토큰은 저장소 하나로 좁혔습니다.
  • MCP로 GitHub·DB 읽기 조회, 파일 전송, 브라우저 같은 도구를 붙였습니다.
  • 미니PC에서 도는 Claude Code 세션의 모델 호출은 봇의 인증 프록시를 거치게 했습니다. 프록시는 작업 토큰을 검증하고, 요청의 모델을 고정하고, 사용량을 기록하게 했습니다(기록이 남지 않던 결함은 PR #115에서 고쳤고, 실서버 확인은 PR 시점에 남아 있었습니다). 부원별 사용 한도(시간당 턴 수)는 봇이 대화 턴을 시작하기 전에 확인합니다.
  • 중요한 결정은 ADR로, 알려진 위험은 위험 등록부로 관리합니다.

결과

  • 2026-09-22 기준 최근 30일(2026-08-23부터 09-22까지) 동안 부원 5명이 모두 사용했습니다. 근거 문서가 그날 집계한 값입니다.
  • main 브랜치에 병합된 PR 수와 그중 제 계정으로 올린 수는 포트폴리오 사이트의 핵심 수치가 매일 자동으로 갱신합니다. main을 production에 반영하는 PR 35건은 이 수에 넣지 않았습니다. agent 코드의 타입 검사와 단위 테스트는 GitHub Actions에서 Ubuntu와 Windows 양쪽으로 돕니다.
  • 사용량 기록(llm_usage)이 한 번도 남지 않던 결함을 진단해 고쳤습니다(PR #115, 2026-09-22). 성공한 INSERT가 0건인데 활동이 많았던 날의 Postgres 로그에도 INSERT 오류가 없어서 실패가 아니라 시도 자체가 없었다고 좁혔고, 압축 응답과 비스트리밍 JSON 응답 두 경로를 고쳤습니다. 회귀 테스트를 더했고, PR에는 수정 전에 실패하는 것을 먼저 확인했다고 적혀 있습니다. 두 경로 중 실제로 어느 쪽이 얼마나 영향을 줬는지는 미니PC 밖에서는 확정할 수 없었고, 실서버 확인은 배포 뒤로 남겨 둔다고 PR에 적었습니다.

주요 결정

  • 워커를 두 번째 에이전트에서 얇은 실행기로 바꿨습니다. 워커가 직접 DB를 읽고 모델 SDK를 호출하던 구조에서 DB 접근과 모델 호출을 없애고, 봇이 요청한 도구 호출 하나하나만 대신 실행하게 했습니다. 워커에 필요한 자격증명은 DB 접속 정보와 Claude 구독 토큰에서 토큰 하나로 줄었습니다. 대신 원격 파일 도구가 SDK 내장 도구만큼 정교하지 못한 점은 감수했습니다(ADR 0006).
  • 부원 사이 격리를 만들지 않기로 했습니다. 완전하지 않은 격리는 운영자가 확인을 멈추게 하고 사용자를 안심시켜 없는 것보다 나쁠 수 있다는 판단이었습니다. 대신 대화와 작업이 공용 PC에 기록으로 남아 다른 부원이 볼 수 있다는 사실을 도움말과 안내 문구에 적고, 소유자가 아닌 사용자의 DM은 받지 않게 했습니다(ADR 0009).
  • 봇을 Railway 클라우드에서 동아리 미니PC로 옮겼습니다(2026-09-05 전환, 이후 Railway 서비스 삭제).

한계와 다음 단계

  • 사용자는 동아리 안의 소수(소유자 1명, 부원 5명)이고, 운영이 한 사람에게 집중되어 있습니다. main에 병합된 PR 중 제 계정 몫과 다른 계정 몫은 포트폴리오 사이트의 핵심 수치가 매일 자동으로 갱신합니다. production 반영은 운영자만 합니다.
  • 셸 명령은 경로로 막을 수 없어서, 워커를 돌리는 OS 계정의 권한이 마지막 경계입니다. 셸의 git 작업용 GitHub 토큰은 contents 쓰기 권한 하나로 좁혔지만 조직의 모든 저장소가 대상입니다(위험 등록부 §5, §9).

AI 협업 방식

방향과 판단은 직접 했고, 구현과 문서 작업은 AI 코딩 에이전트(Claude Code)와 함께 했습니다. 모든 브랜치의 커밋 615개(머지 커밋 125개 포함) 중 423개에 Claude 공동 작성 표기가 있습니다.