
Monolog는 할 일을 각각 JSON 파일로 저장하고 Git으로 동기화하는 개인용 터미널 백로그다. 클라우드 계정이나 구독 없이 자신의 저장소에 데이터를 보관하며, 키보드 중심의 대화형 화면과 명령줄에서 작업을 추가·검색·완료할 수 있다. 제작자는 저장소를 공개하며 macOS용 Homebrew 설치와 Go 설치를 안내했다.
brew install maksmas/tap/monolog # macOS
go install github.com/maksmas/monolog@latest # anywhere with Go
Homebrew는 macOS 전용 cask다. 사전 빌드 바이너리는 GitHub Releases에서 macOS와 Linux용 amd64·arm64 빌드를 받을 수 있다. 소스에서 설치하려면 Go 1.26 이상이 필요하다. 저장소와 전체 사용 설명은 Monolog GitHub 저장소를 참조하면 된다.
저장 방식과 시작
monolog init은 기본 데이터 디렉터리인 ~/.monolog에 저장소를 만든다. --remote <url>을 지정하면 Git 원격 저장소를 설정할 수 있다. 각 작업은 <repo>/.monolog/tasks/<ULID>.json에 저장되며, ULID는 시간순 정렬이 가능하고 전역적으로 고유하다. 명령은 ID 앞부분만으로 작업을 지정할 수 있다.
monolog init # create a new monolog repo at ~/.monolog
monolog add "Review PR #42" # add a task (defaults to today)
monolog add "Write tests" -s week # schedule for this week
monolog ls # list today's open tasks
monolog done 01J5K # mark done by ID prefix
monolog done rp # ...or by title initials ("Review PR #42")
monolog sync # push/pull with a git remote
monolog # launch the interactive TUI
각 작업 변경은 자동으로 Git 커밋된다. 기본 설정에서는 커밋을 원격에 자동 푸시한다. 서로 다른 작업 파일을 두 기기에서 수정하면 rebase 과정에서 충돌하지 않는다는 것이 제작자의 설명이다. TUI는 백그라운드에서 푸시하고, CLI는 성공 문구를 출력한 뒤 푸시하므로 네트워크 상태가 나쁘면 monolog add 종료가 몇 초 늦어질 수 있다. 푸시 성공은 표시하지 않으며, 네트워크가 끊겨도 변경 작업 자체는 실패 처리하지 않는다. 커밋은 로컬에 남고 다음 푸시나 TUI의 s 동기화 때 전송된다.
원격이 앞서 있어 푸시가 거부되면 pull --rebase --autostash를 시도하고 한 번 재시도한다. 저장소에 원격이 없거나, detached HEAD이거나, origin 없이 원격이 여러 개면 푸시를 건너뛴다. 직접 원격을 추가한 저장소는 첫 푸시 때 upstream을 설정하며, 원격에 이미 README 등이 있어 거부되면 rebase 후 재시도한다. 저장소가 rebase 중이면 자동 푸시를 멈추고 수동 해결을 요구한다.
명령줄과 작업 관리
monolog add <title>은 작업을 추가한다. -s, --schedule은 today(기본값), tomorrow, week, month, someday 또는 날짜를 받는다. 기본 날짜 표시는 DD-MM-YYYY이며 예전 형식인 YYYY-MM-DD도 입력할 수 있다. -t, --tags는 쉼표로 구분한 태그, -b, --body는 본문, --recur는 반복 규칙을 지정한다. 제목이 tag: ... 형식이고 같은 태그가 기존 작업에 있으면 해당 태그를 자동으로 붙인다. 예를 들어 jean 태그가 이미 있다면 monolog add "jean: create integration"은 제목은 그대로 둔 채 jean을 추가한다. --tags에도 같은 태그를 지정했다면 중복으로 만들지 않는다.
monolog ls는 기본적으로 오늘의 미완료 작업을 보여준다. -a, --all은 모든 일정의 미완료 작업, -s, --schedule과 -t, --tag는 일정과 태그별 필터, -d, --done은 완료 작업, --active는 활성 작업, -f, --full은 본문과 메타데이터를 포함한 상세 출력을 선택한다. 표준 출력이 터미널이면 상세 출력은 $PAGER로 전달될 수 있다. --json은 JSON 배열로 출력한다. 목록의 날짜는 최근 항목은 5m, 3h, 2d처럼 상대 시간으로, 같은 해의 오래된 항목은 DD-MM, 다른 해 항목은 DD-MM-YY로 축약한다. 완료 작업에는 created→done이 표시되고, 활성 작업은 앞에 *가 붙는다.
monolog search <query>는 제목과 본문을 검색해 제목을 자르지 않은 결과를 출력한다. 기본 최대 결과는 10개이며 -n, --limit으로 바꿀 수 있다. -d, --done은 완료 작업을 포함하고 --json은 JSON 배열을 출력한다. 여러 단어는 따옴표 없이 입력해도 공백으로 합쳐진다. 한 단어 검색은 오타에 가까운 표현과 약어를 포함하는 퍼지 검색이며 제목 일치가 본문 일치보다 우선한다. 여러 단어 검색은 작업이 포함한 검색어 수로 순위를 정하고 하나도 포함하지 않은 작업은 제외한다. 동률이면 제목 일치 수, 그다음 생성일 최신순으로 정렬한다. 이때 제목 가중치는 같은 검색어 수 단계 안에서만 적용된다. 따라서 본문에서 세 단어가 일치하는 작업이 제목에서 두 단어가 일치하는 작업보다 위에 올 수 있다.
여러 단어 검색은 순서에 관계없이 같은 결과를 내며, 단어를 더하면 결과 범위가 좁아진다. 다만 AND 조건은 아니어서 세 단어 중 두 단어만 맞는 작업도 세 단어 모두 맞는 작업 아래에 남는다. 검색은 대소문자를 구분하지 않는 부분 문자열 방식이다. week는 weekly를 찾지만 scheduling은 schedule을 찾지 못하므로 짧은 어간을 쓰는 편이 맞다. 검색어는 공백으로만 나누므로 telegram,처럼 단어에 붙은 문장부호도 검색에 포함된다. 한 글자 단어는 무시하며, 검색어가 한 글자뿐이면 전체 구문 퍼지 검색으로 돌아간다. 빈 검색어는 오류다.
결과 행은 <status> <12-char ID> <title> <schedule> <tags> 형식이다. x는 완료, *는 활성 상태다. ULID는 약 256ms 안에 만들어진 ID끼리 앞 8글자가 같을 수 있어 검색 결과에서는 12글자를 표시한다. 제목 열은 최대 60칸까지 결과 중 가장 긴 제목에 맞춘다. 결과가 없으면 No matches.를 출력한다. ls -a는 모든 일정의 미완료 작업을 뜻하고 search -d는 완료 작업 포함을 뜻한다. CLI와 TUI의 / 검색은 한 단어일 때 같은 순위 산정기를 사용해 결과 순서가 같다. 여러 단어에서는 CLI만 일치 단어 수를 세며, TUI는 입력을 다시 고쳐 가며 결과를 좁히는 사용 방식에 맞춰 순서가 있는 퍼지 검색을 유지한다.
monolog done <id-prefix>는 작업을 완료한다. monolog edit <id-prefix>는 --title, --body, --schedule, --tags, --active=true|false, --recur로 수정하며 플래그를 하나 이상 지정해야 한다. 반복 규칙을 지울 때는 --recur ""을 쓴다. monolog rm <id-prefix>는 작업을 영구 삭제한다. monolog mv <id-prefix>는 같은 일정 그룹에서 작업을 옮기며 --top, --bottom, --before <id>, --after <id> 중 하나만 지정한다. monolog note <id-prefix> <text>는 시간표시가 붙은 메모를 본문에 추가하며 빈 텍스트는 거부한다. 메모 구분선은 --- DD-MM-YYYY HH:MM:SS --- 형식이다. monolog show <id-prefix>는 제목, ID, 상태, 일정, 설정된 경우 반복 규칙, 태그, 날짜, 메모 수와 본문을 출력한다. monolog log는 최근 7일 동안 완료한 작업을 보여준다. monolog sync는 로컬 변경을 커밋하고 rebase로 pull한 뒤 push하며, 원격이 없으면 경고한다.
작업 ID를 받는 명령은 먼저 ULID 앞부분을 찾는다. 일치하는 ID가 없고 입력이 두 글자 이상이면 미완료 작업 제목의 각 단어 첫 글자로도 검색한다. 예를 들어 monolog done flb와 monolog done fl은 제목 Fix login bug를 가리킬 수 있고 대소문자는 구분하지 않는다. 여러 작업이 같은 앞글자와 일치하면 충돌을 알리고 해당 제목들을 나열한다.
반복 작업과 TUI
일정은 today, tomorrow, week, month, someday 또는 특정 날짜다. 각 일정 구간은 TUI 탭과 CLI 기본 필터가 된다. 태그는 쉼표로 구분해 붙이며 예약 태그 active는 현재 작업 중인 작업을 표시한다. 활성 작업은 TUI에서 초록색으로 보이고 별도 패널에 나타난다. 완료 처리하면 자동으로 비활성화되며 --tags로 태그를 편집해도 활성 상태는 유지된다.
반복 규칙은 monthly:N, weekly:<day>, workdays, days:N 네 가지다. monthly:1은 매월 1일, monthly:31은 짧은 달에 월말로 조정된다(2월은 28일 또는 29일). 주간 규칙은 weekly:mon, weekly:Monday, weekly:1처럼 요일의 세 글자·전체 이름·숫자(Mon=1부터 Sun=7)를 대소문자 구분 없이 받는다. 저장할 때는 weekly:Monday와 weekly:1을 모두 weekly:mon으로 정규화한다. workdays는 월요일부터 금요일까지, days:3은 완료 후 3일 뒤를 뜻한다.
monolog add "pay rent" --recur monthly:1 # 1st of every month
monolog add "standup" --recur workdays # every weekday
monolog done <id> # completes this occurrence AND spawns the next
monolog edit <id> --recur "" # stop the chain (clear the rule)
반복 작업을 완료하면 새 ID를 가진 다음 작업을 만든다. 제목·본문·태그(단, active 제외)와 반복 규칙은 이어받고 일정은 다음 발생 날짜로 정한다. 새 작업에는 Spawned from <old-id>, 완료된 작업에는 Spawned follow-up: <new-id> (scheduled <date>) 메모를 붙인다. 두 파일은 done: <title> (recurring, next <date>) 메시지 하나로 함께 커밋된다. 반복을 멈추려면 완료 전에 --recur ""로 규칙을 지우거나 TUI YAML 편집기에서 recurrence: 줄을 제거한다. 작업을 삭제해도 반복이 멈춘다.
인자 없이 monolog를 실행하면 대화형 TUI가 열린다. 기본 탭은 [Today] [Tomorrow] [Week] [Month] [Someday] [Done]이며 --tags 또는 -T로 태그 탭을 열 수 있다. 화살표 키나 Tab으로 탭을 바꾸고 1–6으로 탭을 선택한다. 위아래 화살표로 목록을 이동하며 Enter는 상세·메모 패널을 여닫는다. c는 제목·태그·반복 규칙 입력 모달, d는 완료, a는 활성 상태 전환, r은 일정 변경, t는 태그 편집, e는 $EDITOR에서 YAML로 편집하는 키다. v는 일정 보기와 태그 보기 전환, /는 퍼지 검색, x는 확인 후 삭제, h는 도움말, q는 종료, ,는 날짜 형식과 테마 설정을 연다.
r은 기본 선택지 1–5 또는 6번 사용자 지정 날짜를 제공한다. 사용자 지정 날짜는 설정 형식이나 상대 표기 Nd, Nw, Nm을 받는다. 예를 들어 3d, 2w, 1m은 오늘부터 각각 3일·2주·1개월 뒤다. m은 작업을 잡아 순서를 바꾸는 키다. 위아래로 재정렬하고 좌우로 탭 사이를 옮길 수 있으며 g/G는 맨 위·맨 아래로 이동한다. 잡은 상태에서 +d/e/r/t/a/c/x/s로 작업 동작을 수행한다. u 또는 Ctrl+z는 git revert 기반 다단계 실행 취소, Ctrl+y는 다시 실행이다.
c 모달의 반복 입력란은 문법 안내와 자동완성을 제공한다. Tab은 강조된 제안을 입력란에 반영하고 Enter는 모달을 제출하며 Esc는 제안 목록을 닫는다. e의 YAML에는 반복 규칙을 설정하거나 지울 수 있는 recurrence: 필드와 문법 안내 주석이 포함된다. o는 설정된 경우 현재 작업을 새 터미널 탭의 Claude Code로 열고 활성화한다. s는 전체 Git 동기화를 수행한다. 자동 푸시가 변경 때마다 이뤄지므로 주로 다른 곳에서 생긴 변경을 가져올 때 쓰며, 이메일 연동을 켰다면 이메일 동기화도 병렬 실행한다. 이때 하단 안내는 full sync (git+email)로 바뀐다.
TUI는 활성 작업을 목록에서 초록색으로 표시하고 탭 바 위 전용 패널에도 보여준다. 활성 작업이 없으면 패널을 숨긴다. Raycast 캡처, 다른 터미널의 monolog add, 외부 git pull 등 다른 프로세스가 저장소를 바꾸면 실행 중인 TUI가 자동으로 새로고침한다. MONOLOG_NO_WATCH=1로 파일 감시를 끌 수 있다.
설정과 테마
환경 변수와 선택적인 config.json에서 설정을 읽는다. MONOLOG_DIR은 데이터 디렉터리(기본 ~/.monolog), MONOLOG_THEME는 TUI 테마(default, dracula 또는 사용자 테마 이름), MONOLOG_NO_LINKS=1은 OSC 8 클릭 가능 URL, MONOLOG_NO_WATCH=1은 외부 변경 감시, MONOLOG_NO_AUTOPUSH=1은 변경 시 자동 푸시를 끈다. 테마 환경 변수는 설정 파일보다 우선한다.
지속 설정은 <MONOLOG_DIR>/.monolog/config.json에 둔다. TUI 설정 모달은 theme과 date_format을 쓴다. email과 telegram 블록은 직접 편집하거나 각각의 인증·실행 절차에서 작성하며, launch 블록은 직접 편집해야 한다. 저장할 때 알 수 없는 키는 보존한다. auto_push는 기본값이 true이며 키가 없어도 자동 푸시를 켠다. false로 설정하면 커밋은 로컬에 남는다. MONOLOG_NO_AUTOPUSH=1은 한 번의 실행을 위한 차단 스위치이며, 설정 파일이 false인 푸시를 다시 켜지는 못한다.
{
"theme": "default",
"date_format": "02-01-2006",
"auto_push": true
}
설정 모달이 커밋하지 않는 config.json 등 .monolog/tasks/ 바깥의 미커밋 변경은 rebase 대체 경로에서 임시 저장된다. 같은 설정을 두 기기에서 바꿔 적용 충돌이 나면 로컬 파일을 유지하고 autostash conflict: kept your uncommitted .monolog/config.json; the incoming version is in HEAD를 표시한다. 원격에서 들어온 버전은 커밋돼 있고 git checkout HEAD -- .monolog/config.json으로 가져올 수 있다. 로컬에서 삭제한 파일을 원격이 수정한 경우처럼 로컬 변경을 되살릴 수 없으면 kept 대신 could NOT keep your local change라고 알린다. 어느 경우든 autostash 항목은 사전 rebase 복사본으로 남는다. 이 설정 충돌이 있어도 작업 파일 푸시는 계속된다.
커밋되지 않은 작업 파일이 발견되면 다른 프로세스가 쓰는 중일 수 있어 30초 동안 rebase 대체 경로를 미루며 파일 이름과 함께 rebase deferred while a task write is in flight를 알린다. 다음 푸시나 monolog sync가 파일을 커밋하고 전송한다. 잘린 파일처럼 작업으로 읽을 수 없는 파일은 다른 기기에서 monolog ls까지 실패하게 할 수 있으므로 푸시하지 않고 그대로 둔다.
기본 제공 테마는 default와 dracula다. 사용자가 만든 테마는 <MONOLOG_DIR>/.monolog/themes/*.json에서 시작 시 읽으며 파일명에서 .json을 뺀 이름이 TUI 테마 선택지로 표시된다. 새 저장소에서 TUI를 처음 열면 기본 테마 전체를 담은 themes/example.json을 만든다. 복사해 색을 바꾸고 재시작해 적용한다.
cp ~/.monolog/.monolog/themes/example.json ~/.monolog/.monolog/themes/mytheme.json
# edit mytheme.json — change any of the 19 color roles
# then select it from the TUI settings modal (,) or set
# "theme": "mytheme" in <MONOLOG_DIR>/.monolog/config.json
테마 파일은 각 색상 역할에 light와 dark 값을 하나씩 둔 JSON이다. 19개 필드가 모두 필요하며 값은 #ff79c6 같은 16진 색상이나 "240" 같은 ANSI 코드다. 파일 감시는 없으므로 수정 후 재시작해야 한다. 필드 누락, 잘못된 JSON, 빈 색상 값이 있으면 stderr에 경고를 내고 해당 파일을 건너뛰며, TUI는 정상적으로 읽은 테마를 계속 사용한다. 내장 테마와 같은 default.json, dracula.json은 거부한다. 설정한 테마 파일이 사라지면 설정 파일을 고치지 않은 채 기본 테마로 돌아가고 상태 표시줄에 theme "<name>" not found, using default를 보여준다. 파일을 복원하면 다시 선택된다.
Gmail 가져오기
이메일 연동은 선택 기능이다. monolog email auth를 실행하기 전에는 시작 시 동기화나 TUI s 동작의 변경, 추가 Git 활동이 없다. 사용자는 자신의 Google Cloud OAuth 인증 정보를 준비한다. Google Cloud에서 프로젝트를 만들고 Gmail API를 켠 뒤 OAuth 동의 화면을 설정하고, Desktop app 유형의 OAuth 2.0 자격 증명을 만든다. 자격 증명 JSON을 기본 ~/.config/monolog/gmail_credentials.json 또는 email.client_secrets_path에 지정한 경로에 둔 다음 monolog email auth를 실행한다. 브라우저에서 동의하면 갱신 토큰을 ~/.config/monolog/gmail_token.json에 권한 모드 0600으로 저장하고 설정의 enabled를 자동으로 켠다.
요청 범위는 gmail.modify다. 라벨이 붙은 메시지를 찾고 메타데이터와 발췌문을 읽으며 INBOX 라벨을 제거할 수 있는 최소 범위라고 설명한다. Monolog는 메일을 보내거나 전체 본문을 읽거나 다른 편지함을 건드릴 수 없다. 토큰과 자격 증명은 작업 Git 저장소 밖의 $XDG_CONFIG_HOME/monolog/(기본 ~/.config/monolog/)에 두므로 기기 간 동기화 때 OAuth 비밀 정보가 커밋되지 않는다.
선택적인 email 설정의 기본값은 enabled=false, label="monolog", sync_interval_minutes=5, max_per_sync=100, client_secrets_path=$XDG_CONFIG_HOME/monolog/gmail_credentials.json이다. monolog email auth가 처음 설정 블록을 작성한다. 라벨, 간격, 경로를 바꾸려면 config.json을 직접 편집한다. TUI 설정 모달은 이메일 설정을 아직 제공하지 않는다.
Gmail에서 monolog 또는 설정한 라벨을 만들고 가져올 메일에 붙인다. monolog email sync 또는 TUI의 s로 동기화할 수 있다. TUI는 시작 때 한 번 동기화하고 이후 설정한 분 간격으로 다시 동기화한다. 제목에서는 연달아 붙은 Re:, Fwd:, Fw: 접두사를 대소문자 구분 없이 제거하고, 제목이 비었으면 (no subject)를 쓴다. 본문에는 From: <name>, https://mail.google.com/mail/#all/<msg-id>, 발췌문을 넣는다. URL에서 /u/0/을 빼 현재 로그인한 Google 계정과 무관하게 열리게 한다. 발췌문은 HTML 엔티티를 풀고 최대 200자로 자르며, 잘린 경우에만 …를 붙인다. 태그는 ["email"], 일정은 today, 출처는 "gmail", 출처 ID는 Gmail 메시지 ID다. active 태그는 자동으로 붙이지 않는다.
한 번의 동기화에서 가져온 작업은 한 번에 디스크에 쓰고 email: imported N task(s) (label=<label>) 메시지로 커밋한다. 개별 작업 쓰기에 실패해도 stderr에 경고하고 성공한 작업은 묶어 커밋한다. 중복 검사는 동기화 때 기존 작업 중 Source=="gmail"인 열린 작업과 완료 작업의 SourceID를 살펴 수행한다. 완료 처리되어 Gmail에서 보관된 메일은 라벨이 남아 있어도 다시 가져오지 않는다. Monolog에서 작업을 삭제하고 Gmail에서 보관하지 않았다면 다음 동기화 때 다시 가져온다. 새 메일이 max_per_sync보다 많으면 최신 순서로 처음 N개만 가져오고 나머지는 다음 실행으로 미룬다. 이 상한 초과는 오류나 경고를 내지 않는다.
Gmail에서 가져온 작업을 완료하면 users.messages.modify를 호출해 INBOX 라벨을 제거한다. 가져올 때 사용한 라벨은 남기므로 보관만 하고 라벨은 제거하지 않는다. CLI가 불안정한 네트워크에서 멈추지 않도록 호출 제한 시간은 5초다. 보관 실패는 작업 완료를 되돌리지 않고 오류를 출력한다. TUI는 상태 표시줄에 email archived 또는 archive failed: <err>를 잠시 표시하고 동기화 중에는 통계 표시줄에 ↻를 보인다. 동기화된 갱신 토큰은 토큰 파일에 기록돼 다른 CLI 실행과 TUI가 재인증 없이 사용할 수 있다. 갱신 토큰이 폐기되면 monolog email status에 오류가 나오며 다시 monolog email auth를 실행해야 한다.
monolog email status는 인증 상태, 토큰 만료 또는 미인증 상태, 활성화 여부, 라벨, 동기화 간격, 동기화당 최대 개수, 자격 증명·토큰 경로를 출력한다.
Telegram 봇
선택 기능인 Telegram 봇은 긴 폴링으로 휴대전화에서 작업을 추가하고 찾아 완료하게 한다. 봇도 작업 Git 저장소를 복제해 CLI와 같은 저장소·Git 경로를 이용한다. config.json에 telegram 블록을 설정하고 monolog telegram serve를 실행하기 전에는 토큰이나 리스너, 추가 Git 활동이 없다.
Telegram에서 @BotFather에게 /newbot을 보내 봇을 만들고 API 토큰을 받는다. @userinfobot에서 숫자 사용자 ID를 확인한다. 허용 목록은 사용자 이름이 아니라 ID를 사용한다. 설정 블록에는 enabled, allowed_user_ids, pull_interval_seconds, browse_limit, daily_digest_time, daily_digest_tz를 둘 수 있다. 기본값은 enabled=false, 허용 ID 없음(모든 사용자를 거부), pull 간격 30초, 목록 상한 20개, 일일 요약 끔이다. 예시로 daily_digest_time은 08:00, 시간대는 Europe/Riga를 쓸 수 있다.
일일 요약은 설정한 시각에 전날 이후 오늘 일정으로 넘어온 작업만 나열한다. 작업은 미완료 상태이고 오늘 날짜로 일정이 잡혔으며 생성 날짜는 이전 UTC 날짜여야 한다. 모든 허용 사용자에게 보낸다. 시간대에는 IANA 이름을 쓰며 발송 시각만 결정한다. 빈 값은 호스트의 현지 시간대를 쓰는데 systemd 호스트에서는 UTC일 수 있다. 여기서 오늘은 /today와 마찬가지로 UTC 날짜 기준이다. 정해진 시각이 지난 뒤 봇을 재시작하면 당일 요약을 따라잡아 보내지 않고 다음 날까지 기다린다. 잘못된 시각이나 시간대는 경고와 함께 요약만 비활성화하며 봇 자체를 막지 않는다.
pull_interval_seconds는 대기 중 안전장치다. /today, /week, /active, /all과 인라인 버튼처럼 기존 상태를 읽거나 바꾸는 동작은 먼저 pull한다. pull은 티커와 공유하는 시계 기준으로 5초에 한 번으로 제한된다. 따라서 노트북에서 추가한 작업은 설정 간격과 관계없이 몇 초 안에 휴대전화에 나타날 수 있고, 간격을 줄여도 얻는 이익은 적다.
일반 텍스트 메시지는 오늘 일정의 새 작업이 된다. 첫 줄의 해시태그는 태그로 처리하고(buy milk #shopping #urgent), 첫 줄 앞부분의 tagname: ...은 기존 태그를 붙인다. 여러 줄 메시지에서는 첫 줄이 제목이고 나머지는 본문이며 본문 안 해시태그는 그대로 둔다. 새 작업에 붙는 요약 카드에는 완료, 활성 전환, 상세 보기 버튼이 있다. 반복 작업을 완료하면 다음 작업을 만들고 완료 답글에 ↻ next: <date>를 표시한다. 상세 보기에서 본문·메타데이터를 펼칠 수 있고 버튼은 Collapse로 바뀐다. 작업 요약 메시지에 답글을 달면 시간표시 메모를 추가한다. 이때도 CLI와 같은 ULID 앞부분 또는 제목 첫 글자 검색을 쓰며 모호한 입력은 충돌 오류를 낸다.
/today는 오늘 일정, /week는 내일보다 뒤에서 7일 뒤까지의 주간 일정, /active는 활성 작업, /all은 모든 미완료 작업을 보여준다. /all은 browse_limit까지만 표시하고 초과하면 +N more — open laptop을 덧붙인다. /help와 /start는 사용법 안내를 보여준다.
allowed_user_ids만이 인증 수단이다. 목록에 없는 ID의 업데이트는 답장이나 로그 없이 조용히 버려 봇의 존재도 드러내지 않는다. 비허용 사용자의 콜백에는 Telegram의 로딩 표시를 끝내기 위한 빈 AnswerCallback만 보내고 메시지나 편집은 하지 않는다. 허용 목록은 시작할 때 한 번 읽으므로 config.json을 바꿔 pull해도 실행 중인 봇에는 적용되지 않는다. 설정을 바꾸려면 봇을 재시작해야 한다.
작업 추가, 완료, 활성 전환, 답글 메모를 포함한 모든 쓰기 뒤에는 커밋·rebase pull·push 동기화를 한다. rebase에 실패하면 봇은 읽기 전용 모드로 바뀐다. 이후 쓰기에는 ⚠️ sync conflict, change not saved — resolve on laptop을 답하고 조회에는 ⚠️ read-only — sync conflict pending 배너를 붙인다. 백그라운드 티커나 명령 실행 전 pull이 성공하면 자동으로 회복되며, 노트북에서 충돌을 해결한 뒤 봇을 다시 시작해도 된다.
토큰은 비어 있지 않은 --token <value>가 우선이고, 없으면 MONOLOG_TELEGRAM_TOKEN 환경 변수를 쓴다. 장기 실행 배포에서는 ps aux를 볼 수 있는 사용자가 플래그 값을 확인할 수 있으므로 환경 변수를 권장한다. 토큰이 비어 있으면 시작 단계에서 실패하도록 해 잘못된 EnvironmentFile= 설정이 401을 반복하며 조용히 대기하지 않게 한다.
봇은 systemd가 있는 상시 실행 Linux 기기에서 운영할 수 있다. 오래된 노트북, 미니 PC, Pi, VPS, EC2 t4g.nano 등이 예시다. Telegram을 긴 폴링하고 Git으로는 외부 방향으로만 연결하므로 인바운드 연결이 필요 없으며 가정용 NAT 뒤 기기도 쓸 수 있다. 호스트, 봇 사용자, SSH 배포 키, systemd 단위, 환경 파일과 점검 절차는 배포 안내에 있다.
make build-bot-linux-arm64 # cross-compile to dist/monolog-linux-arm64
make deploy-bot DEPLOY_HOST=<user>@<host> # scp + restart systemd unit
BOT_ARCH는 대상 아키텍처를 선택하며 Pi·Graviton은 arm64, x86 기기는 amd64를 쓴다. EC2_HOST는 DEPLOY_HOST의 별칭으로 계속 지원한다. 재시작 중 봇의 긴 폴링 위치는 잠시 끊기지만 Telegram이 update_id 기준으로 업데이트를 대기시키므로 누락되지 않는다.
빠른 입력과 Claude Code
macOS에서는 Raycast 스크립트 명령과 북마클릿으로 브라우저 페이지나 앱에서 선택한 텍스트를 inbox 태그와 오늘 일정이 붙은 작업으로 빠르게 저장할 수 있다. 북마클릿은 선택 텍스트 또는 페이지 제목을 작업 제목으로, 선택 문구와 #:~:text= 조각이 포함된 URL을 메모로 채운다. 이 URL을 다시 열면 해당 문구로 이동한다. 설정 방법은 Raycast 안내에 있다. 기능은 monolog add를 호출할 뿐 별도 데몬이나 바이너리를 실행하지 않는다.
저장소에는 Claude Code가 백로그에 일을 추가하고 기존 작업을 검색하는 스킬도 포함된다. 현재 세션에서 처리하지 않을 기술 부채나 미해결 버그 등 후속 일을 채팅에서 흘려보내는 대신 작업으로 기록하도록 하는 기능이다. 사용자가 요청하지 않은 추가 작업은 다음처럼 claude 태그와 someday 일정으로 격리한다.
monolog add "<title>" --tags claude -s someday --body "<where + why>"
스킬이 추가하는 모든 작업에는 출처 표시인 claude 태그가 붙고, someday는 오늘·주간 보기에서 제외한다. monolog ls --tag claude -s someday로 확인해 필요한 작업은 일정을 바꾸고 나머지는 monolog rm으로 지울 수 있다. 기록 전에 monolog search를 실행해 비슷한 작업이 있으면 새 작업 대신 monolog note를 추가한다. 설치와 규칙은 Claude Code 스킬 안내에 있다.
TUI의 o는 현재 작업을 Claude Code로 넘길 수 있다. 기본 예시는 kitty 새 탭을 열고, 작업 태그가 가리키는 디렉터리에서 다음 프롬프트로 Claude를 시작하는 방식이다.
Lets work on monolog item <full ULID> <title> <body>
본문이 비었으면 빈 줄과 본문을 뺀다. 이 기능은 <MONOLOG_DIR>/.monolog/config.json에 launch 블록이 있어야 켜진다. 설정 전 o는 launch not configured만 표시하고 하단 도움말에도 키가 나타나지 않는다. command는 셸 명령 문자열이 아니라 argv 배열이며 {dir}과 {prompt}를 각 인자 안에서 치환해 직접 실행한다. 따라서 본문의 따옴표·줄바꿈·백틱·$(...)와 관계없이 프롬프트 전체가 하나의 인자로 전달된다. {dir}은 실행 작업 디렉터리로도 쓰므로 --cwd 옵션이 없는 실행기도 설정할 수 있다. 설정 형식이 잘못되면 기능만 꺼지고 나머지 설정은 읽는다. 그러나 파일 어디든 JSON 문법 오류가 있으면 모든 설정이 초기화된다.
"launch": {
"command": ["kitty", "@", "launch", "--type=tab", "--cwd={dir}", "claude", "{prompt}"],
"dirs": { "paperwall": "~/IdeaProjects/paperwall", "monolog": "~/IdeaProjects/monolog" },
"default_dir": "~/IdeaProjects"
}
작업 태그를 나열한 순서대로 dirs에 등록된 첫 디렉터리를 고른다. 예약 태그 active와 스킬 출처 태그 claude는 디렉터리 매핑에 있어도 건너뛴다. 일치하는 태그가 없으면 default_dir을 쓰며 둘 다 없으면 상태 표시줄에 태그를 알리고 실행하지 않는다. 경로 앞의 ~는 홈 디렉터리로 확장한다. 그 뒤에도 상대 경로면 TUI 작업 디렉터리가 임의일 수 있어 launch dir must be absolute: <path>로 거부한다. 디렉터리가 없으면 launch dir not found: <path>를 표시한다.
Claude Code 스킬이 만든 작업은 저장소 태그를 붙이지 않고 본문에 monolog/internal/store/store.go:142 같은 저장소 경로를 기록하며 claude 태그만 붙인다. 따라서 기본적으로 default_dir에서 열린다. 분류 중 t로 저장소 태그를 붙이거나 모든 저장소의 상위 디렉터리를 default_dir로 설정할 수 있다.
실행기가 성공적으로 종료된 뒤에만 작업을 활성화한다. 이는 a와 같은 경로로 오늘 일정 맨 위로 옮기며 한 번에 커밋되고 u로 되돌릴 수 있으며 자동 푸시된다. 상태에는 launched: <title>이 표시되고 일정이 바뀌면 (moved to Today)가 덧붙는다. 실행 실패는 launch failed: <err>를 표시하고 커밋하지 않는다. 이미 활성인 작업은 활성 상태를 유지하고, 완료 작업은 실행하되 다시 활성화하지 않는다. 실행 중 커서를 옮겨도 활성화 대상은 실행을 시작한 작업이며 커서는 현재 위치에 둔다. 실행 제한 시간은 5초다. 초과하면 launch failed: launcher timed out: context deadline exceeded를 표시한다. kitty @ launch는 탭이 생기면 반환한다.
launch는 실행 가능한 설정이다. o는 설정한 명령을 그대로 실행하고 config.json은 작업 원격과 동기화되므로 원격에 푸시할 수 있는 사람은 모든 기기에서 o가 실행할 내용을 바꿀 수 있다. 작업 본문도 작성자를 가리지 않고 Claude 프롬프트에 들어간다. 가져온 이메일 발췌문이나 Telegram 입력도 포함될 수 있으므로 직접 작성하지 않은 작업은 실행 전 내용을 확인해야 한다.
kitty는 소켓을 통한 원격 제어가 필요하다. ~/.config/kitty/kitty.conf에 아래 설정을 넣고 kitty를 재시작해야 모든 kitty 셸이 KITTY_LISTEN_ON을 내보낸다.
allow_remote_control socket-only listen_on unix:/tmp/kitty
listen_on이 없으면 kitty @가 터미널을 통해 통신하려고 할 수 있으며, 이는 TUI의 대체 화면과 충돌한다. 실행기는 터미널에서 분리되므로 이 경우 화면을 망가뜨리는 대신 launch failed: …로 실패한다.
날짜·셸·라이선스
사용자에게 보이는 날짜의 기본 형식은 DD-MM-YYYY다. CLI 일정 입력, TUI 일정 변경 및 YAML 편집, 목록 날짜 열, 상세 패널, 반복 작업 커밋 메시지와 상호 참조 메모, 본문 메모 구분선, 오류 메시지에 적용한다. 이전 스크립트를 위해 YYYY-MM-DD 입력도 조용히 허용한다. TUI 일정 변경의 사용자 지정 입력은 설정 형식과 관계없이 Nd, Nw, Nm 상대 표기도 받는다. 디스크에는 표시 형식과 무관하게 ISO 형식(예: "schedule": "2026-04-15")으로 저장한다. TUI의 , 설정 모달에서 형식을 바꾸며 config.json의 date_format에 저장한다.
셸 자동완성은 다음 명령으로 생성할 수 있다.
monolog completion zsh > "${fpath[1]}/_monolog" # zsh
monolog completion bash > /etc/bash_completion.d/monolog # bash
monolog completion fish > ~/.config/fish/completions/monolog.fish # fish
기여 안내는 CONTRIBUTING.md에 있다. 변경마다 테스트를 포함하고 병합 전에 모든 테스트를 통과시키는 규칙과 빌드·테스트 명령, 계획 절차를 설명한다. Monolog는 MIT License로 배포되며 LICENSE에서 확인할 수 있다.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요