TrendShift · Local-first PKM

files.md — 당신의 인생을
plain .md 파일에 담는다

노트는 그냥 마크다운 파일 하나로 충분하다. 빌드 시스템 없는 PWA + Go 서버 + 텔레그램 봇으로 만든 안티-Second-Brain 선언문.

zakirullin/files.md · Go 56% · MIT · 3,632★ 2026-05-21 · TrendShift 15위
00 — 들어가며Context

먼저, PKM이 뭔가?

files.md를 이해하려면 PKM이라는 동네부터.

2020년대 들어 Obsidian·Roam·Notion·Logseq 같은 도구가 폭발적으로 늘었다. 공통 명칭은 PKM (Personal Knowledge Management). "내 머릿속 지식을 외부 시스템에 차곡차곡 쌓아두자"는 사상이다.

그런데 이 PKM 도구들에는 공통된 문제가 있다. 그래프 뷰, 백링크, 플러그인, 동기화 서비스, 자체 포맷… 기능이 늘어날수록 내 머리는 점점 비워진다. 정작 노트는 쌓이지만 다시 안 읽는다. files.md는 이 흐름을 정면으로 비판하며 등장했다.

Term · 용어
PKM (Personal Knowledge Management, 개인 지식 관리)
개인이 자기 지식을 모으고 연결하고 활용하는 시스템 전반. 대표 도구는 Obsidian, Roam Research, Notion, Logseq 등. 1990년대 데이비드 알렌의 GTD에서 시작해 2020년대에 폭발적으로 확산.
Term · 용어
Local-first (로컬 우선 소프트웨어)
2019년 Ink & Switch 연구소의 논문에서 정립된 개념. 네트워크가 없어도 동작하고, 클라우드가 망해도 데이터가 살아남는 설계. 진실의 원천(source of truth)이 클라우드가 아니라 사용자 디바이스에 있다. files.md는 이 원칙의 충실한 실천 예다.
Term · 용어
Second Brain (외부 두뇌)
Tiago Forte가 대중화한 PKM 사상. "외부 저장소에 지식을 쌓아 머리를 비우자". files.md 저자는 이것을 미루기(deferral)의 함정으로 본다. 시스템이 커질수록 "나중에 정리"가 늘어나고, 그 나중은 오지 않는다.
01 — 한 줄 요약TL;DR

이 프로젝트의 핵심 메시지

한 문장으로 줄이면.

Core Message

"노트는 그냥 .md 파일 하나면 충분하다. 도구가 똑똑해질수록 내 뇌는 멍청해진다 — Second Brain을 키우지 말고 First Brain을 써라."

files.md는 코드량보다 철학이 먼저다. 모든 데이터는 .md 파일과 폴더. 빌드 시스템 없음. 플러그인 없음. 의존성은 vendor/에 직접 포함. 입력 채널은 웹앱 + 텔레그램 봇 두 가지. 동기화는 mtime 기반 + append-only 로그.

Obsidian이 "스위스 아미 나이프"라면, files.md는 "잘 갈린 부엌칼 한 자루". 기능을 뺀 만큼 머리는 비워진다는 게 저자 zakirullin의 5년짜리 실제 시스템이다.

02 — 왜 주목받는가Why now

3,600개 넘는 별을 받은 레포가 TrendShift 15위에 오른 이유

시대적 배경 + 경쟁 우위 + 저자 후광.

경쟁 비교 — Obsidian/Notion vs files.md

비교 항목Obsidian · Notion · Roamfiles.md
설치네이티브 앱 다운로드브라우저에서 PWA로 설치 (혹은 그냥 URL 열기)
저장 방식자체 포맷 + 마크다운 + SQLite오직 .md 파일과 폴더
플러그인수백 개의 커뮤니티 플러그인없음. 의도적으로 차단
빌드 시스템Webpack/Vite/Esbuild없음. web/index.html이 그냥 동작
의존성node_modules 수백 MBvendor/에 모든 의존성 포함
입력 채널앱 자체웹앱 + Telegram 봇 (모바일 메모)
동기화유료 서비스 또는 iCloud자체 Go 서버 또는 iCloud/Dropbox 폴더
Analogy · 부엌칼 비유

Obsidian이 다기능 스위스 아미 나이프라면, files.md는 잘 갈린 부엌칼 한 자루다. 기능을 뺀 만큼 머리는 비워지고, 10년 뒤에도 그대로 굴러간다.

저자의 진짜 주장 — "Second Brain의 함정"

저자 zakirullin은 README에서 PKM 커뮤니티가 빠지기 쉬운 함정을 정면으로 비판한다. 영문 원문 일부를 풀어 옮기면:

Quote · 저자 인용

"PKM 도구를 쓰기 시작했을 때, 나는 망각의 문제를 풀고 있다고 믿었다. 나중에는 통합의 문제를 풀고 있다고 생각했다. 결국 깨달은 건, 내가 만든 게 새로운 문제 — 미루기(deferral) 였다는 사실이다. 시스템이 커질수록, 나는 정리·태깅·증류·금 캐내기 작업을 미래의 어떤 나에게로 미루고 있었다. 그 미래의 나는 절대 오지 않았다."

그래서 files.md의 결론은 "노트는 적게, 생각은 깊이"다. 폴더 구조는 처음엔 0개로 시작하고, 노트 하나에 아이디어 하나만, 새로운 지식은 미루지 말고 즉시 적용. 도구가 똑똑해질수록 내 뇌는 멍청해진다는 경고가 핵심이다.

왜 TrendShift가 이걸 잡았나 — 4가지 이유

  1. LLM 친화 — 모든 데이터가 .md라 ChatGPT/Claude에 그대로 던지면 컨텍스트가 된다. files.md/llms.txt까지 제공한다.
  2. 저자 후광 — 같은 저자의 cognitive-load 레포가 이미 큰 인기를 끌었다. 이름값이 가산점.
  3. 안티-트렌드 트렌드 — AI가 모든 걸 채워주는 시대에 "내 머리 써라"는 메시지가 역설적으로 신선하다.
  4. 실용성 — 5년간 저자 본인이 쓰고 있는 살아있는 시스템이다. 데모용 토이가 아니다.
03 — 기술 스택Stack

전체 기술 지도

백엔드 · 프론트엔드 · 인프라.

백엔드 (Go 56.1%)

코어 런타임

  • Go 1.24 — 전체 서버, 단일 바이너리로 배포. systemd로 띄움
  • 표준 net/http — Gin/Echo 같은 웹 프레임워크 없이 표준 라이브러리만
  • 리버스 프록시 없음 — 단일 바이너리가 HTTPS까지 직접 처리

외부 통합

  • go-telegram-bot-api/v5 — 텔레그램 봇 통합 (이동 중 입력 채널)
  • joho/godotenv.env 파일 로드 (BOT_API_TOKEN 등)
  • kelseyhightower/envconfig — 환경변수 → Go 구조체 매핑
  • robfig/cron/v3 — 주기 작업 (예약된 노트 이동, 백업 등)

파일시스템 · 암호 · 테스트

  • spf13/afero — 파일시스템 추상화. 테스트 시 인메모리 FS로 교체 가능
  • golang.org/x/crypto — 토큰 해시 등 암호 연산
  • rivo/uniseg — 유니코드 grapheme cluster 처리 (이모지 길이 계산)
  • stretchr/testify — 테스트 어설션
Term · 용어
Vendored Dependencies (벤더된 의존성)
외부 라이브러리를 레포 안에 직접 복사해두는 방식. go.mod만 있어도 빌드되지만, vendor/ 폴더를 두면 외부 네트워크 없이도 빌드된다. 저자는 "삭제된 의존성 걱정 없도록 자급자족이 우선"이라고 말한다.

프론트엔드 (JavaScript 28% + CSS 13.4%)

Vanilla JS PWA

  • HTML / Vanilla JS / CSS — React/Vue/Svelte 등 프레임워크 일절 없음
  • CodeMirror — 마크다운 에디터. (저자: "언젠가 우리 손으로 작은 구현으로 대체했으면")
  • web/lib/ — 모든 JS 의존성을 레포 안에 포함. PATCHED 키워드로 수정 부분 표시

브라우저 스토리지 (3중)

  • OPFS (Origin Private File System) — 브라우저 내부 가상 파일시스템, 기본 저장소
  • File System Access API — 실제 로컬 폴더에 직접 쓰기 (사용자 폴더 선택 시)
  • IndexedDBDirHandle 저장 → 재방문 시 동일 폴더 자동 재연결
  • localStorageserver.files 스냅샷, lastServerOk 인증 표식

PWA 인프라

  • manifest.json + service worker — 오프라인 동작, 홈 스크린에 설치 가능
  • 빌드 시스템 없음web/index.html만 열면 그대로 동작
Analogy · 변속기 없는 자전거

웹 프레임워크 없이 vanilla JS만 쓰는 건, 자전거에 변속기 없이 평지만 달리겠다는 결심과 비슷하다. 단순한 만큼 부품이 적고, 10년 뒤에도 그대로 굴러간다. "10년 뒤에도 /web/index.html을 열면 그냥 동작해야 한다" — 저자가 README에 못 박은 룰.

인프라 · 운영

  • 배포make init_server + make deploy_systemd. Debian 계열 호스트에 systemd 서비스
  • 인증 — HttpOnly 쿠키로 토큰 저장. JS에서 직접 접근 불가 (XSS 방어)
  • 백업 — crontab으로 매일 git commit. 0 0 * * * cd /app/storage/<USER_ID> && git add . && git commit -m "..."
  • 관리journalctl -u filesmd로 로그 확인. 별도 모니터링 스택 없음
  • 봇 모드 — Telegram long-poll API → 외부 포트 노출 없어도 작동 (NAT 안쪽 라즈베리파이 OK)
04 — 아키텍처Design

시스템 구조와 4가지 설계 패턴

전체 구조도 → 핵심 패턴 하나하나.

전체 시스템 구조도

┌───────────────────────────────────────────────────────────────────────┐
│                          사용자 디바이스                                │
│                                                                       │
│   ┌──────────────────┐         ┌─────────────────────┐                │
│   │  PWA (브라우저)   │ ◀──────▶│  로컬 .md 파일들    │                │
│   │  - CodeMirror    │  OPFS/  │  - brain/*.md       │                │
│   │  - Vanilla JS    │  FSAPI  │  - journal/*.md     │                │
│   │  - localStorage  │         │  - habits/*.md      │                │
│   └────────┬─────────┘         └─────────────────────┘                │
│            │ HTTPS                                                    │
└────────────┼──────────────────────────────────────────────────────────┘
             │
             │ POST /syncFile      (단일 파일 동기화)
             │ POST /syncFilenames (배치 동기화)
             │ POST /syncMediaFile (이미지 업로드)
             ▼
┌───────────────────────────────────────────────────────────────────────┐
│                       서버 (단일 Go 바이너리)                          │
│                                                                       │
│   ┌────────────────┐    ┌─────────────────┐    ┌──────────────────┐   │
│   │  sync API      │    │  Telegram Bot   │    │  Cron Worker     │   │
│   │  (server/sync) │    │  (server/bot.go)│    │  (robfig/cron)   │   │
│   └───────┬────────┘    └────────┬────────┘    └────────┬─────────┘   │
│           │                       │                       │           │
│           └───────────┬───────────┴───────────┬───────────┘           │
│                       ▼                       ▼                       │
│              ┌───────────────────────────────────────┐                │
│              │  파일 시스템 (afero abstraction)       │                │
│              │  /app/storage/<USER_ID>/*.md          │                │
│              │  + tokens/ + fslog (renames 로그)     │                │
│              └───────────────────────────────────────┘                │
└───────────────────────────────────────────────────────────────────────┘
             │
             │ Pull API (long poll)
             ▼
   ┌───────────────────────┐
   │  Telegram (외부)       │
   │  사용자가 메모 전송    │
   └───────────────────────┘

패턴 1 — 로컬 우선 + 옵션 서버

일반 웹앱은 "서버가 진실의 원천(source of truth)"이다. files.md는 정반대로 "로컬 디스크가 진실"이다. 서버가 없어도 앱은 동작한다. 사용자가 폴더를 열어주면 그 자리에서 .md 파일이 쓰여진다. 서버를 붙이면 여러 디바이스 간 동기화가 추가될 뿐이다.

패턴 2 — 동기화 알고리즘 (mtime 기반)

로컬 우선이지만 동기화는 만만치 않다. 같은 파일이 두 디바이스에서 동시에 수정되면? files.md의 답은 의외로 단순하다 — "timestamp 두 개로 모든 걸 판단한다".

타임스탬프의미용도
mtime파일 내용 마지막 수정 시간내용 동기화 비교
ctime파일 메타데이터(이동/이름변경) 변경 시간이름변경/이동 추적
lastClientSynced클라이언트가 마지막으로 서버 반영을 확인한 시점"여기까지 봤어요" 포인터

동기화는 두 가지 경로로 작동한다:

  1. 배치 동기화 (POST /syncFilenames): 수정된 파일 목록 + 삭제된 파일 목록 + 디렉토리별 포인터를 보내고, 서버는 그 포인터보다 최신인 파일들을 응답.
  2. 단일 파일 동기화 (POST /syncFile): 현재 에디터로 열려있는 파일 하나만 따로. 활발히 편집 중인 파일은 배치에서 제외하고 별도 채널로 처리해 경쟁 상태(race condition)를 회피.
Trap · 함정
왜 mtime을 쓰고 ctime을 안 쓰나?

Dropbox 같은 클라우드 폴더에서는 ctime이 임의로 바뀐다. 권한이나 소유자가 바뀌어도 ctime이 갱신되기 때문에 "진짜 내용이 바뀐 것"을 가려내기 어렵다. 그래서 내용 동기화는 mtime, 이름변경은 append-only 로그(fslog)로 분리했다.

패턴 3 — append-only 동기화 로그

파일 내용 동기화는 stateless로 처리되지만, 파일 이름변경삭제는 그렇게 못 한다. 클라이언트가 "이 파일이 사라졌네"라고 판단할 때, 그게 "삭제된 것"인지 "이름 바뀐 것"인지 알 수 없기 때문이다.

그래서 files.md는 서버에 fslog라는 append-only 로그를 둔다. 이름변경/삭제 이벤트가 모두 여기 쌓이고, 클라이언트는 자기가 마지막으로 읽은 위치 다음부터 읽어 동기화한다.

Analogy · 은행 거래원장

은행이 잔액을 직접 저장하지 않고 "거래 기록"만 쌓은 뒤 합산해서 잔액을 구하는 것과 같다. 상태(state)보다 이벤트(event)가 진실에 가깝다. 카프카, 데이터베이스 WAL, 블록체인 모두 같은 패턴이다.

패턴 4 — 텔레그램 봇 = "이동 중 입력 채널"

저자의 통찰: "PKM 도구의 가장 큰 적은 '입력 마찰'". 모바일에서 앱을 켜고, 폴더 정하고, 파일명 짓고... 이 과정에서 80%의 메모는 사라진다. 그래서 files.md는 텔레그램을 입력 채널로 활용한다.

봇은 외부에 포트를 열지 않는다. Telegram의 long-poll API를 사용하기 때문에 NAT 안쪽 라즈베리파이에서도 돌릴 수 있다.

Fix · 해결책
"모든 흐름을 Chat.md로 통합"

README ADR 2025-06-30 — 저자 본인의 결정. "회의 중에 머릿속에서 나오는 모든 걸 그냥 한 입력 필드에 떨어뜨리고 싶었다. 나중에 분류하면 된다." 입력 마찰을 0으로 만드는 게 핵심.

05 — 디렉토리Repo map

레포 구조 해부

어디에 뭐가 있는지.

files.md/
├── cmd/                  # 명령행 도구들 (Go의 관습)
│   ├── server/           # 메인 서버 entrypoint
│   ├── whoop/            # 웨어러블(Whoop) 데이터를 일기에 자동 추가
│   ├── tomdlinks/        # [[wikilinks]] → [표준 마크다운 링크] 변환
│   ├── backlink/         # 역참조 링크 자동 삽입
│   └── shifttime/        # 일기 타임스탬프 시간대 이동
│
├── server/               # 서버 비즈니스 로직
│   ├── bot.go            # 텔레그램 봇 핸들러
│   └── sync/             # 동기화 API 핵심
│
├── web/                  # PWA 프론트엔드
│   ├── index.html        # 단일 진입점 (빌드 불필요)
│   ├── lib/              # 프론트엔드 라이브러리들 (PATCHED 키워드 표시)
│   └── img/              # 스크린샷, 아이콘
│
├── tests/                # E2E 테스트 (앱 + 서버 동시에)
├── vendor/               # 벤더된 Go 의존성 (외부 네트워크 불필요)
├── docs/                 # 아키텍처 문서 (Mermaid 다이어그램 포함)
│   ├── sync-flow.md      # 동기화 흐름 상세
│   ├── your-own-server.md# 셀프호스팅 가이드
│   └── bot.md            # 봇 사용법
│
├── Makefile              # init_server / deploy_systemd 명령
├── go.mod / go.sum       # Go 모듈 정의
├── LICENSE               # MIT
└── README.md             # 철학 + 사용법 + ADR(!) 일체형

가장 흥미로운 두 곳

(1) cmd/ — "마크다운 파일에 대한 미니 유닉스 도구들"

저자는 마크다운 폴더를 마치 유닉스 파일 시스템처럼 다룬다. 작은 Go 프로그램들이 각자 한 가지 일만 한다.

# 위키링크를 표준 마크다운 링크로 변환
go run cmd/tomdlinks/tomdlinks.go .

# Whoop(웨어러블)에서 어제의 수면/심박수 가져와
# journal/2026.05 May.md에 추가
go run cmd/whoop/whoop.go

# 모든 파일에 "이 파일을 참조하는 다른 파일들" 섹션 자동 삽입
go run cmd/backlink/backlink.go
Analogy · 유닉스 철학

"한 가지 일을 잘하는 작은 도구를 조합하라" — 유닉스 철학의 마크다운 버전이다. ls | grep | sort처럼 tomdlinks | backlink | shifttime을 조합한다.

(2) README의 ADR 섹션 — 살아있는 결정 기록

대부분의 레포는 README에 사용법만 적는다. files.md README의 절반은 ADR (Architecture Decision Records)로 채워져 있다. "왜 이걸 이렇게 만들었나"의 시간순 기록이다.

Quote · ADR 발췌

2024-10-06 — fyne.io를 제거했다. Electron의 대안으로 좋아보였지만, 스크롤·이모지·텍스트 선택 같은 디테일을 구현하는 데 엄청난 노력이 필요했다. 결국 웹 스택을 쓰기로. ("데스크탑에 웹 스택 쓰는 거 싫어하지만 다른 선택지가 없어보인다")

2025-09-21 — WASM 제거했다. 메시지 이동 시 버그가 났는데 재현 못 했다. JS→Go→JS 콜백 체인이 너무 복잡해서 디버깅이 불가능했다. inbox.wasm 파일이 8MB라는 것도 문제였다. JS로 재구현했다.

2025-06-30 — 모든 흐름을 Chat.md로 통합 결정. 회의 중에 머릿속에서 나오는 모든 걸 그냥 한 입력 필드에 떨어뜨리고 싶었다. 나중에 분류하면 된다.

이 ADR 섹션은 단순한 기록이 아니다. "우리가 이 길에 도달하기까지 어떤 길을 거쳤는가"의 박물관이다. 코드를 읽기 전에 ADR을 읽으면 "왜 이 함수가 이렇게 생겼지?"가 풀린다.

06 — 저자 철학Principles

files.md를 만드는 6가지 룰

코드 스타일이 아니라 인생 철학에 가깝다.

README의 "How to contribute" 섹션은 다른 어떤 레포에서도 보기 힘든 강한 의견을 담고 있다.

Rules · 기여 룰 6가지

1. 주니어 개발자가 이해할 수 있어야 한다.

2. 이상적으로, 모든 PR은 코드를 추가가 아니라 제거하거나 단순화해야 한다.

3. 코드가 적을수록 우리는 유연해진다.

4. 모든 의존성은 우리의 책임이다. 가능하면 의존성을 피하라.

5. 코드는 자급자족해야 한다 (vendor/, web/lib/가 레포에 포함된 이유).

6. "이 기능이 정말 필요한가? 진짜 일을 돕는가, 아니면 도파민만 주는가?"

백엔드 가이드라인 (Go)

프론트엔드 가이드라인 (Vanilla JS)

07 — 학습 포인트What to learn

분야별 배울 것

기술 영역마다 무엇을 가져갈지.

Go — 모듈러 모놀리스 패턴

  • 마이크로서비스가 아니지만 모듈 경계가 분명한 단일 바이너리 설계
  • cmd/에 진입점, server/에 비즈니스 로직, vendor/에 의존성
  • Go 커뮤니티의 표준 레이아웃을 충실히 따른다
  • spf13/afero로 파일시스템 추상화 → 테스트 가능성 확보

실습: cmd/에 자기만의 작은 유틸리티(예: 오래된 일기 자동 아카이브) 추가해보기. afero로 인메모리 파일시스템 테스트.

PWA / File System Access API

  • 브라우저가 어떻게 OPFS와 실제 디스크 폴더를 동시에 다루는지 코드로 본다
  • showDirectoryPicker()로 얻은 FileSystemDirectoryHandle을 IndexedDB에 보관
  • 재방문 시 권한 복원하는 패턴 분석

실습: 빈 HTML 파일 하나로 시작해서 "로컬 폴더의 마크다운 파일 목록 보여주는 PWA" 200줄로 완성.

텔레그램 봇 통합

  • go-telegram-bot-api로 long-poll API 사용법
  • 인라인 모드(Inline Mode)로 검색 기능 구현
  • NAT 안쪽에서도 동작하는 봇 아키텍처

실습: 텔레그램에서 받은 메시지를 자기 노트 폴더의 inbox.md에 자동 append하는 미니 봇.

동기화 알고리즘 설계

  • 두 클라이언트가 같은 파일을 동시 편집할 때의 충돌 처리
  • append-only 로그로 이름변경/삭제 추적
  • mtime 기반 비교 vs Hash 기반 비교의 trade-off
  • HttpOnly 쿠키 기반 인증 + 클라이언트 표식 (lastServerOk) 패턴

실습: "두 폴더를 자동 동기화하는 미니 Dropbox"를 Go로 구현.

문서화 — ADR 패턴

  • Mermaid 다이어그램으로 흐름도/시퀀스도를 깃허브에서 바로 렌더링
  • "이 결정의 배경"을 시간순으로 기록하는 ADR 습관
  • README에 ADR을 통합하는 자유로운 형식

실습: 자기 사이드 프로젝트에 ADR 섹션 추가하고 결정마다 한 줄씩 적기.

08 — 요구사항Setup

하드웨어·시스템 요구사항

모드별 최소 사양.

모드요구사항외부 노출
브라우저만 사용Chromium 계열 (File System Access API 지원)불필요 — OPFS만으로 OK
Safari/FirefoxOPFS만 사용 (실제 폴더 미지원)불필요
오프라인서비스 워커가 캐싱 → 네트워크 없어도 동작불필요
셀프호스팅 서버Debian/Ubuntu + Go 1.24+, SSH 가능 호스트HTTPS 포트 노출
라즈베리파이가능. 매우 가벼움봇만 쓰면 노출 불필요
봇 전용로컬 PC도 OK (Long-poll API)전혀 불필요
Tip · 셀프호스팅 최단 경로

BOT_API_TOKEN.env에 설정하고 make init_server + make deploy_systemd. storage/<USER_ID> 폴더가 자동 생성되고 텔레그램 봇이 입력 채널 역할을 한다. 외부 포트 노출이 부담스러우면 봇 모드만 써도 충분.

09 — 실습 과제Hands-on

직접 해볼 수 있는 5단계

난이도별 실습 — Easy → Hard.

실습 1 — 5분 안에 직접 써보기Easy

1) Chrome에서 app.files.md 접속 2) 로컬 폴더 하나 열기 3) brain/첫노트.md 만들고 두 번째 노트와 [키로 연결 4) Finder/탐색기에서 직접 열어 .md 파일이 정말로 거기에 있는지 확인

배우는 것: File System Access API의 실체, "정말 내 디스크에 쓰는구나"의 감각

실습 2 — 텔레그램 봇 연동Easy

1) @FilesMDBot에서 메시지 하나 보내기 2) 웹앱에서 Chat.md를 새로고침해서 동기화 시간 측정 3) 모바일 잠금 화면에서 "노트 한 줄" 떠올렸을 때 텔레그램만 켜서 보내는 워크플로우 체험

배우는 것: "입력 마찰 0" 체감 — 왜 저자가 Chat.md로 모든 흐름을 통합했는지 이해

실습 3 — cmd/에 미니 도구 추가Medium

1) Go 설치 2) cmd/wordcount/wordcount.go 새로 생성 3) 현재 폴더의 모든 .md 파일 단어 수 합산 4) 가장 긴 파일 Top 5 출력 5) 기존 cmd/backlink/backlink.go 패턴 참고

배우는 것: Go 표준 라이브러리만으로 파일 처리, "유닉스 도구 한 개 추가" 패턴

실습 4 — 자체 LLM 통합Medium

1) 로컬 폴더의 모든 .md를 합쳐 OpenAI/Anthropic API로 전송 2) "최근 일주일 일기에서 반복되는 키워드 3개" 추출 3) Python 스크립트로 자동화 4) 결과를 brain/keywords.md로 저장

배우는 것: files.md의 "LLM-friendly" 주장을 직접 검증, llms.txt의 효용 체감

실습 5 — 자체 서버 + 두 디바이스 동기화Hard

1) 저렴한 VPS 또는 라즈베리파이에 make init_server로 서버 배포 2) 데스크탑과 휴대폰에서 동시에 같은 파일 편집 3) 충돌 동작 관찰 4) POST /syncFilenames 응답을 브라우저 Network 탭에서 캡처 5) README의 sync-flow.md와 매칭

배우는 것: 실전 동기화 알고리즘, mtime/ctime/lastClientSynced 3개가 만드는 정합성

10 — 학습 로드맵6 weeks

6주 심화 학습 로드맵

주차별로 따라가면 local-first PKM 마스터.

Week 01
Local-first 사상의 뿌리 이해

Ink & Switch "Local-first software" 논문 읽기 → CRDT 개념 입문 → files.md README의 ADR 섹션 처음부터 끝까지 정독

Week 02
File System Access API + OPFS 실전

MDN의 File System Access API 문서 → navigator.storage.getDirectory()로 OPFS 다루기 → FileSystemDirectoryHandle을 IndexedDB에 저장/복원 → "브라우저 안에서만 동작하는 노트 앱" 200줄로 완성

Week 03
Go 단일 바이너리 서버 디자인

표준 라이브러리 net/http만으로 REST API 구축 → spf13/afero로 파일시스템 추상화 → 벤더링 (go mod vendor) → systemd 서비스 파일과 journalctl

Week 04
동기화 알고리즘 직접 구현

두 클라이언트 동시 편집 충돌 케이스 정리 → mtime 기반 비교 vs Hash 비교 trade-off → append-only 로그 + 클라이언트 포인터 관리 → "두 폴더를 자동 동기화하는 미니 Dropbox" Go로 구현

Week 05
텔레그램 봇 + PKM 자동화

go-telegram-bot-api로 봇 만들기 → Inline mode와 callback button 처리 → cron으로 "매일 아침 일기 템플릿 자동 생성" 워커 추가 → 웨어러블 API(Whoop, Oura, Garmin) 데이터를 일기에 자동 주입

Week 06
자신만의 PKM 의견 정립

저자의 cognitive-load 레포 정독 → Joan Westenberg의 "I Deleted My Second Brain" 에세이 읽기 → 본인 노트 폴더에서 1년 이상 안 본 파일 비율 측정 → 도구를 다이어트할지, 사용 패턴을 바꿀지 결정

11 — 키워드 사전Glossary

핵심 용어 한눈에

자주 마주칠 단어들.

PKM
Personal Knowledge Management. 개인이 자기 지식을 모으고 연결하고 활용하는 시스템. Obsidian, Roam, Notion이 대표적 도구.
Local-first
데이터의 진실(source of truth)이 사용자 디바이스에 있는 설계. 클라우드는 동기화 부속물.
PWA
Progressive Web App. 브라우저 기반 앱이지만 설치 가능하고 오프라인 동작 + 푸시 알림 등 네이티브 앱 기능 제공.
OPFS
Origin Private File System. 브라우저가 도메인별로 격리해서 제공하는 가상 파일시스템. 사용자 폴더에 직접 못 쓸 때의 폴백.
File System Access API
웹앱이 사용자 동의 하에 로컬 폴더에 직접 읽기/쓰기 할 수 있는 모던 브라우저 API. Chrome/Edge에서 지원.
CodeMirror
웹에서 동작하는 풍부한 텍스트 에디터 라이브러리. VSCode가 Monaco를 쓰는 것처럼 많은 마크다운 앱이 CodeMirror를 쓴다.
vendoring
외부 의존성을 자기 레포에 복사해두는 방식. Go의 vendor/ 폴더가 대표적. 빌드 재현성과 자급자족.
mtime / ctime
파일의 modification time(내용 수정 시간)과 change time(메타데이터 변경 시간). 유닉스 stat 호출로 얻을 수 있는 타임스탬프.
append-only log
새 데이터를 끝에 추가만 하고 절대 수정하지 않는 로그. 카프카, 데이터베이스 WAL, 블록체인 모두 이 패턴.
ADR
Architecture Decision Record. "왜 이런 설계 결정을 했는가"를 시간순으로 기록한 문서. 미래의 자신을 위한 메모.
HttpOnly Cookie
JS에서 접근할 수 없는 쿠키. XSS 공격으로부터 토큰을 보호하기 위한 표준 방식.
race condition
두 비동기 작업이 같은 자원에 동시 접근할 때 순서에 따라 결과가 달라지는 버그. files.md는 "대부분의 버그가 race"라고 강조.
Second Brain
Tiago Forte가 대중화한 개념. "외부 저장소에 지식을 쌓아 머리를 비우자". files.md 저자는 미루기(deferral) 함정으로 비판.
Tolerant Reader
"받은 데이터가 약간 이상해도 최대한 동작하라"는 파싱 철학. files.md는 마크다운 파싱에서 이 원칙을 따른다.
grapheme cluster
사용자가 "한 글자"로 인식하는 유니코드 단위. 이모지 같은 합성 문자는 여러 코드포인트로 구성. files.md는 rivo/uniseg로 처리.
systemd
현대 Linux의 init 시스템. systemctl start filesmd / journalctl -u filesmd로 서비스·로그 관리.
12 — 참고 링크Refs

더 깊이 파고들 자료

공식 · 사상 · 학습 리소스.

공식 자료

저자 + Local-first 사상

핵심 라이브러리 · 학습 리소스

Action · 이번 주에 해볼 것

files.md를 처음 만났다면 이 순서로 5단계.

  1. app.files.md 5분 체험. Chrome에서 접속 → 로컬 폴더 열기 → 노트 두 개 만들고 링크 → Finder/탐색기에서 실제 .md 파일 확인. "정말 내 디스크에 쓰는구나"를 손으로 느낀다.
  2. README ADR 정독. 코드 보기 전에 README의 ADR 섹션 처음부터 끝까지. 저자가 5년간 어떤 결정을 했고 어떻게 바꿔왔는지 시간순으로 추적. "왜 이 모양인가"가 풀린다.
  3. 텔레그램 봇 워크플로 체험. @FilesMDBot에 메시지 한 줄 → 웹앱에서 Chat.md 새로고침. "입력 마찰 0"이 어떤 느낌인지 직접 느껴봐야 저자의 의도가 이해된다.
  4. 본인 노트 폴더 감사. 1년 이상 안 본 파일 비율 측정. 50% 이상이면 도구 다이어트가 답이다. files.md 철학이 본인에게 맞는지 판단의 근거.
  5. cmd/ 패턴으로 미니 도구 하나. Go 설치 → cmd/wordcount/wordcount.go 같은 작은 유틸리티 한 개를 직접 작성. 유닉스 철학의 마크다운 버전이 어떤 느낌인지 손으로 체득.
원문 · zakirullin/files.md (GitHub) · 분석일 2026-05-21 · TrendShift 15위 시점