Giting.
낮의 Giting

홈 · rust · cli · 카카오톡 · 개발도구

lazykatok 대표 이미지 9d050d1
분석 리포트실측 정보적용점원문 README

구조와 기능

lazykatok 은 로컬 우선(local-first) 카카오톡 터미널 클라이언트다. README 기준으로 실행 중인 카카오톡 macOS 앱의 로컬 DB를 읽어 실시간 대화 TUI를 띄우고, 키워드·BM25·의미 검색을 제공하며, 전송은 macOS 접근성(Accessibility) 경로로 실제 앱에 넣는다. 대화 데이터는 로컬 SQLCipher 아카이브에만 저장되고 네트워크로 나가지 않는다고 명시한다. Apple Silicon macOS 전용이다.

실측 기준 전체 86개 파일, 텍스트 25,517줄. 코드는 사실상 Rust 단일 언어에 쏠려 있고 나머지는 보조 스크립트 수준이다.

  • rs: 59파일, 23,005줄 (전체 텍스트 라인의 약 90%)
  • py: 2파일, 387줄
  • sh: 2파일, 91줄
  • toml: 1파일, 72줄
  • gitignore: 1파일, 57줄
  • rb: 1파일, 30줄
  • jsonl: 3파일, 11줄

가장 큰 파일은 src/commands.rs로 2,888줄이다. 전체 Rust 코드 23,005줄 중 이 한 파일이 차지하는 비중이 12%를 넘는다. 테스트 파일은 17개로, 86개 전체 파일 중 소수지만 초기 단계 프로젝트치고는 존재감이 있다.

의존성은 cargo 매니저 기준 23개로 집계됐다(meta.deps 필드 자체는 null). CI 워크플로는 2개 구성돼 있고, 라이선스는 MIT License(SPDX: MIT)다. 원격 태그는 0개로, 아직 정식 릴리스 버전을 끊지 않은 상태다.

하이라이트

에이전트 소비를 겨냥한 문서 패키징

meta.hasAgentDocs가 true이고 agentPackaging에서 rootDocs와 skillMd가 모두 true로 나온다. claudePlugin, codexPlugin, agentsDir은 false여서 완전한 플러그인 형태는 아니지만, 루트 문서와 SKILL.md를 갖춘 것만으로도 AI 코딩 에이전트가 이 리포를 다루기 쉽게 만들려는 의도가 읽힌다. 자체 CLI에 에이전트 친화적 문서를 얹으려는 프로젝트라면 문서 배치 방식을 참고할 만하다.

짧은 기간에 몰린 커밋 밀도

전체 커밋 64개 중 61개가 최근 90일 안에 발생했고, 첫 커밋이 2026-06-05다. 즉 관측 시점까지 약 3개월 사이에 이력의 대부분이 만들어졌다는 뜻이다. 기여자는 6명으로 집계됐고 github-actions[bot]도 포함돼 있어, 자동화된 커밋(예: 포맷팅, 의존성 업데이트)이 일부 섞여 있을 가능성이 있다.

주의점

비공식 클라이언트라는 사실이 가장 큰 리스크다. 카카오 공식 API가 아니라 로컬 DB 직접 읽기와 접근성 자동화로 동작하므로, 서비스 약관과의 충돌 소지와 카카오톡 앱 업데이트 시 파손 가능성을 감수해야 한다. 전체 디스크 접근·접근성이라는 강한 macOS 권한 둘을 요구한다는 점도 도입 전 인지가 필요하다. 다만 데이터가 네트워크로 나가지 않는 로컬 우선 설계는 이 계열 도구 중에서는 보수적인 선택이다.

릴리스 태그가 0개다. 특정 버전을 고정해 의존하거나 참고하려면 커밋 해시(예: 9d050d1)를 직접 지정해야 하고, 시맨틱 버저닝에 기반한 호환성 보장은 기대하기 어렵다.

issueResponse 표본이 0건이라 이슈 대응 속도를 판단할 데이터가 없다. openIssues는 1개로 적지만, 이 수치만으로 유지보수 대응력을 추정하기는 무리가 있다.

src/commands.rs 한 파일이 2,888줄로 전체 Rust 코드의 12% 이상을 차지한다. 파일 하나에 로직이 집중돼 있으면 이후 리팩터링이나 신규 기여자의 온보딩 비용이 커질 수 있다.

라이선스는 MIT로 재배포와 수정에 제약이 적다. 다만 스타 13, 포크 4라는 수치는 외부 검증이 아직 얕다는 뜻이므로, 프로덕션 도입보다는 코드와 문서 구조를 참고하는 수준의 활용이 현재로서는 적합하다.

실측 정보

헤드커밋
9d050d1
전체 커밋
64개 (최근 90일 61개)
기여자
6명 (github-actions[bot] 포함)
파일 / 텍스트 라인
86개 / 25,517줄
최대 파일
src/commands.rs, 2,888줄
테스트 파일
17개
라이선스 / 스타·포크
MIT / 13 stars, 4 forks, open issues 1

적용점

  • P1 · 비용 낮음릴리스 태그와 CHANGELOG가 없다면, 특정 커밋(9d050d1 등)을 고정해 참고하는 편이 안전하다
  • P2 · 비용 중간src/commands.rs 2,888줄은 전체 Rust 코드의 12% 이상을 차지한다. 이 파일부터 읽으면 프로젝트의 핵심 로직 구조가 빠르게 파악된다
  • P2 · 비용 낮음SKILL.md와 루트 문서로 에이전트 소비를 염두에 둔 패키징을 하고 있다. 유사한 에이전트 친화적 CLI를 설계할 때 문서 배치 참고용으로 볼 만하다
◇ 관망

첫 커밋이 2026-06-05로 관측 시점 기준 3개월 남짓이고, 전체 커밋 64개 중 61개가 최근 90일에 몰려 있어 아직 초기 활성 개발 단계다. remoteTagCount가 0이라 릴리스 태그가 없고 issueResponse 표본도 0이라 이슈 대응 속도를 판단할 근거가 없다. CI 워크플로 2개와 테스트 파일 17개는 최소한의 엔지니어링 규율을 보여주지만, 외부 검증(스타 13, 포크 4)이 아직 얕아 candidate로 올리기는 이르다. 개발 속도와 에이전트 패키징 방향을 지켜볼 가치는 있어 watch로 판정한다.

원문 README

아래는 changeroa/lazykatok 저장소의 README 원문입니다(GitHub 렌더, 수집 시점 기준). 저작권은 원 프로젝트에 있으며 원 저장소의 라이선스를 따릅니다. GitHub에서 보기

README 전문 펼치기

lazykatok

로컬 우선(local-first) 카카오톡 터미널 클라이언트. 방 목록을 최신순으로 골라 들어가는 실시간 대화 TUI, 로컬 암호화 아카이브, 키워드·BM25·의미 검색을 하나의 CLI로 제공합니다. Apple Silicon macOS 전용.

CI

특징

  • 대화 TUI (lazykatok chat) — 마지막 메시지가 최신인 방이 목록 맨 아래(입력 프롬프트 바로 위)에 1번으로 오는 방 선택, 로컬 시각 HH:MM + 보낸 사람 열 + 연속 메시지 · 묶음 + 날짜 구분선으로 정돈된 대화 뷰, readline식 입력 편집, 스크롤과 새 메시지 표식. 폴링과 전송이 백그라운드에서 돌아 입력은 항상 반응형입니다.
  • 답장 전송 — TUI에서 Enter로 카카오톡 앱에 실제 전송(macOS Accessibility 경로). 전송 중에도 입력 가능하고, 동시 전송은 안전을 위해 하나로 직렬화됩니다.
  • 로컬 검색 — 키워드 / BM25 / 임베딩 의미 검색. 대화 데이터는 전부 로컬 SQLCipher 아카이브에 저장되고 네트워크로 나가지 않습니다.

요구 사항

  • Apple Silicon macOS

  • 실행 중인 카카오톡 macOS 앱 (실시간 읽기·전송)

  • Rust 1.91+ (직접 빌드 시)

  • 터미널에 전체 디스크 접근 권한(카톡 DB 읽기)과 접근성 권한(전송) —

    시스템 설정 > 개인정보 보호 및 보안에서 부여하고 lazykatok doctor로 확인하세요.

설치

git clone https://github.com/changeroa/lazykatok.git
cd lazykatok
cargo build --release
# 바이너리: target/release/lazykatok

편하게 쓰려면 PATH에 둔 래퍼 하나면 충분합니다:

cat > ~/.local/bin/lazykatok <<'EOF'
#!/usr/bin/env bash
exec "$(dirname "$(git -C ~/src/lazykatok rev-parse --git-dir 2>/dev/null)")/target/release/lazykatok" "$@"
EOF
# 실제 클론 경로에 맞게 조정한 뒤 chmod +x

빠른 시작

lazykatok doctor                 # 권한·설정 상태 점검
lazykatok sync                   # 로컬 카톡 DB → 아카이브 동기화
lazykatok chat                   # 방 선택 → 대화 TUI 진입 (기본)
lazykatok chat-bg                # 카톡 창을 띄우지 않고 이미 열린 방에만 전송
lazykatok keyword 회식           # 키워드 검색 (--limit 5 등 옵션 전달)
lazykatok bm25 회식              # BM25 검색
lazykatok semantic "언제 만나기로 했지"  # 의미 검색

원본 CLI 그대로 쓰는 경우:

lazykatok watch --select --reply --accept-use-policy --source macos
lazykatok search keyword <질의> --json
lazykatok transcript --chat <chat_id> --from 2026-08-01 --to 2026-08-31 --out export.md

TUI 사용법

방 목록은 마지막 메시지 시각이 오래된 방부터 위에서 아래로 정렬되고 번호는 아래가 1번입니다 — 가장 최근에 활동한 방이 입력 프롬프트 바로 위에 1번으로 놓입니다. 시각을 알 수 없는 방은 맨 위에 이름 순으로 표시됩니다.

키 동작
Enter 현재 초안을 선택한 방으로 전송 (/send 메시지도 동일)
← → Home End, Ctrl-A/B/E/F 초안 커서 이동
Backspace / Delete, Ctrl-W/U/K 글자·단어·행 삭제
↑ ↓ / PgUp PgDn 대화 스크롤 / 페이지
Ctrl-C 또는 Ctrl-D 종료
/help, /quit 도움말, 종료
  • 메시지는 HH:MM 보낸사람 본문 형태로, 같은 사람이 5분 안에 보낸 연속 메시지는 ·로 묶여 표시됩니다. 날짜가 바뀌면 날짜 구분선이 나타납니다. 색상 구분 없이 기본 전경색으로 렌더링됩니다.
  • 새 메시지가 도착해도 작성 중인 초안과 커서는 그대로 유지됩니다. 과거 기록을 보는 중이면 화면은 흔들리지 않고 N new messages 표식만 표시됩니다.
  • 전송은 즉시 전송 중… 상태 줄과 함께 백그라운드로 실행되고, 결과는 sent reply (N chars) 또는 send failed: ... 줄로 알림됩니다. 전송 중 추가 Enter는 초안을 지키고 이전 전송 완료를 기다립니다.
  • paste는 텍스트 삽입일 뿐 절대 전송을 유발하지 않습니다. 붙여넣은 줄바꿈은 공백으로 변환됩니다.

전송 주의사항

전송은 되돌릴 수 없고 상대에게 실제로 도착합니다. --reply-no-open(래퍼의 chat-bg)은 카톡 창을 띄우거나 포커스를 가져가지 않고 이미 열려 있는 방에만 조용히 전송합니다. 기본 경로는 필요할 때만 잠깐 커튼을 띄우고 카톡을 앞으로 가져옵니다. 자세한 정책은 ACCEPTABLE_USE_POLICY.md와 DISCLAIMER.md를 참고하세요.

프라이버시

  • 모든 대화 데이터는 로컬(~/Library/Application Support/katok — 이전 이름의 디렉터리를 그대로 사용) SQLCipher 암호화 아카이브에 저장됩니다.
  • 텔레메트리가 없고, 대화 내용이 네트워크로 전송되지 않습니다. 의미 검색의 임베딩도 로컬 모델로 계산됩니다.
  • 이 저장소는 공개입니다. 실제 대화에서 유래한 어떤 값도 커밋되지 않으며, 테스트는 합성 fixture만 사용합니다 (scripts/verify_release_config.py의 프라이버시 오라클이 이를 계속 검사합니다).

개발

cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test --all-targets
python3 scripts/verify_release_config.py

라이선스

MIT. 이 프로젝트는 NomaDamas/katok을 포크해 리브랜딩한 개인 빌드입니다.

의견

판정에 대한 반론, 도입 경험, 정정 제보를 환영합니다. GitHub 계정으로 참여합니다.

이것도 재봤습니다

전체 리포트 →