vibe-mod 실증 검증 보고서
Devvit 공식 문서(reddit/devvit-docs GitHub) verbatim cross-reference · 4 전문가 plan 클레임 전수 검증
1. 검증 요약
Devvit.addTrigger(...) closure 패턴은 구버전 @devvit/public-api. 현재 공식은 @devvit/web — devvit.json에 endpoint 선언 + Hono/Express HTTP 라우트로 처리. 아키텍처 다이어그램·코드 샘플 모두 업데이트 필요.
1.1 11개 클레임 검증 결과
| # | 원본 plan 클레임 | 판정 | verbatim 근거 |
|---|---|---|---|
| 1 | Devvit apps can call external HTTPS APIs via fetch | ✅ | "Make requests to allow-listed external domains" |
| 2 | Claude Haiku 4.5를 LLM으로 사용 | ❌ | "the only AI providers we allow are OpenAI and Google Gemini... Requests to use any other AI provider will be denied" |
| 3 | onPostSubmit / onCommentSubmit 트리거 사용 | ✅ | 모든 트리거 verbatim enumerate |
| 4 | Devvit Redis (1000 cmd/s, 500MB) | ✅+ | 실제는 40,000 cmd/s (훨씬 관대), 500MB 스토리지 정확 |
| 5 | Sorted sets (zAdd/zRange) 지원 | ✅ | verbatim — zAdd/zRange/zRem/zScore/zRank/zIncrBy/zScan/zRemRangeBy* |
| 6 | Redis transactions (multi/exec/watch) | ✅ | verbatim — max 20 concurrent transactions, 5s timeout |
| 7 | Scheduler cron + one-shot | ✅ | verbatim — scheduler.runJob({cron|runAt}) |
| 8 | Settings with isSecret (App scope) | ✅ | verbatim — global+subreddit scopes, isSecret 지원, CLI로만 설정 가능 |
| 9 | Reddit API: removePost, modMail.create, setUserFlair 등 | ✅* | 메서드 전부 존재 (단 호출 패턴은 comment.remove() 객체-메서드형으로 변경) |
| 10 | Devvit.addTrigger() closure-style handler | ⚠️ | 구버전 패턴. 현 공식: devvit.json에 endpoint + HTTP route |
| 11 | Devvit.addCustomPostType + addSettings | ⚠️ | 현 공식은 devvit.json 설정 + 서버 endpoint 패턴 |
전체 판정: 9/11 fully feasible, 2/11 require pattern modernization. 컨셉은 흔들리지 않음.
2. 🚨 결정적 변경: Claude → OpenAI (또는 Gemini)
2.1 정책 verbatim
At this time, the only AI providers we allow are OpenAI and Google Gemini:
- api.openai.com
- generativelanguage.googleapis.com
Requests to use any other AI provider will be denied. — docs/capabilities/server/http-fetch-policy.md, section "AI providers"
2.2 LLM 재선정
| 모델 | 속도 | 비용 (입력/출력 per 1M tokens) | JSON 모드 | 판정 |
|---|---|---|---|---|
| OpenAI gpt-4o-mini | ~3-5s | $0.15 / $0.60 | ✅ response_format:{type:'json_object'} | 최우선 픽 |
| OpenAI gpt-4o | ~5-8s | $2.50 / $10 | ✅ | 고비용, 불필요 |
| Gemini 2.0 Flash | ~2-4s | $0.10 / $0.40 (대략) | ✅ structured output | 대안 |
| Gemini 2.5 Pro | ~5-8s | $1.25 / $5 | ✅ | 고비용 |
| ~3-5s | $1 / $5 | — | 정책 거부 |
2.3 신규 비용 추정 (gpt-4o-mini 기준)
- 1 룰 컴파일: 800 in + 400 out ≈
$0.00012 + $0.00024 = $0.00036(≈ 0.36¢ → Haiku의 8배 cheaper) - 50 컴파일/sub/day × 30일 × 1,000 sub = 150만 컴파일 × $0.00036 = $540/월
- 실제로 sub당 일평균 5 컴파일 정도면 → $54/월 (1,000 sub 운영)
2.4 영향 — 아키텍처 변경 사항
- devvit.json:
permissions.http.domains에"api.openai.com"(또는"generativelanguage.googleapis.com") 추가 - global settings:
openaiApiKey(isSecret: true). 공식 settings-and-secrets 문서에 정확히 이 패턴이 예시로 등장 → vibe-mod-shaped 사례 - System prompt + JSON schema: OpenAI JSON 모드 활용 (Zod validator 그대로 유지)
- 비용 절감: Anthropic보다 8배 저렴 → 50 compiles/day rate limit 완화 가능 (예: 100/day)
2.5 공식 sample — vibe-mod와 동일 패턴
// devvit.json (공식 settings-and-secrets.mdx 예시 — 그대로 차용 가능)
{
"settings": {
"global": {
"openaiApiKey": {
"type": "string",
"label": "OpenAI API Key",
"isSecret": true,
"defaultValue": ""
}
}
},
"permissions": {
"http": { "enable": true, "domains": ["api.openai.com"] }
}
}
// server/index.ts (공식 예시 그대로)
import { settings } from '@devvit/web/server';
app.post('/api/generate', async (c) => {
const apiKey = await settings.get('openaiApiKey');
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
body: JSON.stringify({ model: 'gpt-4o-mini', messages: [...] }),
});
...
});
3. API / Primitive 검증 매트릭스
3.1 Triggers (verbatim from docs/capabilities/server/triggers.mdx)
| vibe-mod에서 사용 | 공식 이름 | 판정 |
|---|---|---|
| 새 포스트 → 룰 평가 | onPostSubmit | ✅ |
| 새 댓글 → 룰 평가 | onCommentSubmit or onCommentCreate | ✅ |
| 리포트 임계점 → 액션 | onPostReport / onCommentReport | ✅ |
| 모드 액션 learning (v0.2) | onModAction | ✅ |
| 최초 install 시 seed | onAppInstall | ✅ |
| 버전 업그레이드 시 migration | onAppUpgrade | ✅ |
등록 방법 (verbatim):
// devvit.json
"triggers": {
"onAppUpgrade": "/internal/on-app-upgrade",
"onPostSubmit": "/internal/on-post-submit",
"onCommentCreate": "/internal/on-comment-create"
}
// server/index.ts (Hono)
app.post('/internal/on-post-submit', async (c) => {
const input = await c.req.json<OnPostSubmitRequest>();
const post = input.post;
const author = input.author;
// ... evaluate rules
return c.json<TriggerResponse>({ status: 'ok' });
});
3.2 Redis
| vibe-mod 사용 | 공식 지원 | 한계 |
|---|---|---|
get / set / del (rules:active) | ✅ | — |
zAdd / zRange / zRemRangeByScore (audit) | ✅ | BYSCORE LIMIT count 기본 1000/call |
hSet / hGet / hGetAll (rules:meta) | ✅ | — |
incrBy (counters:compile) | ✅ | — |
expire (rollback TTL 30일) | ✅ | — |
multi / exec / watch (atomic audit write) | ✅ | max 20 concurrent tx, 5s exec timeout |
| 전체 cmd/s | 40,000 | 원본 plan은 1,000으로 추정 → 실제 40배 관대 |
| 스토리지 | 500 MB / installation | 정확 |
| max request size | 5 MB | — |
3.3 Scheduler
| vibe-mod 사용 | 공식 지원 | 한계 (실제) |
|---|---|---|
| daily audit retention (cron) | ✅ cron: "0 3 * * *" | 최대 10 live recurring actions / install |
| one-shot dry-run replay | ✅ scheduler.runJob({runAt: new Date(...)}) | 60 runJob()/min, 60 deliveries/min |
| seconds-level (<= 1 min) | ✅ "Faster scheduler" — cron: "*/30 * * * * *" | experimental |
| cancelJob / listJobs | ✅ | — |
scheduler는 install당 10 recurring 한도라 매 액션마다 새 job 등록 불가능. 대신 redis.set(rollback:<actionId>, ...).expire(2_592_000)로 30일 TTL 부여. 만료되면 자동 삭제. (원본 plan과 동일 결론)
3.4 Settings (정확히 vibe-mod 시나리오 그대로)
공식 settings-and-secrets.mdx에 "OpenAI API Key with isSecret: true" 예시가 그대로 등장. vibe-mod의 LLM 통합 패턴이 정식 권장 패턴임을 의미.
3.5 HTTP Fetch
| 요구사항 | 공식 답 |
|---|---|
| 외부 API 호출 가능? | ✅ permissions.http.domains 선언 시 |
| HTTPS only | ✅ |
| Methods | GET, POST, PUT, DELETE, OPTIONS, PATCH |
| Timeout | 30s |
| Global allowlist에 OpenAI | ✅ api.openai.com |
| Global allowlist에 Anthropic | ❌ + 정책상 거부 |
| 도메인 신청 후 승인 시간 | "reviewed separately and can add time" |
| Terms+Privacy Policy | 필수 (앱 등록 폼에 업로드) |
4. 패턴 전환: @devvit/public-api → @devvit/web
4.1 변경 요약
| 요소 | 원본 plan (구버전) | 실제 공식 (현재) |
|---|---|---|
| 패키지 | @devvit/public-api | @devvit/web/server + @devvit/web/shared |
| 설정 파일 | devvit.yaml | devvit.json |
| 트리거 등록 | Devvit.addTrigger('PostSubmit', (event,ctx)=>{...}) | devvit.json에 "triggers":{"onPostSubmit":"/internal/on-post-submit"} + HTTP route |
| 커스텀 포스트 | Devvit.addCustomPostType({render}) | devvit.json + Devvit Blocks (interactive-posts) — 더 복잡 |
| 메뉴 액션 | Devvit.addMenuItem({onPress}) | devvit.json의 "menu":{"items":[{"endpoint":"/internal/menu/..."}]} |
| 설정 | Devvit.addSettings() | devvit.json의 "settings":{"global":{...},"subreddit":{...}} |
| 스케줄러 job 등록 | Devvit.addSchedulerJob() | devvit.json의 "scheduler":{"tasks":{...}} + endpoint |
| HTTP 서버 프레임워크 | 없음 (closure) | Hono 또는 Express (선택) |
| Reddit API 클라이언트 | context.reddit | import {reddit} from '@devvit/reddit' 또는 '@devvit/web/server' |
| Reddit 액션 패턴 | context.reddit.removePost(id) | const c = await reddit.getCommentById(id); await c.remove(); |
4.2 신 패턴의 장점
- HTTP routes = 표준 웹 패턴, 디버깅 쉬움
devvit.json이 single source of truth- Hono/Express 선택 자유
- Validation endpoint 같은 declarative 패턴 지원
5. 공식 Mod Tool 패턴 (quickstart-mod-tool.md verbatim)
5.1 공식 권장 구조: Menu Action + Form
quickstart의 Comment Mop 예시가 정확히 vibe-mod의 base pattern입니다.
// devvit.json
{
"menu": {
"items": [
{
"label": "Compose rule",
"description": "Write a moderation rule in English",
"forUserType": "moderator",
"location": "subreddit",
"endpoint": "/internal/menu/compose-rule"
}
]
},
"forms": {
"ruleComposerForm": "/internal/form/compose-rule-submit"
},
"permissions": {
"reddit": { "enable": true, "scope": "moderator" },
"redis": true,
"http": { "enable": true, "domains": ["api.openai.com"] }
},
"triggers": {
"onPostSubmit": "/internal/on-post-submit",
"onAppInstall": "/internal/on-app-install"
},
"scheduler": {
"tasks": {
"audit-retention": {
"endpoint": "/internal/scheduler/audit-retention",
"cron": "0 3 * * *"
},
"dry-run-replay": {
"endpoint": "/internal/scheduler/dry-run-replay"
}
}
},
"settings": {
"global": {
"openaiApiKey": { "type": "string", "label": "OpenAI Key", "isSecret": true }
},
"subreddit": {
"dryRunOnly": { "type": "boolean", "label": "Dry-run mode (no actions)", "defaultValue": true }
}
}
}
5.2 코드 샘플 — vibe-mod 핵심 부분 (실현 가능 입증)
// server/index.ts
import { Hono } from 'hono';
import type {
MenuItemRequest, UiResponse,
OnPostSubmitRequest, TriggerResponse,
SettingsValidationRequest
} from '@devvit/web/shared';
import { reddit, settings, scheduler } from '@devvit/web/server';
import { redis } from '@devvit/redis';
const app = new Hono();
// 1. Mod opens "Compose rule" menu → form
app.post('/internal/menu/compose-rule', async (c) => {
return c.json<UiResponse>({
showForm: {
name: 'ruleComposerForm',
form: {
title: 'Write a moderation rule',
acceptLabel: 'Compile + Preview',
fields: [
{ name: 'rule', label: 'Your rule (English)', type: 'paragraph', defaultValue: '' },
{ name: 'shadow', label: 'Shadow mode (recommended)', type: 'boolean', defaultValue: true }
]
}
}
});
});
// 2. Form submit → call OpenAI → store as draft
app.post('/internal/form/compose-rule-submit', async (c) => {
const { rule, shadow } = await c.req.json<{rule:string,shadow:boolean}>();
const apiKey = await settings.get('openaiApiKey');
const llmResp = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
body: JSON.stringify({
model: 'gpt-4o-mini',
response_format: { type: 'json_object' },
messages: [
{ role: 'system', content: VIBE_MOD_SYSTEM_PROMPT }, // ~600 tok, schema-defining
{ role: 'user', content: rule }
],
max_tokens: 700, temperature: 0.1
})
});
const { choices } = await llmResp.json();
const compiledRule = JSON.parse(choices[0].message.content);
// Validate against Zod schema (action whitelist, predicate schema)
const validated = RuleSchema.parse(compiledRule);
// Store as draft
await redis.set('rules:draft', JSON.stringify(validated));
// Schedule dry-run replay
await scheduler.runJob({
name: 'dry-run-replay',
runAt: new Date(),
data: { ruleId: validated.id }
});
return c.json<UiResponse>({
showToast: { text: 'Rule compiled. Dry-run running…', appearance: 'success' }
});
});
// 3. Trigger: PostSubmit → evaluate active rules → take action
app.post('/internal/on-post-submit', async (c) => {
const { post, author } = await c.req.json<OnPostSubmitRequest>();
const activeRulesJson = await redis.get('rules:active');
if (!activeRulesJson) return c.json<TriggerResponse>({ status: 'ok' });
const activeRules = JSON.parse(activeRulesJson);
const factBag = await buildFactBag(post, author); // account age, karma, etc.
for (const rule of activeRules.rules) {
if (!rule.enabled) continue;
if (evaluatePredicate(rule.when, factBag)) { // pure deterministic
for (const action of rule.then) {
await executeAction(action, post, author);
await writeAuditEntry(rule.id, action, post.id);
}
}
}
return c.json<TriggerResponse>({ status: 'ok' });
});
// 4. Helper: deterministic action executor
async function executeAction(action: Action, post: any, author: any) {
const allowed = ['remove', 'lock', 'flair', 'modmail', 'report'];
if (!allowed.includes(action.action)) throw new Error('forbidden action');
switch (action.action) {
case 'remove': {
const p = await reddit.getPostById(post.id);
await p.remove();
break;
}
case 'lock': {
const p = await reddit.getPostById(post.id);
await p.lock();
break;
}
case 'modmail': {
await reddit.modMail.create({
subredditName: post.subreddit,
subject: action.params.subject,
body: action.params.body
});
break;
}
// ... etc
}
}
5.3 검증된 사실: 무료 호스팅
"Notice that you don't need to worry about running costs for your mod tool, because Reddit hosts all Devvit applications for free." — quickstart-mod-tool.md
→ 인프라 비용 = $0. LLM API 비용만 부담 (OpenAI에 직접 결제).
6. HTTP Fetch + AI 정책 verbatim
6.1 Global allowlist (verbatim)
다음 도메인은 모든 앱에서 즉시 호출 가능 (단, permissions.http.domains에 여전히 명시해야 함):
example.com, site.api.espn.com, cdn.espn.com, discord.com,
api.polygon.io, api.massive.com, polygon.io, slack.com,
lichess.org, api.telegram.org, commentanalyzer.googleapis.com,
language.googleapis.com, statsapi.mlb.com,
api.openai.com, ← ✅ vibe-mod 사용
api.scryfall.com, api.nasa.gov,
api.sportradar.us, api.sportradar.com, random.org,
generativelanguage.googleapis.com, ← ✅ Gemini 대안
youtube.googleapis.com, api.weather.gov, wikipedia.org,
finance.yahoo.com, api.twitter.com, api.petfinder.com,
fonts.googleapis.com, nytimes.com, npr.org, propublica.org,
pbs.org, i.giphy.com, chessboardjs.com
6.2 AI providers 정책 (verbatim, 강조)
### AI providers
At this time, the only AI providers we allow are OpenAI and Google Gemini:
-api.openai.com
-generativelanguage.googleapis.com
Requests to use any other AI provider will be denied. — docs/capabilities/server/http-fetch-policy.md
6.3 도메인 신청 카테고리
- API 제공 서비스 (e.g.
api.openai.com) — public docs + valid use case면 승인 가능 - 제한적 클라우드 (
supabase.com, firebase.com, s3.amazonaws.com등) — 예외 승인 가능, 단 정책 준수 - 개인 도메인 — 거부됨. Devvit 서버로 해결 불가능한 use case만 예외
7. Redis 실제 한계
| 제약 | 실제 값 (공식) | 원본 plan | 차이 |
|---|---|---|---|
| Max commands per second | 40,000 | 1,000 | 40× 관대 |
| Max request size | 5 MB | 5 MB | 정확 |
| Max storage | 500 MB | 500 MB | 정확 |
| Pipelining | 지원 안 함 | — | — |
| Sets | sorted sets만 지원 | — | — |
| Key listing | 지원 안 함 (KEYS *) | — | — |
| Lua scripts | 지원 안 함 | — | — |
| Transactions | 최대 20 concurrent, 5s exec timeout | — | — |
redisCompressed 클라이언트로 큰 룰 번들(rules:active JSON) 자동 압축 가능. v0.2에서 검토.
8. Scheduler 실제 한계
| 제약 | 실제 값 | vibe-mod 영향 |
|---|---|---|
| Max live recurring actions | 10 / installation | cron 작업은 audit-retention 1개만 사용 → 9 여유 |
| Creation rate (runJob) | 60/min | dry-run 1회 = 1 job, 충분 |
| Delivery rate | 60/min | — |
| Min cron 간격 | 1 min (또는 sec-granular experimental) | — |
| Single job timeout | 30s (HTTP fetch limit과 동일) | dry-run replay는 chunking + daisy-chain 필요 |
9. Reddit API 메서드 검증 (RedditAPIClient verbatim)
모든 vibe-mod 필요 메서드가 공식 API에 존재 확인. (docs/api/redditapi/RedditAPIClient/classes/RedditAPIClient.md)
| vibe-mod 사용 | 공식 메서드 | 호출 패턴 |
|---|---|---|
| Post 제거 | post.remove() (객체 메서드) | const p = await reddit.getPostById(id); await p.remove(); |
| Comment 제거 | comment.remove() | quickstart에 정확히 이 패턴 사용 |
| Post/Comment 승인 | reddit.approve() | thing ID로 호출 |
| Lock | post.lock() / comment.lock() | 객체 메서드 |
| ModMail 생성 | reddit.modMail | ModMailService 객체 |
| PM 발송 | reddit.sendPrivateMessage(options) | — |
| 유저 조회 | reddit.getUserByUsername(name) | account age 계산용 |
| Ban (whitelist 외) | reddit.banUser(options) | 2-step confirmation 필요 |
| Mute | reddit.muteUser(options) | — |
| Mod note | reddit.addModNote(options) | — |
| Removal note | reddit.addRemovalNote(options) | — |
| Removal reason | reddit.addSubredditRemovalReason() | — |
| User flair 설정 | reddit.createUserFlairTemplate | flair template create |
| 모드큐 조회 | reddit.getModQueue() | dry-run preview용 |
| 최근 포스트 조회 | reddit.getNewPosts() | dry-run preview용 |
| 모드 로그 조회 | reddit.getModerationLog() | v0.2 "learn from mods" |
reddit permission in your app." — 우리는 OAuth 토큰 rotation 등에 신경 쓸 필요 없음.
10. Day-0 CLI Smoke Test 결과
10.1 환경 검증
| 요소 | 결과 | 요구사항 |
|---|---|---|
| Node.js | v24.15.0 (사용자 머신) | 22.2.0+ ✅ |
| npx | 11.12.1 | — |
@devvit/cli 최신 | v0.12.22 (npm) | — |
| CLI 실행 가능 | npx @devvit/cli/0.12.22 darwin-arm64 정상 응답 | ✅ |
10.2 실제 devvit new 시도 제약
"Go to https://developers.reddit.com/new and choose Mod Tool under Other templates. Go through the wizard. You will need to create a Reddit account and connect it to Reddit developers. Follow the instructions on your terminal." — quickstart-mod-tool.md
→ Devvit new는 Reddit 계정 OAuth 로그인 + 브라우저 wizard가 필수. AI 환경에서 비대화형 실행 불가. 사용자 본인이 실행해야 함.
10.3 Day-0 권장 액션 (사용자 단독 수행)
# 1) 브라우저에서 https://developers.reddit.com/new 열고 "Mod Tool" 템플릿 선택
# → wizard가 끝나면 터미널에 token + dir 생성 안내
# 2) 생성된 디렉토리로 이동
cd vibe-mod # or whatever you named it
# 3) devvit.json 확인 — http 권한 추가
# permissions: { http: { enable: true, domains: ['api.openai.com'] }, reddit: {...}, redis: true }
# 4) server/index.ts에 fetch test endpoint 한 줄 추가
# app.post('/internal/menu/test-openai', ...) — OpenAI ping
# 5) npm run dev — playtest sub에서 실행
# 6) 메뉴 액션 클릭 → 토스트로 OpenAI 응답 표시
# → 성공 시 vibe-mod 본격 개발 시작
api.openai.com은 globally allowlisted. 사용자의 CLI 실행은 코드 작동 확인이지 정책 게이트 검증이 아님.
11. 추가 제출 요건 (원본 plan 누락)
11.1 Terms and Conditions + Privacy Policy 의무
"Any app that uses fetch must upload Terms and Conditions and a Privacy Policy. Links to each of these documents must be saved in the app details form."
— http-fetch.mdx
→ 새 작업 항목: 2 문서 작성 + 호스팅 (GitHub Pages 또는 우리 갤러리 repo 활용 가능):
/tos.html— vibe-mod 사용 약관 (1-page)/privacy.html— Privacy Policy (모드의 NL → OpenAI 전송, Reddit 콘텐츠 미전송 명시)
11.2 README "Fetch Domains" 섹션
"If your app uses fetch domains, you must add context to your app's README for the approval process: Create a 'Fetch Domains' section in your README, List each domain you're requesting and explain why you need it." — http-fetch-policy.md
→ README 추가 섹션 (vibe-mod 예시):
## Fetch Domains
The following domains are requested for this app:
- `api.openai.com` — Used to translate moderators' natural-language
rule descriptions into a structured rule JSON. The LLM call happens
ONLY at rule-edit time, NOT on every post evaluation. Reddit user
content (post bodies, usernames) is NEVER sent to the LLM. Only the
moderator's own typed sentence is sent.
11.3 App publishing 결정
| 옵션 | 명령 | 적합도 |
|---|---|---|
| Unlisted (default) | npx devvit publish | 해커톤 심사용으로 충분. 다른 모드가 install 링크로 접근 가능 |
| Public (App Directory) | npx devvit publish --public | Moderator's Choice 영향력 + 사후 광범위 install |
→ 전략: 마감 4-5일 전 (5/22~23) Public publish 신청. Review 1주 걸린다고 명시되어 있음. 늦으면 unlisted로 fallback.
11.4 vibe-mod 제출 패키지 업데이트
- ☐ App listing 링크 (developers.reddit.com/apps/vibe-mod)
- ☐ NEW: ToS HTML URL
- ☐ NEW: Privacy Policy HTML URL
- ☐ NEW: README의 "Fetch Domains" 섹션
- ☐ 참가자 Reddit username 전원
- ☐ Tool overview
- ☐ Project impact (1-3 communities)
- ☐ 200-member 미만 sub 데모 포스트 (심사 기간까지 free access)
- ☐ 60초 데모 비디오 (YouTube/Vimeo 공개)
12. 업데이트된 4일 MVP scope (검증 후)
Day 1 (5/12 화)
- 사용자 액션: 브라우저로
developers.reddit.com/new→ Mod Tool 템플릿 선택 → wizard → terminal에 vibe-mod 디렉토리 생성 devvit.json확장: permissions(reddit moderator, redis, http openai), settings(global openaiApiKey isSecret, subreddit dryRunOnly), menu, forms, triggers(onPostSubmit, onCommentSubmit, onAppInstall), scheduler(audit-retention cron, dry-run-replay one-shot)- OpenAI key 발급 + 일일 $5 ceiling +
npx devvit settings set openaiApiKey - Hono 서버 stub: menu/compose, form/submit, trigger/post-submit endpoints (모두 200 응답만)
- Redis schema 검증:
rules:active,auditZSET - EXIT GATE:
npm run dev→ 플레이테스트 sub에서 "Compose rule" 메뉴 보이고 form 열림
Day 2 (5/13 수)
- OpenAI gpt-4o-mini 호출 wrapper + JSON 모드 + Zod schema validator
- System prompt + 3 few-shot 예제 (rule schema 정의)
- Action whitelist 하드코딩 (
remove/lock/flair/modmail/report;ban/permaban/mute는 confirmation) - Predicate evaluator (pure TS,
{all|any|not}tree) onPostSubmithandler에서 rules:active 평가 + 첫 action 실행 (reddit.getPostById().remove())- EXIT GATE: form에 "Remove posts containing 'discord.gg' from accounts under 7 days" 입력 → compile → 실제 매칭 포스트 제거 + audit 엔트리
Day 3 (5/14 목)
- Rollback 메커니즘: audit:<actionId> ZSET + reverse-action params +
redis.expire(rollback:..., 2592000) - Dry-run replay scheduler one-shot:
reddit.getNewPosts({limit:100})가져와rules:draft평가, 매치 카운트를 Redis에 저장 - Live Log 보기: 별도 메뉴 →
zRange(audit, 0, 50)→ form display - Activate 흐름: shadow mode 24h cron job 등록
- EXIT GATE: "47 posts would fire" 확인 → Activate (shadow) → 새 포스트 들어옴 → action 실행 → Undo
Day 4 (5/15 금)
- 5 starter rules
onAppInstall에서 seed - 50 compiles/day rate limit (Redis counter)
- 30-day audit retention (cron
0 3 * * *) - Error 카피 8개 (LLM down, invalid rule, conflict, permission denied, ...)
- ToS + Privacy Policy HTML 작성 + 갤러리 repo에 호스팅
- README "Fetch Domains" 섹션 작성
- EXIT GATE: 완전한 end-to-end 흐름 + 200-member 미만 sub 생성 + 첫 데모 영상 trial
Days 5-15: Polish + Beta + 데모 영상 (원본 plan 유지)
마감일 작업 (5/27 수)
- 아침:
npx devvit publish(unlisted) — 이미 5/22-23경 Public publish 신청 시도 OK - 제출 양식 채우기 + ToS/PrivacyPolicy URL 입력
- 10:00 PT (KST 5/28 02:00): 제출 완료 목표 (8시간 buffer)
13. 출처 (verbatim 인용 소스)
공식 문서 (cloned from reddit/devvit-docs @ HEAD)
docs/quickstart/quickstart-mod-tool.md— Mod Tool 공식 quickstart (Comment Mop 예시)docs/capabilities/server/http-fetch.mdx— fetch 활성화 + global allowlistdocs/capabilities/server/http-fetch-policy.md— AI provider 정책 + 도메인 신청 카테고리docs/capabilities/server/triggers.mdx— 모든 트리거 이벤트 + 등록 패턴docs/capabilities/server/redis.mdx— Redis 명령어 + 한계 + transactionsdocs/capabilities/server/scheduler.mdx— 스케줄러 + cron + one-shot + daisy chaindocs/capabilities/server/settings-and-secrets.mdx— 설정 + isSecret + OpenAI 예시docs/capabilities/server/reddit-api.mdx— Reddit API 개요 + 인증 자동 처리docs/api/redditapi/RedditAPIClient/classes/RedditAPIClient.md— 100+ 메서드 전체 API surfacedocs/capabilities/client/menu-actions.mdx— menu items + forUserType moderator + 10분 보안 제약docs/guides/faq.mdx— publish/install 패턴, unlisted vs public
관련 자료 (이 갤러리 repo 내)
검증 완료: 2026-05-11 KST · 다음 단계: 사용자가 Day-1 CLI 액션 수행 시점에 본 보고서를 implementation guide로 사용