Initial commit: OpenClaw 워크스페이스 버전관리 시작

설정·스크립트·스킬·문서·큐레이션 메모리 추적.
시크릿(credentials/identity)·런타임 상태(state/logs/sessions/sqlite)·
백업(clobbered/bak)·dream 캐시는 .gitignore로 제외.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-06-04 15:39:41 +09:00
commit fed3526b20
199 changed files with 49671 additions and 0 deletions
+144
View File
@@ -0,0 +1,144 @@
{
"version": 1,
"jobs": [
{
"id": "56d66b54-9a2b-4e94-95d8-fb73efd888ae",
"agentId": "main",
"sessionKey": "agent:main:main",
"name": "오전 브리핑",
"enabled": true,
"createdAtMs": 1774622556732,
"schedule": {
"kind": "cron",
"expr": "0 7 * * *",
"tz": "Asia/Seoul"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "오전 브리핑 HTML 메일 작성. 아래 순서대로 실행:\n\nStep 1: python3 /Users/snowoyh/.openclaw/workspace/scripts/briefing_mail.py prepare morning > /tmp/briefing_morning_prep.json\n JSON 읽어서 already_sent=true면 \"오전 브리핑 이미 발송 완료 (스킵)\" 한 줄 답하고 종료.\n\nStep 2: articles 각 항목에 한국어 평문 설명을 작성. articles[].description에 언론사 리드문(100~500자)이 들어 있음 — 이를 **근거**로 2~3문장 요약. description이 비어 있는 항목만 제목 기반 추정이며, 이 경우 summary 첫 문장을 \"(리드문 없음 — 제목 기반 추정)\"로 시작.\n 작성 기준:\n - 제목을 그대로 옮기지 말고 description 내용을 바탕으로 무슨 일이 왜 생겼고 어떤 영향이 예상되는지 일상어로 풀어서 설명\n - 길이는 필요한 만큼. 2~3문장으로 충분하면 그 정도, 복잡한 사안은 더 길게. 억지 축약/억지 연장 둘 다 하지 말 것\n - 숫자·인용은 description 또는 제목에 명시된 것만 사용 (description 밖 추측·추정 금지)\n - 확신 없는 부분은 \"후속 확인 필요\" 로 마무리\n - '핵심/의미/체크/제 의견' 같은 라벨 구조 사용 금지 — 자연스러운 문장 흐름으로\n - 스크립트가 유사 뉴스는 이미 걸러내지만 혹시 남아 있으면 summary 첫 문장에 \"동일 사안 다른 매체 보도\"로 표기하고 짧게 처리\n\nStep 3: prep JSON을 복사해서 articles 배열의 각 원소에 \"summary\": \"<평문 설명 문자열>\" 필드를 추가한 augmented JSON을 Write 도구로 /tmp/briefing_morning_augmented.json 에 저장 (나머지 필드는 prep 그대로 보존). summary는 반드시 단일 문자열 (여러 단락은 '\\n'로 구분 가능).\n\nStep 4: python3 /Users/snowoyh/.openclaw/workspace/scripts/briefing_mail.py compose --input /tmp/briefing_morning_augmented.json > /tmp/briefing_morning_body.html\n\nStep 5: python3 /Users/snowoyh/.openclaw/workspace/scripts/briefing_mail.py send morning --subject \"[오전 브리핑] {date}\" --body-file /tmp/briefing_morning_body.html --html\n ({date}는 prep JSON의 date 값)\n\nStep 6: 성공 시 \"오전 브리핑 HTML 발송 완료 (뉴스 N건 요약)\" 한 줄. 실패 시 exact error 포함해 한국어로 보고.",
"timeoutSeconds": 900
},
"delivery": {
"mode": "none"
},
"deleteAfterRun": false,
"state": {}
},
{
"id": "9d2c105f-02a7-416c-9ca3-8aaa0dd522bd",
"agentId": "main",
"sessionKey": "agent:main:main",
"name": "오후 브리핑",
"enabled": true,
"createdAtMs": 1774622556739,
"schedule": {
"kind": "cron",
"expr": "0 19 * * *",
"tz": "Asia/Seoul"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "오후 브리핑 HTML 메일 작성. 아래 순서대로 실행:\n\nStep 1: python3 /Users/snowoyh/.openclaw/workspace/scripts/briefing_mail.py prepare evening > /tmp/briefing_evening_prep.json\n JSON 읽어서 already_sent=true면 \"오후 브리핑 이미 발송 완료 (스킵)\" 한 줄 답하고 종료.\n\nStep 2: articles 각 항목에 한국어 평문 설명을 작성. articles[].description에 언론사 리드문(100~500자)이 들어 있음 — 이를 **근거**로 2~3문장 요약. description이 비어 있는 항목만 제목 기반 추정이며, 이 경우 summary 첫 문장을 \"(리드문 없음 — 제목 기반 추정)\"로 시작.\n 작성 기준:\n - 제목을 그대로 옮기지 말고 description 내용을 바탕으로 무슨 일이 왜 생겼고 어떤 영향이 예상되는지 일상어로 풀어서 설명\n - 길이는 필요한 만큼. 2~3문장으로 충분하면 그 정도, 복잡한 사안은 더 길게. 억지 축약/억지 연장 둘 다 하지 말 것\n - 숫자·인용은 description 또는 제목에 명시된 것만 사용 (description 밖 추측·추정 금지)\n - 확신 없는 부분은 \"후속 확인 필요\" 로 마무리\n - '핵심/의미/체크/제 의견' 같은 라벨 구조 사용 금지 — 자연스러운 문장 흐름으로\n - 스크립트가 유사 뉴스는 이미 걸러내지만 혹시 남아 있으면 summary 첫 문장에 \"동일 사안 다른 매체 보도\"로 표기하고 짧게 처리\n\nStep 3: prep JSON을 복사해서 articles 배열의 각 원소에 \"summary\": \"<평문 설명 문자열>\" 필드를 추가한 augmented JSON을 Write 도구로 /tmp/briefing_evening_augmented.json 에 저장 (나머지 필드는 prep 그대로 보존). summary는 반드시 단일 문자열 (여러 단락은 '\\n'로 구분 가능).\n\nStep 4: python3 /Users/snowoyh/.openclaw/workspace/scripts/briefing_mail.py compose --input /tmp/briefing_evening_augmented.json > /tmp/briefing_evening_body.html\n\nStep 5: python3 /Users/snowoyh/.openclaw/workspace/scripts/briefing_mail.py send evening --subject \"[오후 브리핑] {date}\" --body-file /tmp/briefing_evening_body.html --html\n ({date}는 prep JSON의 date 값)\n\nStep 6: 성공 시 \"오후 브리핑 HTML 발송 완료 (뉴스 N건 요약)\" 한 줄. 실패 시 exact error 포함해 한국어로 보고.",
"timeoutSeconds": 900
},
"delivery": {
"mode": "none"
},
"deleteAfterRun": false,
"state": {}
},
{
"id": "08e9a978-4897-4adc-b9f1-48e19fd96fb0",
"agentId": "budget",
"sessionKey": "agent:budget:main",
"name": "월간 결산 (자산 변동 메일 + 골디 텔레그램)",
"enabled": true,
"createdAtMs": 1776936832705,
"schedule": {
"kind": "cron",
"expr": "0 5 1 * *",
"tz": "Asia/Seoul"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "월간 결산 자동 처리 (매월 1일). 오늘이 Asia/Seoul 기준 매월 1일인지 확인하고, 1일이면 아래 명령을 정확히 한 번 실행한다.\n\npython3 /Users/snowoyh/.openclaw/agents/budget/workspace/skills/monthly-settlement/scripts/monthly_settlement.py\n\n이 스크립트가 budget inbox의 securities_balance envelope 검증·후잉 자동 reconcile·processed/failed 이동·월간 스냅샷 저장·메일과 골디 텔레그램 보고를 모두 담당한다. 스크립트 실행 전에 inbox 파일을 직접 이동하거나 별도 처리하지 않는다. --dry-run 또는 --no-send를 붙이지 않는다.\n\n실행 후 stdout/stderr의 핵심 결과를 확인한다. 실패하면 에러 내용을 골디 텔레그램으로 보고하고, 성공하면 추가 메시지는 보내지 않는다(스크립트 자체 보고와 중복 방지).",
"timeoutSeconds": 300
},
"delivery": {
"mode": "none"
},
"deleteAfterRun": false,
"state": {}
},
{
"id": "80052b62-1c7a-4f8e-91c9-222ae4c3c045",
"agentId": "stock",
"sessionKey": "agent:stock:telegram:direct:8443122995",
"name": "비하이브 종목분석 요약",
"enabled": true,
"deleteAfterRun": false,
"createdAtMs": 1778106343263,
"schedule": {
"kind": "cron",
"expr": "0 7,12,18 * * 1-5",
"tz": "Asia/Seoul"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "비하이브투자자문 신규 '종목분석' 영상 점검 → 검증 성공 시에만 watchlist 저장 + 이메일 발송 + 텔레그램 요약.\n\nStep 1: 신규 영상 메타데이터 fetch (자막은 stdout에 포함되지 않음 — FETCH_CACHE에만 저장됨).\npython3 /Users/snowoyh/.openclaw/agents/stock/workspace/scripts/behive_youtube_digest.py fetch\n\nStep 2: 배열이 비어 있으면 아무 발송도 하지 말고 \"신규 종목분석 영상 없음\" 한 줄 답하고 종료.\n\nStep 3: 각 영상마다 자막을 먼저 꺼내 읽는다:\npython3 /Users/snowoyh/.openclaw/agents/stock/workspace/scripts/behive_youtube_digest.py transcript <VIDEO_ID>\n\n중요: 영상 하나에 종목이 여러 개 나올 수 있다. title의 모든 #종목 태그와 자막 내용을 함께 보고, 종목별 JSON을 각각 따로 만든 뒤 같은 VIDEO_ID로 여러 번 save해도 된다. 종목이 2개면 save도 2번, 3개면 3번 해야 한다. 첫 번째 태그만 저장하고 끝내면 안 된다.\n\n그 자막을 바탕으로 아래 스키마의 JSON을 종목별로 생성해서 save에 전달.\n\nJSON 스키마:\n{\n \"stock\": \"종목명 한 단어 (영상 title의 #태그들 또는 자막 본문에서 식별된 실제 분석 종목명)\",\n \"target\": {\"raw\": \"원문 가격 표현\", \"low\": 숫자, \"high\": 숫자},\n \"buy\": {\"raw\": \"원문 가격 표현\", \"primary\": 숫자, \"levels\": [숫자,...]},\n \"stop\": {\"raw\": \"원문 가격 표현\", \"value\": 숫자},\n \"upside_pct\": 숫자,\n \"summary\": [\"불릿1\", \"불릿2\", \"...\"],\n \"notes\": [\"기타1\", \"...\"]\n}\n\n규칙:\n- 가격이 단일값이면 low=high, primary만 기재. 범위면 low/high 모두 기재\n- 숫자는 원(KRW) 단위 정수. \"13,000원\" → 13000. \"3만원대\" → 30000\n- 가격 정보가 자막에 명시되지 않으면 해당 필드는 {\"raw\": \"언급 없음\"}만 남기고 숫자 키 생략\n- target 또는 buy 가격이 없으면 upside_pct는 null\n- stop(손절가)은 반드시 buy(매입가)보다 낮아야 함. 영상에서 매입가 위에 있는 지지선/경계선 수치가 언급되면 stop이 아니라 notes에 \"지지선 XXX원 이탈 시 하방 열림\" 형태로 기록하고 stop은 {\"raw\": \"언급 없음\"}으로 둘 것\n- transcript_status가 'ok'가 아니면 summary 첫 불릿을 \"(자막 수집 불가 — 제목 기반 추정)\"로 시작\n- 여러 종목 영상이면 각 종목 summary/notes가 서로 섞이지 않게 종목별 문단만 분리해서 저장\n\n필수 검증(하나라도 실패하면 전체 발송 금지):\n- 각 영상의 title #태그 개수와 실제 save할 종목 수를 먼저 대조한다.\n- 자막/제목상 다종목 영상인데 종목 수가 모자라거나, 종목별 내용이 뒤섞여 분리가 불확실하면 실패로 종료한다.\n- 검증이 끝나기 전에는 save/email/notify를 호출하지 않는다.\n- 이미 일부 save한 뒤 불일치가 발견되면 email/notify는 호출하지 말고 실패로 종료한다.\n- \"일단 보내고 정정\" 금지.\n\nStep 4: 모든 영상이 검증을 통과한 경우에만 save 실행.\nprintf '%s' '<JSON>' | python3 /Users/snowoyh/.openclaw/agents/stock/workspace/scripts/behive_youtube_digest.py save <VIDEO_ID>\n\nStep 5: 모든 save 성공 후에만 이메일 발송.\npython3 /Users/snowoyh/.openclaw/agents/stock/workspace/scripts/behive_youtube_digest.py email <VIDEO_ID1> <VIDEO_ID2> ...\n\nStep 6: 이메일 성공 후에만 텔레그램 요약 발송.\npython3 /Users/snowoyh/.openclaw/agents/stock/workspace/scripts/behive_youtube_digest.py notify <VIDEO_ID1> <VIDEO_ID2> ...\n\nStep 7: 종료 시 성공이면 \"이메일 N건 + 텔레그램 알림 완료 (종목명들)\", 실패면 실패 내역만 한 줄 보고.",
"timeoutSeconds": 900
},
"delivery": {
"mode": "none"
},
"failureAlert": {
"after": 1,
"channel": "telegram",
"to": "8443122995",
"mode": "announce",
"accountId": "stock"
},
"state": {}
},
{
"id": "ae946886-5829-4d45-a03a-72e70ed371cd",
"agentId": "main",
"sessionKey": "agent:main:telegram:direct:8443122995",
"name": "Gmail 라벨 분류",
"enabled": true,
"deleteAfterRun": false,
"createdAtMs": 1778461171202,
"schedule": {
"kind": "cron",
"expr": "0 1 * * *",
"tz": "Asia/Seoul"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "Gmail 라벨 자동 분류 작업. 다음 명령을 실행하고 결과만 한 줄로 보고:\npython3 /Users/snowoyh/.openclaw/workspace/scripts/gmail_label_classify.py\n\n성공 시 \"Gmail 라벨 분류 완료 (대상 N건, 신규 라벨 M건)\" 형식으로 요약. 실패 시 exact error 포함.",
"timeoutSeconds": 300
},
"delivery": {
"mode": "none"
},
"failureAlert": {
"after": 1,
"channel": "telegram",
"to": "8443122995",
"mode": "announce",
"accountId": "default"
},
"state": {}
}
]
}