내 AI 러닝 코치는 Git 저장소와 Claude 에이전트다
훈련을 마치고 시계가 동기화되면, 3분 뒤에는 분석이 저장소에 기록되고 그 주의 계획이 조정되어 있으며 코치가 Strava 활동 아래에 댓글을 남겨 둔다. 앱을 만든 것도, 서버를 짠 것도, 토큰 단위 요금이 나가는 것도 아니다:Claude 구독과 AgentsRoom, 그리고 Markdown 파일뿐이다. 그대로 따라 할 수 있는 전체 구성을 공개한다.
훈련을 마친다. 시계는 늘 그렇듯 알아서 Strava에 동기화된다. 나는 샤워를 하러 간다.
샤워를 마치고 나올 때쯤이면 내가 아무것도 건드리지 않은 채 세 가지 일이 끝나 있다. 훈련 분석이 내 훈련 저장소에 기록되어 있다. 그 주의 계획이 조정되었고, 변경 이유가 옆에 적혀 있다. 그리고 Strava 활동 아래에는 코치의 댓글이 있다. 오늘 훈련이 어떤 값어치였는지, 금요일 내용이 어떻게 바뀌는지를 알려 준다.
이 코치는 내가 만든 애플리케이션이 아니다. Markdown 파일로 된 Git 저장소, Claude 구독, 그리고 그 전부를 붙들고 있는 AgentsRoom이다. 서버는 한 줄도 짜지 않았고, 토큰 단위 청구서도 없다. 조립에 든 시간은 주말 하나쯤이다.
전체를 템플릿으로 공개해 두었다:github.com/AgentsRoomDev/running-performance-coach. 클론해서 비워 둔 자리를 채우면 당신 것이 된다. 이 글은 API라는 단어는 들어 봤지만 webhook은 짜 본 적 없다는 전제로, 구조를 조각별로 설명한다.
배경을 밝히자면:나는 오래 달렸고, 마라톤 2시간 47분, 하프 1시간 13분 59초, 10km 33분 45초다. 지금 사이클의 목표는 10km에서 다시 34분을 깨는 것이다. 뒤에 나올 이야기와 관계가 있다:역치 훈련이 무엇인지 매번 다시 설명해 주는 범용 코치는 나에게 아무 쓸모가 없고, 이 구성이 푸는 문제가 바로 그것이다.
훈련이 끝난 뒤 댓글이 달릴 때까지 벌어지는 일
전체 흐름은 여섯 단계다:
- 시계가 활동을 Strava로 보낸다. 이건 이미 누구에게나 일어나는 일이다.
- 15분마다 작은 Python 스크립트가 Strava에 새로운 것이 있는지 묻는다.
- 새 훈련을 찾으면 내 저장소에 Markdown 훈련 시트를 만든다:랩, 구간 기록, 거리, 심박. 측정된 값만 담는다.
- 동시에 Strava 활동의 제목과 설명도 다시 쓴다. 내 피드에 계속 "오후 러닝"이라고 뜨지 않도록.
- 그런 다음 서명된 메시지를 AgentsRoom에 보내고, 훈련을 이미 손에 쥔 상태로 Claude 에이전트를 띄운다.
- 그 에이전트가 코치의 일을 한다:읽고, 비교하고, 분석을 쓰고, 그 주를 조정하고, 커밋하고, 푸시하고, Strava에 댓글을 달고, 긴 리포트를 메일로 보내 준다.
앞의 다섯 단계는 배관 공사다. 여섯 번째가 이 글의 주제다.
훈련 일지는 데이터베이스가 아니라 Git 저장소다
모든 것을 바꾼 결정이고, 사람들이 가장 놀라는 결정이기도 하다.
훈련 하나 = 파일 하나, journal/2026/2026-09-03.md. 한 주 = 파일 하나, plan/weeks/2026-W36.md. 계획 변경 하나 = 커밋 하나, 이유는 메시지 안에. 데이터베이스도, 스키마도, 마이그레이션도, 인터페이스도 없다.
중요한 순서대로 세 가지 결과가 따라온다.
코치가 자기 이력을 다시 읽을 수 있다. 3주 전에 자기가 무엇을 처방했는지 알고, 그것이 통했는지 확인할 수 있다. 훈련 이야기를 들려주는 챗봇은 대화할 때마다 0에서 다시 시작한다. 저장소를 가진 에이전트에게는 기억이 있고, 그 기억은 사람도 읽을 수 있다.
나는 계획을 휴대폰의 GitHub 앱에서 읽는다. 저장소의 README.md는 소개 페이지가 아니다:내 대시보드다. CLAUDE.md에 적힌 계약이 그 점을 못박아 둔다. README에 반영되기 전까지 어떤 계획도 끝난 것이 아니다. 결과적으로 나는 유지할 인터페이스가 하나도 없으면서도, 오늘 무엇을 하는지 알려 주는 화면을 가지고 있다.
되돌릴 수 없는 것은 없다. 에이전트가 쓰는 모든 것은 커밋이다. 읽을 수 있고, 따질 수 있고, revert할 수 있다. 애플리케이션이 혼자 결정해 버리는 것과는 아주 다르다.
1단계:Strava가 작은 스크립트를 깨운다
Strava는 API를 공개한다:프로그램이 "이 선수의 최근 활동을 달라"고 물을 수 있는 통로다. strava_sync.py 스크립트는 정확히 그 일을 하고, 돌아온 답을 훈련 시트로 바꾼다.
흥미로운 부분은 네트워크 호출이 아니라 재구성 쪽이다. 시계는 가공되지 않은 랩을 기록한다. 스크립트는 그것이 어떤 훈련이었는지 알아내야 한다:
Lap 1 : 4.40 km in 26'07 (5:56/km) ← 워밍업
Lap 2 : 1.00 km in 3'41 (3:41/km) ← 1번째 반복
Lap 3 : 0.20 km in 1'59 (9:55/km) ← 회복
... → "5 x 1000m r' 2'"
스크립트는 "가장 빠른 k개의 랩이 반복 구간이다"라는 형태의 모든 분할을 시도해 보고, 그중 말이 되는 최선을 남긴다. 사소해 보이지만 사소하지 않다:속도로 단순하게 묶으면 워밍업이 회복 구간보다 빠른 순간 바로 걸려 넘어진다.
무엇보다 훈련의 형태는 시계에서 재구성하지, 절대 계획에서 재구성하지 않는다. 반대로 하고 싶어진다(계획에 5 x 1000m라고 적혀 있으니 그대로 쓰면 된다). 그리고 그것이 정확히 실수다:핵심은 내가 다른 것을 한 날을 잡아내는 데 있다. 둘이 어긋날 때 그 어긋남이 곧 정보이고, 코치는 그것을 본다:
계획 3 x 8' → 연속주로 실행
시작하기 전에 경고 두 가지.
Strava API는 2026년 6월부터 유료 개발자 구독을 요구한다. 그것이 없으면 모든 호출이 403 Application Status Inactive를 돌려준다. 대안은 있고 템플릿에도 들어 있다:시계에서 TCX 파일을 내보내 import_tcx.py에 넘기면 된다. 가져오기 이후의 모든 단계는 똑같이 동작한다.
할당량은 넉넉하지만 실재한다. 내 애플리케이션 기준으로 읽기는 15분당 300건, 하루 3,000건이다. 스크립트는 정상 상태에서 한 회차당 하나만 쓰니 하루 96건이다. 상한과는 한참 떨어져 있지만, 이런 것은 나중이 아니라 미리 확인하는 종류의 일이다.

2단계:스크립트가 서명과 함께 에이전트를 깨운다
여기서부터 재미있어진다.
webhook은 질문의 반대다. 5분마다 새로운 것이 있는지 묻는 대신, 프로그램에 웹 주소를 넘겨 두면 그 일이 일어났을 때 저쪽에서 메시지를 보내온다. 아무 일도 없는 동안에는 아무것도 내지 않는다.
AgentsRoom이 제공하는 것이 정확히 그것이다:webhook 트리거다. 앱에서 트리거를 만들면 URL과 시크릿을 돌려준다. 그 URL로 JSON 메시지를 보내는 사람은 누구나 에이전트를 띄울 수 있다. 내가 쓴 프롬프트와 메시지 내용이 이미 주입된 상태로.

내 스크립트가 보내는 메시지는 일부러 아주 작다:
{
"type": "created",
"title": "03/09 · 5 x 1000m r' 2'",
"body": "03/09/2026 훈련을 Strava에서 가져왔습니다.\n\n포인트 훈련:5 x 1000m r' 2'\n구간 기록:3'41 - 3'40 - 3'38 - 3'40 - 3'35\n\n총 거리:12.51 km, 1h07'42 (5:25/km), 누적 상승 56 m\n계획된 훈련:RP10-5x1000\n\n훈련 시트:journal/2026/2026-09-03.md\n주간 시트:plan/weeks/2026-W36.md"
}
여기에 없는 것을 눈여겨보라:계획의 본문이다. webhook이 나르는 것은 계획된 훈련의 코드와 시트의 경로이지, 그 내용이 아니다. 저장소를 가진 에이전트는 직접 읽으러 갈 것이고, 저장소가 없는 에이전트가 내 내부 지시를 받을 이유는 없다. Strava에 공개하는 설명문에 적용되는 규칙과 같다.
서명, 그리고 함께 딸려 오는 함정
에이전트를 띄우는 공개 URL을, 발견한 사람이면 누구나 쓸 수 있게 열어 둘 수는 없다. 그래서 트리거에는 서명이 붙는다:스크립트가 공유 시크릿으로 메시지의 지문을 계산해서(용어가 익숙하다면 HMAC-SHA256이다) X-AgentsRoom-Signature 헤더에 실어 보낸다. 서버도 같은 지문을 다시 계산하고, 일치하지 않으면 거부한다.
서명이 없으면 답은 무뚝뚝하다:
{"error":"REJECTED","message":"Signature missing."}
그리고 나에게 저녁 하나를 통째로 쓰게 만든 함정이 이것이다. 서명이 덮는 것은 실제로 회선에 나가는 정확한 바이트열이지, 메모리 위의 객체가 아니다. 디스크에 있는 파일에 서명해 놓고 다른 레이어가 객체를 다시 직렬화하게 두면(공백 하나가 늘거나, 키 순서가 달라지거나, 악센트 이스케이프 방식이 달라지면), 서버가 절대 받지 않을 메시지에 대한 완벽하게 유효한 서명이 만들어진다. 이 거부는 디버깅이 불가능하다:양쪽 모두 멀쩡해 보인다.
고치는 방법은 한 문장이면 된다:직렬화와 서명을 같은 자리에서 한다. 템플릿에서는 post_json 함수가 둘 다 맡고, 그 밖의 무엇도 메시지 본문을 건드릴 수 없다.
3단계:세 개의 층이 코치에게 자신이 누구인지, 여기서는 어떻게 돌아가는지, 지금 무엇을 할지를 알려 준다
코칭하는 에이전트는 커다란 프롬프트 하나가 아니다. 서로 다른 세 개의 텍스트이고, 그 분리가 중요하다.
층 1, 페르소나:누구인가
AgentsRoom에서 에이전트에 붙여 둔 시스템 프롬프트다. 훈련 철학을 담고 있고, 의도적으로 종목에 대해 범용적이다:누구든 코칭할 수 있다.
당신의 일은 단순히 훈련 계획을 생성하는 것이 아닙니다. 선수의 훈련을 분석하고, 현재 컨디션을 이해하고, 앞으로의 훈련을 조정하면서 지속적으로 코칭합니다. […] 동기 부여형 챗봇이 아니라 경험 많은 코치처럼 말하세요.
하지 않는 일도 적혀 있다:훈련을 목표 페이스를 지켰는지만으로 판단하지 않을 것, 기록 예측의 불확실성을 분명히 말할 것, 선수가 원한다는 이유만으로 목표를 승인하지 않을 것. 마지막 줄이야말로 코치를 쓸모 있게 만드는 대목이다.
직접 쓸 필요는 없다:이 페르소나는 AgentsRoom 에이전트 카탈로그에 러닝 퍼포먼스 코치라는 이름으로 공개되어 있다. 한 번 클릭하면 설치되고, 바로 쓸 수 있다.
층 2, CLAUDE.md:여기서는 어떻게 돌아가는가
이것이 계약이고, 세션이 시작될 때마다 가장 먼저 읽힌다. 파일 구조, 그 구조를 일관되게 지켜 주는 규칙, 모든 제안을 제약하는 훈련 원칙, 그리고 무엇보다 의식:훈련이 보고되었을 때 실행할 정확한 순서가 담겨 있다.
정밀도의 수준이 드러나므로 한 대목을 인용한다:
한 주가 무너질 때 깎는 순서: 먼저 조깅에 붙은 여분의 시간, 다음은 보강 운동, 다음은 장거리주의 길이, 그다음 포인트 훈련 하나. 한 주 전체는 절대 안 된다.
여기서 코치는 챗봇이기를 그만둔다. 매번 즉석에서 절차를 지어내는 것이 아니라, 내가 한 번 써 둔 절차를 따른다. 템플릿 저장소에서 파일 하나만 읽어야 한다면 이것을 읽어라.
층 3, 트리거 프롬프트:지금 무엇을 할 것인가
훈련이 도착했을 때 에이전트에게 건네지는 메시지다. 활동은 템플릿 변수로 받는다:{{event.title}}, {{event.body}}, {{event.url}}. 그래서 에이전트는 훈련을 찾으러 가는 대신 이미 손에 쥔 상태로 시작한다.

트리거에 들어 있는 그 골격은 이렇다:
Strava에서 새 훈련을 가져왔습니다.
**{{event.title}}** · 활동 {{event.id}}
{{event.url}}
{{event.body}}
---
당신은 `training-plan` 저장소 안에 있습니다. `CLAUDE.md`를 먼저 읽으세요:그것이 법입니다.
내 언어로 쓰고, 처음부터 끝까지 나에게 직접 말하세요(§3).
§6의 의식이 적용되지만 그 **1단계는 이미 끝나 있습니다**:`strava_publish.py`가
훈련 시트를 만들고 커밋했습니다. 당신은 2단계에서 다시 시작해 끝까지 갑니다.
산출물은 셋, 이 순서대로입니다:**저장소 안의 분석**,
**Strava 활동 아래의 댓글**, **메일**.
⚠️ **당신은 무인으로 돌아갑니다:질문을 읽을 사람이 없습니다.** 절대 판단을
요청하지 마세요:스스로 정하고, 스스로 실행하고, 무엇을 어떻게 정했는지와
그 이유를 보고서에 쓰세요.
## 1 · 분석과 계획 조정(§6 의식, 2단계에서 6단계)
1. 무엇보다 먼저 `git pull --rebase`:시트가 서버에서 왔을 수 있습니다.
2. 이 순서로 읽으세요:오늘의 시트, 주간 시트,
`athlete/zones-and-paces.md`, 그리고 **최근 3개의 훈련 시트**:
훈련은 절대 혼자 판단하지 않습니다.
3. `## Analysis` 섹션을 쓰세요:**결론이 먼저**, 다음은 그것을 떠받치는
신호들, 마지막으로 그것이 무엇을 바꾸는지.
⛔ `## Analysis`가 이미 채워져 있으면 다시 쓰지 마세요.
4. 주간 시트를 갱신하고 **모든** 계획 변경을 `## Adjustments` 아래에
이유와 함께 남기세요.
5. **`README.md`를 다시 생성하세요**:내가 휴대폰으로 읽는 화면입니다.
6. 커밋과 푸시, 경로는 명시적으로, ⛔ 절대 `git add -A`는 쓰지 마세요.
## 2 · Strava에서 kudos와 댓글
⛔ Strava 댓글은 공개됩니다:목표 심박 금지, 잔부상 이야기 금지,
내부 판단 금지, 예측 기록 금지.
## 3 · 메일로 보내는 전체 리포트
가장 많은 일을 하는 줄은 가운데에 있다:"질문을 읽을 사람이 없습니다". 화면 앞에 아무도 없는 상태로 돌아가는 에이전트가 판단을 요청하는 것은 실수를 저지르는 것이 아니다. 그냥 멈춰 설 뿐이고, 그 사실은 다음 날에야 알게 된다.
어떤 모델을 쓰고, 100만 토큰이 왜 허세가 아닌가
| 설정 | 값 |
|---|---|
| 모델 | Claude Opus, 1M 컨텍스트 |
| 추론 강도 | 높음 |
| 권한 모드 | 자율 |
| 브라우저 접근 | 켜짐 |

긴 컨텍스트는 멋 부리기가 아니다. 훈련 하나를 제대로 판단하려고 코치는 오늘의 시트, 주간 시트, 기준 페이스 표, 그리고 직전 세 번의 훈련을 읽는다. 훈련은 절대 혼자 판단할 수 없다:쌓인 부하, 날들의 배치, 지켜보는 중인 항목들이 결론을 통째로 바꾼다. 두 시간짜리 장거리주 다음 날의 3'38 세 개는, 휴식일 다음 날의 같은 3'38과 같은 이야기를 하지 않는다.
자율 모드는 부주의가 아니라 결과다:화면 앞에 아무도 없는 실행에는 git push를 승인해 줄 사람이 없다. 그리고 브라우저 접근은 에이전트가 Strava에 댓글을 달러 가고 메일을 보내게 해 주는 것인데, 둘 다 여기서는 쓸 만한 API가 없다.
무엇을 자동화했고, 무엇을 일부러 자동화하지 않았나
내가 가장 만족하는 설계 결정이고, 놓치기 쉬운 부분이다.
가져오기 작업은 기록하고 게시할 뿐, 절대 판단하지 않는다.
| 스크립트가 하는 일 | 하지 않는 일 |
|---|---|
| 새 활동을 가져오기 | Analysis 섹션 채우기 |
| 훈련 시트 만들기 | 주간 시트 건드리기 |
| Strava에 제목과 설명 쓰기 | 기준 페이스 건드리기 |
| 만든 시트를 커밋하기 | 어떤 의견이든 내놓기 |
판단하기 시작한 스크립트는 맥락 없는 결론을, 아무도 다시 읽지 않는 코드에 굳어 버린 로직으로 찍어내게 된다. 판단한다는 것은 그 주의 부하, 지금의 컨디션, 지난번에 한 말을 함께 붙들고 있는 일이다:그것이 코치의 일이고, 서류 일체를 눈앞에 둔 에이전트가 그 일을 한다.
실질적인 이점은 곧바로 나타난다:에이전트가 돌지 않았을 때(머신이 꺼져 있었거나 API가 죽었거나) 시트는 어쨌든 남아 있다. 잃는 것은 없고, 빠진 것은 댓글뿐이며, 다시 재생하면 그만이다.
같은 방향의 선택이 하나 더 있다:스크립트는 이미 처리한 것을 알기 위한 상태 파일을 두지 않는다. 기준이 되는 것은 Strava의 설명문이다. 비어 있으면 쓰고, 자기 서명이 붙어 있으면 넘어가고, 비어 있지 않은데 서명이 없으면 당신이 쓴 것이니 건드리지 않는다. 로컬 상태 파일은 다른 머신이 무엇을 했는지에 대해 아무 말도 해 줄 수 없었을 것이다. 이 방식이면 두 대의 머신이 나란히 돌아도 서로 밟지 않는다.
저장소에 새겨 두었고 우회해서는 안 되는 분리 규칙이 두 개 더 있다:
- Strava에 공개하는 설명문은 계획의 본문을 절대 베끼지 않는다:내 주간 시트에는 목표 심박과 내부적인 절충이 들어 있고, 공개 활동에 올라갈 이유가 없다.
- 손으로 쓴 설명문은 절대 덮어쓰지 않는다.
활동 아래에 달리는 댓글
목적은 자화자찬이 아니다. 코치의 결론을 저장소를 열지 않고도 휴대폰에서, 활동 바로 아래에서 읽을 수 있다는 것, 그리고 그것이 훈련에 붙은 채 계속 남아 있다는 것이다.
그래서 댓글은 일부러 좁다:결론을 나타내는 이모지, 그것을 떠받치는 숫자, 그리고 다음 훈련에서 무엇이 달라지는지. 250자 남짓이다.
✅ 목표 3'38-3'44에 다섯 개를 평균 3'39, 심박도 블록 전체에서 평평했다. 페이스 표는 유효하다. 금요일은 조깅 그대로:이번 주 여유분은 다 썼다.
심박, 내가 표시해 둔 관찰 항목, 다음 주 거리에 대한 판단이 들어간 긴 버전은 저장소와 메일로 간다. 두 개의 채널, 두 개의 독자, 그 경계를 지키는 것은 프롬프트다.
운영에서만 깨지는 세 가지
이 줄들은 하나하나, 그것이 없을 때 무언가가 깨졌기 때문에 존재한다. 이 글의 나머지보다 배울 것이 많다.
1. 브라우저를 고정하라. 내 Chrome에는 Claude 확장 두 개가 연결되어 있다. 에이전트가 어느 쪽을 잡을지는 보장되지 않고, Strava 세션을 가진 것은 한쪽뿐이다. 결과:두 번에 한 번은 에이전트가 엉뚱한 브라우저 안에서, 로그아웃된 채로, 아무 데도 댓글을 달지 못했다. 기기 ID로 브라우저를 고르는 설정은 세션 사이에 유지되지 않는다:그러니 그것은 프롬프트 안에 들어가야 하고, 어느 것을 고를지 사용자에게 물으러 가는 일은 명시적으로 금지해 두어야 한다. 무인 운전에서 질문은 교착이다.
2. Strava 댓글 입력란에는 maxlength가 없다. 브라우저에는 너무 길게 쓰는 것을 막는 것이 아무것도 없다:제출할 때 거부하는 쪽은 서버다. 600자짜리 멋진 문단을 쓴 에이전트는 그것을 전부 입력하고, "게시"를 누르고, 이해하지 못할 실패를 맞는다. 그래서 프롬프트는 쓰기 전에 간결함을 강제하고, 실패한 경우까지 대비해야 한다:제출이 실패하면 줄여서 다시 올리고, 절대 두 개의 댓글로 쪼개지 않는다.
3. 활동 하나에 코치 댓글 하나. 테스트하려고 이벤트를 다시 재생하면(처음에는 아주 많이 하게 된다) 이 규칙이 없을 때 에이전트는 이미 처리한 활동에 댓글을 쌓는다. 그래서 프롬프트는 쓰기 전에 "댓글" 탭을 읽게 하고, 이미 자기 댓글이 있으면 그냥 넘어가게 한다. 저장소 쪽도 같은 논리다:## Analysis 섹션이 이미 채워져 있으면 다시 쓰지 않는다.
비용
| 조각 | 어디에 | 비용 |
|---|---|---|
| 코치 에이전트 | AgentsRoom을 거쳐 내 머신에서 | 내 Claude 구독 |
| 15분마다 확인 | 켜져 있는 작은 Linux 머신 | 월 5유로 정도, Raspberry Pi면 0 |
| 일지 | 비공개 Git 저장소 | 무료 |
| Strava API | Strava Developer Program | Strava 요금 정책 참고 |
이 구성에는 토큰 단위로 과금되는 API 키가 없다. 가장 과소평가되고 있다고 느끼는 지점이 그것이다:같은 것을 사용량 과금 API 위에 만들었다면 훈련마다 미터기가 돌았을 테고, 나는 아마 계속 쓰지 않았을 것이다.
이번 주말에 만들기
순서대로 정리한 단계다. Strava 계정과 Claude 구독이 이미 있다면 저녁 한 번을 잡으면 된다.
1. 템플릿을 클론해서 내 것으로 만든다.
git clone https://github.com/AgentsRoomDev/running-performance-coach.git my-coach
cd my-coach
rm -rf .git && git init
복사본은 비공개로 만들어라. 훈련 일지에는 건강 데이터가 들어간다:심박, 수면, 부상. 템플릿은 공개되어 있지만 당신의 복사본은 그러면 안 된다.
그다음 이 순서로 채운다:athlete/profile.md(러너로서 당신이 누구인지), athlete/records.md(개인 최고 기록), athlete/constraints.md(실제로 낼 수 있는 시간대), athlete/zones-and-paces.md(기준 페이스), plan/objective.md(대회와 목표), 그다음 CLAUDE.md에서 모든 {{...}} 자리를 바꿔 넣는다.
마지막으로 Claude 에이전트로 저장소를 열고 이렇게 말한다:"CLAUDE.md와 athlete/를 읽고 첫 주를 만들어 줘."
2. Strava를 연결한다.
cp .env.example .env && chmod 600 .env
python3 scripts/strava_oauth.py # 브라우저에서 한 번만 클릭
python3 scripts/strava_sync.py --dry-run
--dry-run은 아무것도 쓰지 않고 무엇이 쓰일지를 보여 준다. 훈련 재구성이 마음에 드는지 확인할 시점이 바로 여기다.
3. AgentsRoom에서 트리거를 만든다. Triggers에서 New trigger:
| 항목 | 값 |
|---|---|
| 종류 | Webhook, 소스는 generic |
| 프롬프트 | docs/trigger-prompt.md의 내용 |
| 역할 / 페르소나 | docs/coach-persona.md |
| 권한 모드 | 자율 |
| 브라우저 접근 | 켜짐 |
AgentsRoom이 URL과 서명용 시크릿을 발급한다. 둘 다 .env에 넣는다:
WEBHOOK_URL=https://agentsroom.dev/api/triggers/t_xxxxxxxxxxxx
WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxx
4. 믿기 전에 테스트한다.
python3 scripts/webhook_replay.py scripts/examples/webhook-session.json --dry-run
python3 scripts/webhook_replay.py scripts/examples/webhook-session.json
이렇게 하면 다음 훈련을 기다리지 않고, 자동 작업의 상태도 건드리지 않고 훈련 하나를 트리거로 흘려보낼 수 있다. ✅ HTTP 202가 보여야 하고, AgentsRoom에 에이전트 탭이 하나 열려야 한다.
5. 15분마다 돌린다.
bash scripts/systemd/install.sh # Linux 서버에서
oneshot 유닛에 타이머를 더한 구성이다:상주 프로세스가 없고, 머신이 꺼져 있는 동안 놓친 회차는 다음 부팅 때 따라잡는다.
늘 켜져 있는 머신이 없다면 이 단계는 건너뛰어도 된다:내킬 때 strava_sync.py를 손으로 돌리거나, 그냥 대화에서 에이전트에게 훈련 내용을 이야기하면 된다. CLAUDE.md의 의식은 똑같이 작동한다. 잃는 것은 자동화이지 코치가 아니다.
달리기를 넘어, 여기서 얻은 것
이 구성에 달리기에만 해당하는 것은 하나도 없다. 이것이 보여 주는 것은, 개인 데이터가 쌓이고 그에 대한 유능한 의견이 있으면 좋겠다 싶은 거의 모든 영역에 다시 쓸 수 있는 패턴이다.
조각은 셋, 그것이 전부다. 기계도 당신도 읽을 수 있는 기억으로서의 Markdown 파일로 된 Git 저장소. 루프를 돌며 조회하고 헛되이 토큰을 태우는 에이전트 대신 에이전트를 깨우는 이벤트. 에이전트가 누구인지, 당신 환경에서 어떻게 일하는지, 지금 당장 무엇을 해야 하는지를 깔끔하게 갈라 놓는 세 개의 설정 층.
"러닝 훈련"을 "은행 거래 내역", "코딩 세션", "혈당 측정값", "독서 노트"로 바꿔 보라:구조는 달라지지 않는다.
자주 묻는 질문
AI 러닝 코치를 만들려면 코딩을 알아야 하나요
터미널에서 명령 하나를 실행하고 텍스트 파일을 편집할 수 있으면 됩니다. 템플릿 저장소는 바로 클론할 수 있고, Python 스크립트는 표준 라이브러리만 씁니다(pip install이 필요 없습니다). 코칭 부분은 Markdown 파일에 평범한 문장을 쓰는 것으로 설정합니다. 진짜 작업은 기술적인 것이 아닙니다:러너로서 내가 어떤 사람이고 무엇을 목표로 하는지 솔직하게 쓰는 일입니다.
한 달에 비용이 얼마나 드나요
에이전트는 이미 쓰고 있는 Claude 구독(Pro 또는 Max)으로 돌아갑니다:토큰 단위로 과금되는 API 키가 없습니다. 여기에 15분마다 Strava를 확인할 작은 상시 가동 머신이 있으면 좋습니다. VPS라면 월 5유로 정도, Raspberry Pi라면 0입니다. 비공개 Git 저장소는 무료입니다. 남는 것은 Strava API인데, 2026년 6월부터 유료 개발자 구독이 필요합니다.
데이터베이스 대신 Git 저장소를 쓰는 이유가 뭔가요
이력이 코치에게도 나에게도 읽히는 것이 되기 때문입니다. 훈련 하나가 Markdown 파일 하나, 계획 변경 하나가 이유가 적힌 커밋 하나입니다. 에이전트는 3주 전에 자기가 처방한 내용을 다시 읽고 그것이 통했는지 확인할 수 있고, 나는 인터페이스를 한 줄도 짜지 않고 휴대폰의 GitHub 앱에서 계획을 봅니다.
webhook이 뭔지 쉽게 설명해 주세요
webhook은 내가 부르러 가는 대신 상대가 나를 불러 주는 서비스입니다. 5분마다 새 것이 있는지 묻는 대신, 프로그램에 웹 주소를 넘겨 두면 그 일이 일어났을 때 저쪽에서 메시지를 보내옵니다. 여기서는 훈련을 가져오는 스크립트가 그 메시지를 AgentsRoom에 보내고, AgentsRoom이 1초 안에 Claude 에이전트를 띄웁니다. 이 구성이 저렴한 이유도 그것입니다:루프를 돌며 조회하는 에이전트는 매 턴 토큰을 태우지만, webhook 트리거는 아무 일도 일어나지 않는 한 비용이 들지 않습니다.
달리기 말고 다른 운동에도 쓸 수 있나요
쓸 수 있습니다. 가져오기는 시계의 랩을 재구성하는데, 자전거도 수영도 랩을 기록합니다. 달라지는 것은 전략 파일과 훈련 카탈로그이고, 둘 다 다시 쓰면 되는 텍스트입니다. 구조(가져오기, webhook, 에이전트, 저장소)는 그대로입니다.
에이전트가 틀려서 내 계획을 망칠 수도 있나요
틀릴 수는 있지만 크게 망치지는 못합니다:에이전트가 쓰는 모든 것은 읽고, 따지고, 되돌릴 수 있는 Git 커밋입니다. CLAUDE.md 파일은 이력을 다시 쓰는 것, 제공하지 않은 데이터를 지어내는 것, 이유를 남기지 않고 계획을 바꾸는 것, 의학적 조언을 하는 것을 명시적으로 금지합니다. 통증이 수상하면 전문가에게 가라고 돌려보냅니다.
템플릿 저장소는 여기 있다:AgentsRoomDev/running-performance-coach. 클론해서 자기 페이스를 채워 넣으면 코치가 생긴다. 에이전트를 깨우는 조각을 보고 싶다면 webhook 트리거 페이지에 설명되어 있고, AgentsRoom은 여기서 내려받는다.
AgentsRoom 다운로드
모든 AI 에이전트를, 모든 프로젝트에서, 하나의 창으로 실행하세요.
컴패니언 앱: 이동 중에도 에이전트를 모니터링
Claude, Codex, Antigravity CLI 또는 다른 AI 공급자를 사용하세요.
버그와 요청을 공개 백로그로 바로 보내세요.
AgentsRoom의 실제 모습.
계속 읽기
Antigravity CLI는 컴퓨터 한 대에 Google 로그인 하나만 유지합니다. 대신 통하는 방법은 이것입니다.
Antigravity CLI에서 Google AI Pro 구독 두 개를 번갈아 쓸 수 없는 이유, 로그인이 실제로 저장되는 위치, 계정 전환 도구가 시스템 키체인에 진짜로 하는 일, 가족 요금제가 할당량을 두 배로 만들어주지 않는 이유, 그리고 여러 계정을 실제로 병렬로 굴리는 유일한 방법.
기사 읽기Claude에 토큰이 얼마나 남았을까요? 그런 숫자는 애초에 없습니다.
Claude 구독 요금제는 토큰 단위로 팔리지 않기 때문에 토큰 잔액을 보여 주는 화면도 없습니다. 실제로 무엇을 측정하는지, 어디서 읽는지, 그리고 아무것도 입력하지 않는 동안에도 왜 줄어드는지, 또 2026년 9월 14일에 주간 사용 기간이 어떻게 바뀌는지 정리했습니다.
기사 읽기이제 코드는 에이전트가 씁니다. 개발자의 일은 이렇게 바뀌었습니다.
코드를 쓰는 일은 고리 여섯 개짜리 사슬에서 고리 하나였고, 에이전트가 가져간 것이 바로 그 고리입니다. 나머지 다섯은 더 무거워졌습니다. 남은 일을 하나씩 짚어 봅니다: 무엇을 만들지 듣기, 정하기, 브리핑하기, 굴리기, 검토하기, 배포하기.
기사 읽기