올해 초, Andrej Karpathy(@karpathy)는 자신의 트레이닝 코드에 에이전트를 투입하고 이틀 동안 실행했습니다. 700번의 실험을 실행해 기준을 통과한 20개를 유지했고, 모델 학습 속도를 11% 향상시켰습니다. 그러고 나서 그는 꽤 흥미로운 말을 했습니다: 저렴하게 평가할 수 있는 모든 지표는 에이전트 swarm에 넘길 수 있다고요.
회신율은 저렴하게 평가할 수 있는 지표입니다. 저는 그 이후로 그 루프가 아웃바운드에 적용될 때 어떤 모습일지 연구하는 데 시간을 보냈습니다.
제 빌드:
Codex가 지난주의 결과를 읽고, 아웃바운드 시스템이 실행하는 점수 및 플레이 파일을 편집하며, 테스트를 실행하고, 풀 리퀘스트를 엽니다. 증거와 점수가 첨부된 플레이북 변경을 제안한 후, 사람이 승인할 때까지 기다립니다. 발송과 병합은 루프 밖에 있습니다.
저는 첫 번째 루프를 몇 번 구축했습니다: 시장을 감지하고, 계정에 점수를 매기고, 신호를 바탕으로 작성하고, 메시지를 확인하고, 결과를 기록하고, 회신을 통해 학습합니다. 이 글은 두 번째 루프, 즉 첫 번째 루프를 편집하는 루프에 관한 것입니다.
그것이 바로 빌드입니다: 시장에서 개선되는 버전 관리 코드로서의 GTM입니다.

Repo
폴더에서 시작합니다. 구조가 중요한 이유는 Codex가 읽고 편집할 수 있는 것만 개선할 수 있기 때문입니다.
1codex-self-improving-outbound/2 AGENTS.md3 README.md4 config/5 scoring.yaml6 plays.yaml7 prompts/8 improve_scoring.md9 improve_prompt.md10 pr_summary.md11 memory/12 outcomes.jsonl13 evals/14 fixtures.yaml15 score.py16 scripts/17 append_outcome.py18 run_codex_step.sh19 propose_improvement.py20 open_pr.sh21 weekly_tune.sh22 examples/23 outcomes.sample.jsonl24 weekly-pr.md
Repo는 의도적으로 단순하게 유지됩니다. config/scoring.yaml에는 어떤 신호가 중요한지 결정하는 규칙이 있습니다. prompts/에는 메시지를 작성하는 플레이가 있습니다. memory/outcomes.jsonl에는 시장의 반응이 기록됩니다. evals/score.py는 제안된 변경 사항이 도움이 되었는지 판단하는 게이트입니다. AGENTS.md는 Codex가 어떤 작업을 수행하기 전에 읽는 법칙입니다.
첫 번째 버전은 오프라인으로 실행합니다. CRM, 인리치먼트, 전송 시스템이 없습니다. 개선 루프는 실제 아웃바운드 머신에 적용되기 전에 로컬 파일에서 먼저 입증되어야 합니다.
Step 1. 법칙을 먼저 작성하세요
점수 파일보다, 프롬프트 파일보다 먼저 AGENTS.md를 작성하세요. 이 파일은 에이전트를 유용하게 유지하고 통제하는 파일입니다.
1# Self-Improving Outbound Rules23당신은 결과로부터 아웃바운드 시스템을 개선합니다.45엄격한 규칙:6- 절대 메시지를 보내지 마세요.7- 절대 실제 사람을 스크래핑하거나 인리치하지 마세요.8- 절대 스스로 병합하지 마세요.9- 이 repo 안의 파일만 편집하세요.10- 한 번에 하나의 개념만 변경하세요.11- 모든 제안된 변경 사항에 대해 memory/outcomes.jsonl의 결과를 인용하세요.12- 변경 사항이 PR이 되기 전에 evals/score.py를 개선하세요.13- 평가가 개선되지 않으면 편집을 되돌리고 중단하세요.1415허용된 편집:16- config/scoring.yaml17- config/plays.yaml18- prompts/*.md1920필수 출력:21- 변경된 파일22- 각 변경 사항에 대한 이유23- 이전 점수24- 이후 점수25- 풀 리퀘스트 요약
법칙의 임무는 하나입니다: 작업 범위를 좁히는 것입니다. 이것이 없으면 Codex는 범위를 확장하여 도움을 주려고 할 것입니다. 더 많은 데이터를 추가하고, 더 많은 파일을 건드리고, 더 많은 도구를 호출하거나, 인간의 통제 하에 있어야 할 단계를 자동화할 것입니다. 여기서 작업은 더 작습니다: 결과를 읽고, 하나의 파일 변경을 제안하고, 그것이 도움이 되었음을 증명한 다음, 기다리는 것입니다.
좋은 결과물이란. PR을 승인하기 전에 법칙을 읽고 Codex가 무엇을 할 수 있었는지 정확히 알 수 있습니다.
실패 지점. 법칙이 규정 준수 문서가 됩니다. AGENTS.md에 목차가 필요하다면 이미 너무 큰 것입니다. 실행 가능한 상태로 유지하세요.
Step 2. 판단을 config로 옮기세요
대부분의 아웃바운드 판단은 누군가의 머릿속에 있습니다. 그러면 팀은 소프트웨어를 구매하고 소프트웨어가 볼 수 없는 결정을 개선해주길 기대합니다.
판단을 파일로 옮기세요.
1signals:2 competitor_comparison:3 weight: 84 reason: "buyer is comparing alternatives"5 implementation_page_visit:6 weight: 67 reason: "buyer is checking whether this can be installed"8 job_repost:9 weight: 510 reason: "role is still open and urgent"11 funding_event:12 weight: 513 reason: "budget or mandate may have changed"14 generic_download:15 weight: 116 reason: "content interest, weak buying intent"1718thresholds:19 draft: 620 human_review: 102122negative_signals:23 student_research: -824 vendor_pitch: -625 competitor: -10
이 파일은 눈에 보이는 가설로 시작합니다. 일반 다운로드가 0으로 계산되어야 한다면, 팀은 정확한 라인을 가리키고 변경할 수 있습니다. 구현 페이지 방문이 생각보다 더 강력한 신호라면, Codex는 diff를 제안하고 이를 정당화하는 결과 행을 보여줄 수 있습니다.
이 로직을 Python 함수에 숨기지 마세요. 규칙이 보이면 팀은 검토하고, 논쟁하고, 판매 판단을 엔지니어링 리팩터로 바꾸지 않고 개선할 수 있습니다.
좋은 결과물이란. 파일이 충분히 작아서 논쟁할 수 있습니다. 5개의 신호가 좋은 첫 번째 버전입니다.
실패 지점. 점수 파일이 잡동사니 서랍이 됩니다. 20개의 신호, 6개의 임계값, 모든 엣지 케이스에 대한 예외 규칙은 개선기가 과적합되게 만듭니다. 좁게 시작하고 결과가 다음 손잡이가 어디에 있어야 하는지 알려주도록 하세요.
Step 3. 결과를 메모리로 작성하세요
가장 중요한 파일은 memory/outcomes.jsonl입니다.
터치당 한 줄씩, 결과가 알려졌을 때 작성합니다:
1{"date":"2026-07-01","account":"Northwind Finance","signal":"competitor_comparison","play":"migration_note","score":8,"outcome":"reply","reason":"asked for migration notes"}2{"date":"2026-07-01","account":"Bluepeak Studio","signal":"generic_download","play":"resource_followup","score":1,"outcome":"no_reply","reason":"content-only intent"}3{"date":"2026-07-02","account":"KiteOps","signal":"implementation_page_visit","play":"implementation_angle","score":6,"outcome":"reply","reason":"asked about implementation timeline"}4{"date":"2026-07-02","account":"Atlas Recruiting","signal":"job_repost","play":"hiring_angle","score":5,"outcome":"bad_fit","reason":"student research request"}
reason 필드가 핵심입니다. no_reply는 거의 아무 정보도 주지 않습니다. content-only intent는 다음 실행에 이 신호가 초안을 받을 가치가 없을 수도 있음을 알려줍니다. bad_fit은 이유가 왜인지 설명할 때만 유용합니다. asked about implementation timeline은 가중치를 바꿀 수 있는 종류의 세부 정보입니다.
개선기를 만들기 전에 검증기를 먼저 구축하세요:
1scripts/append_outcome.py를 빌드하세요.23다음을 허용합니다:4- date5- account6- signal7- play8- score9- outcome: reply | meeting | no_reply | bad_fit | bounced10- reason1112다음을 거부합니다:13- 누락된 필드14- 알 수 없는 outcome15- 빈 reason16- 미래 날짜1718유효한 행을 memory/outcomes.jsonl에 추가하세요.19추가된 행을 출력하세요.
이것이 복리 효과가 시작되는 지점입니다. 대시보드는 캠페인이 저조하다고 알려줄 수 있습니다. 깔끔한 결과 로그는 Codex에게 다음 실행 전에 어떤 신호, 플레이 또는 문구를 변경해야 하는지 알려줄 수 있습니다.
좋은 결과물이란. 일주일 후, 낯선 사람이 파일을 읽고 어떤 신호가 회신을 만들었는지, 어떤 플레이가 부적합한 대화를 만들었는지, 시장이 무시한 내부 선호도는 무엇인지 알 수 있습니다.
실패 지점. 팀이 금요일에 기억에서 결과를 백필합니다. 성공 사례는 살아남고, 부적합 이유는 흐릿해지며, 시스템은 허구에서 학습합니다. 결과가 나왔을 때 즉시 행을 작성하세요.
Step 4. Eval 게이트 구축하기
Codex가 무엇이든 편집하기 전에, 설명할 수 없는 테스트가 필요합니다.
evals/fixtures.yaml을 생성하세요:
1cases:2 - account: Northwind Finance3 signals: [competitor_comparison, implementation_page_visit]4 expected: human_review5 note: "two strong signals on one account"67 - account: Bluepeak Studio8 signals: [generic_download]9 expected: ignore10 note: "content-only intent"1112 - account: KiteOps13 signals: [implementation_page_visit]14 expected: draft15 note: "implementation intent should clear draft threshold"1617 - account: Atlas Recruiting18 signals: [job_repost, student_research]19 expected: ignore20 note: "bad-fit marker cancels the signal"
그런 다음 evals/score.py를 생성하세요:
1evals/score.py를 빌드하세요.23config/scoring.yaml과 evals/fixtures.yaml을 읽으세요.45각 케이스에 대해:61. 모든 신호의 가중치를 합산하세요.72. 부정 신호 패널티를 추가하세요.83. 계정을 라우팅하세요:9 - score >= thresholds.human_review => human_review10 - score >= thresholds.draft => draft11 - 그 외 => ignore124. 라우트를 expected와 비교하세요.1314각 예측을 출력하세요.15최종 정확도를 score=0.00에서 score=1.00으로 출력하세요.16정확도가 1.00일 때만 Exit 0을 출력하세요.
첫 번째 게이트는 이해할 수 있을 정도로 작고 실제 실수를 잡을 수 있을 정도로 예리해야 합니다. 제 첫 번째 실행에서 기준선은 하나의 케이스에서 실패했습니다:
1Northwind Finance: predicted=human_review expected=human_review2Bluepeak Studio: predicted=ignore expected=ignore3KiteOps: predicted=ignore expected=draft4Atlas Recruiting: predicted=ignore expected=ignore5score=0.75
그것은 좋았습니다. 시스템이 초안 임계값 아래에 구현 의도를 두었기 때문에 fixture가 메시지를 받을 자격이 있다고 말한 계정을 무시했습니다. 한 달 동안 계정을 놓친 후보다 테스트에서 잡는 것이 훨씬 낫습니다.
좋은 결과물이란. 하나의 명령이 하나의 숫자를 주고, 실패한 모든 케이스를 쉽게 검사할 수 있습니다.
실패 지점. fixture에 명백한 성공 사례만 포함됩니다. 그러면 모든 무모한 변경이 통과됩니다. 게이트에 추한 케이스를 넣으세요: 약한 의도, 부적합, 무응답, 오래된 신호, 그리고 시스템이 건너뛰었으면 하는 계정들.
Step 5. Codex가 하나의 점수 변경을 제안하도록 하기
이제 Codex가 편집할 수 있습니다.
prompts/improve_scoring.md를 생성하세요:
1당신은 아웃바운드 점수 시스템을 개선합니다.23다음을 읽으세요:4- AGENTS.md5- config/scoring.yaml6- memory/outcomes.jsonl7- evals/fixtures.yaml89당신의 임무:101. 변경되어야 할 하나의 점수 규칙을 찾으세요.112. 이유는 memory/outcomes.jsonl을 인용해야 합니다.123. config/scoring.yaml만 변경하세요.134. python3 evals/score.py를 실행하세요.145. 점수가 개선되면 변경 사항을 유지하세요.156. 점수가 그대로이거나 떨어지면 변경을 되돌리고 중단하세요.1617출력:18- 변경된 정확한 라인19- 그 원인이 된 결과 행20- 이전 점수21- 이후 점수22- 변경 사항이 PR이 되어야 하는지 여부2324prompts를 편집하지 마세요.25새로운 신호를 추가하지 마세요.26전송을 건드리지 마세요.
Repo 래퍼를 통해 실행하세요:
1scripts/run_codex_step.sh improve_scoring
제 개선기의 첫 번째 버전은 유용한 실수를 했습니다. 가장 깔끔해 보이는 회신 신호를 쫓았습니다. competitor_comparison이 작은 결과 로그에서 가장 강력한 회신율을 보였기 때문에 개선기는 그 가중치를 높이려고 했습니다. 평가가 0.75로 유지되었기 때문에 변경이 거부되었습니다.
바로 이것이 게이트가 존재하는 이유입니다. 더 약한 시스템은 합리적으로 들렸기 때문에 그 이야기를 받아들였을 것입니다. 이 시스템은 더 나은 질문을 했습니다: 변경 사항이 알려진 실수를 고쳤습니까?
두 번째 패스는 도움이 되는 가장 작은 편집을 찾았습니다:
1- implementation_page_visit: 42+ implementation_page_visit: 6
평가가 통과했습니다:
1Northwind Finance: predicted=human_review expected=human_review2Bluepeak Studio: predicted=ignore expected=ignore3KiteOps: predicted=draft expected=draft4Atlas Recruiting: predicted=ignore expected=ignore5score=1.00
루프가 유용해지는 순간입니다. 하나의 규칙을, 하나의 이유로 변경하고, fixture에 대해 변경을 증명했습니다.

좋은 결과물이란. 제안된 diff는 지루하고 추적 가능합니다: 한 줄 변경, 하나의 결과 기반 이유 첨부, 하나의 평가 개선.
실패 지점. Codex가 한 번에 세 개의 가중치와 두 개의 프롬프트를 변경합니다. 이제 누구도 어떤 변경이 도움이 되었는지 알 수 없습니다. 법칙을 엄격하게 유지하세요: 제안당 하나의 개념.
Step 6. 프롬프트 파일을 별도로 개선하기
점수는 시스템의 절반일 뿐입니다. 메시지 템플릿도 낡아집니다.
지난 달에 효과가 있었던 라인이 이제는 익숙하게 들리기 시작합니다. 한 세그먼트에서 회신을 얻는 질문이 다른 세그먼트에서는 무시됩니다. 내부적으로 날카롭게 느껴지는 문구가 시장에서 처벌을 받습니다. Codex가 동일한 PR에서 점수와 카피를 섞지 않도록 프롬프트 개선을 별도 레인으로 취급하세요.
config/plays.yaml을 생성하세요:
1plays:2 migration_note:3 prompt_file: prompts/plays/migration_note.md4 use_when:5 - competitor_comparison6 banned_lines:7 - "thought this might be relevant"8 - "quick question"910 implementation_angle:11 prompt_file: prompts/plays/implementation_angle.md12 use_when:13 - implementation_page_visit14 banned_lines:15 - "checking out our solution"16 - "would love to chat"
그런 다음 prompts/improve_prompt.md를 생성하세요:
1당신은 하나의 아웃바운드 플레이를 개선합니다.23다음을 읽으세요:4- AGENTS.md5- config/plays.yaml6- memory/outcomes.jsonl7- 선택한 플레이의 프롬프트 파일89최소 10개의 결과가 있는 하나의 플레이를 선택하세요.1011다음을 찾으세요:12- 긍정적인 결과에 나타난 라인 또는 구조13- no_reply 또는 bad_fit 결과에 나타난 라인 또는 구조14- 금지되어야 할 문구1516해당 플레이의 프롬프트에 하나의 작은 편집을 하세요.1718규칙:19- 점수를 변경하지 마세요.20- 새 플레이를 만들지 마세요.21- 새 채널을 추가하지 마세요.22- 결과 행을 인용하세요.23- 이전 및 이후 지침을 작성하세요.2425그런 다음 카피 eval이 있으면 실행하세요.26카피 eval이 없으면 PR을 review_required로 여세요.
일부 개선 사항은 자동으로 점수를 매길 수 있습니다. 다른 것들은 여전히 감각이 필요합니다. 카피 eval이 없으면 Codex가 프롬프트 편집을 제안할 수 있지만, 편집이 입증된 것처럼 가장하지 않고 검토를 위해 PR을 표시해야 합니다.
좋은 결과물이란. Codex가 "이 문구가 7개의 무응답 결과에 나타났기 때문에 banned_lines에 추가했습니다" 또는 "긍정적인 회신이 문장 하나에 구현 세부 정보를 인용했기 때문에 이를 요구하도록 플레이를 강화했습니다"라고 말합니다.
실패 지점. 개선기가 하나의 메시지가 회신을 받았다는 이유로 전체 어조를 다시 작성합니다. 프롬프트 편집은 직감보다 더 작아야 합니다.
Step 7. 변경 사항을 풀 리퀘스트로 배송하기
이것이 통제 계층입니다. Codex가 파일을 편집하고, 평가를 실행하고, PR 요약을 작성합니다. 사람이 검토하고 병합합니다.

prompts/pr_summary.md를 생성하세요:
1이 아웃바운드 개선 사항에 대한 풀 리퀘스트 요약을 작성하세요.23다음을 포함하세요:41. 무엇이 변경되었나요.52. 왜 변경되었나요, 결과 행을 인용하여.63. 이전 점수.74. 이후 점수.85. 변경된 파일.96. 위험.107. 사람 검토자가 확인해야 할 사항.1112짧게 유지하세요.13변경 사항이 적용되었다고 주장하지 마세요.
scripts/open_pr.sh을 생성하세요:
1#!/usr/bin/env bash2set -euo pipefail34branch="codex/weekly-tune-$(date +%Y-%m-%d)"56git checkout -b "$branch"7git add config prompts evals memory8git commit -m "Codex weekly outbound tune"910body="$(cat outputs/pr-summary.md)"1112python3 scripts/create_pr.py \13 "$branch" \14 "Codex weekly outbound tune" \15 "$body"
PR은 팀원이 작성한 것처럼 읽혀야 합니다:
1변경 사항:2- implementation_page_visit을 4에서 6으로 상향 조정했습니다.34이유:5- KiteOps가 구현 페이지 의도를 보였고 구현 일정에 대해 회신했습니다.6- 이전 점수는 이 계정을 ignore로 라우팅했습니다.78이전:9- eval score 0.751011이후:12- eval score 1.001314검토자 확인:15- 구현 의도가 충분히 구체적인지 확인하세요.16- 일반 다운로드는 낮게 유지하세요.17- 실제 영업 판단과 일치하는 경우에만 병합하세요.
이것이 안전 시스템입니다. Codex는 지루한 작업을 수행합니다. 운영자는 기준을 유지합니다.
좋은 결과물이란. 일주일에 하나의 PR, 작은 diff, 명확한 이유, 통과하는 평가.
실패 지점. 누군가 검토가 마찰처럼 느껴지기 때문에 Codex에 병합 권한을 부여합니다. 그 1분이 시스템이 개선되는 시스템과 표류하는 시스템을 가릅니다.
Step 8. 주기에 맞추기
모든 회신 후에 이것을 실행하지 마세요. 그것이 시스템이 하나의 시끄러운 계정에 과적합되는 방법입니다.
일주일이 지나고 결과가 축적되도록 한 다음 조정하세요.

scripts/weekly_tune.sh을 생성하세요:
1#!/usr/bin/env bash2set -euo pipefail34cd "$(dirname "$0")/.."56python3 evals/score.py || true7scripts/run_codex_step.sh improve_scoring8python3 evals/score.py9scripts/run_codex_step.sh pr_summary > outputs/pr-summary.md10scripts/open_pr.sh
그런 다음 cron:
10 8 * * MON cd ~/codex-self-improving-outbound && scripts/weekly_tune.sh
GitHub Actions를 사용하는 경우 동일한 형태를 유지하세요:
1name: weekly-outbound-tune23on:4 schedule:5 - cron: "0 8 * * 1"6 workflow_dispatch:78jobs:9 tune:10 runs-on: ubuntu-latest11 steps:12 - uses: actions/checkout@v413 - uses: actions/setup-python@v514 with:15 python-version: "3.11"16 - run: pip install -r requirements.txt17 - run: python3 evals/score.py || true18 - run: scripts/weekly_tune.sh
처음 두 번의 튜닝은 수동으로 실행하세요. 모든 diff를 읽으세요. 샘플이 적을 때 Codex가 무엇을 변경하려고 하는지 지켜보세요. 제안이 지루해지면 일정에 넣으세요.
좋은 결과물이란. 증거, diff, 평가 결과와 함께 주간 PR이 나타납니다. 병합, 편집 또는 종료합니다.
실패 지점. 작업이 실행되지만 아무도 검토하지 않고 PR이 쌓입니다. 자기 개선 시스템에도 여전히 하나의 인간 습관이 있습니다: diff를 읽으세요.
클론 앤 런 버전
Repo는 4개의 명령어와 함께 제공되어야 합니다:
1git clone <repo>2cd codex-self-improving-outbound3python3 -m venv .venv4source .venv/bin/activate5pip install -r requirements.txt6python3 evals/score.py7python3 scripts/propose_improvement.py
예상되는 첫 번째 실행:
1score=0.752changed config/scoring.yaml3implementation_page_visit: 4 -> 64score=1.005open PR for human review
오프라인 데모는 파일 계약을 입증합니다. Codex 실행은 편집 루프를 입증합니다. 그 후, 샘플 결과를 자신의 것으로 바꾸고, 신호 이름을 바꾸고, 플레이를 추가하고, 시스템이 다르게 라우팅했으면 하는 계정을 반영하는 fixture를 구축하세요.
전송을 연결하는 것부터 시작하지 마세요. 개선 루프를 입증하는 것부터 시작하세요.
풀 버전: max
이 repo는 수동 계층입니다. 파일, 공개 신호 및 Codex 계획에서 실행됩니다. 모든 규칙이 노출되어 있기 때문에 형태를 가르칩니다.
max.yourmax.ai는 이음새가 숨겨진 동일한 시스템입니다.
직접 연결해야 하는 repo 대신, max는 직접 사용하는 에이전트입니다. 시장의 움직임을 감지하고, 연락할 가치가 있는 사람과 그 이유를 결정하며, 이메일과 LinkedIn을 통해 아웃리치 초안을 작성하여 승인을 받고, 결과에서 지속적으로 개선됩니다.
Repo는 대부분의 팀이 구축하지 않는 자체 튜닝 계층을 보여줍니다: 결과는 제안된 규칙 변경이 되고, 제안된 규칙 변경은 게이트를 통과하며, 인간의 병합이 무엇을 적용할지 결정합니다. max는 동일한 운영 로직을 가져와 관리형 시스템으로 실행합니다.
전체 repo를 원하시면 알려주시면 보내드리겠습니다.





