WhipWhip

챗으로 만들기

아래 글 전체를 복사해 평소 쓰는 챗(ChatGPT·Claude·Gemini 등)에 붙여넣고, 맨 끝에 원하는 기능을 적어 보내세요. 챗이 휩셋 JSON을 돌려주면 그대로 복사해 휩휩 패널의 가져오기 칸에 붙여넣으면 됩니다. 고칠 곳이 있으면 패널이 목록을 주고, 그 목록을 챗에 다시 붙여넣으면 됩니다.

JSON 스키마 · llms-full.txt

지금부터 휩휩(WhipWhip)의 휩셋을 설계해서 JSON 객체 하나로 써 주세요. 이 안내를 끝까지 먼저 읽으세요. 맨 끝 "내 요청" 아래에 제가 원하는 것을 적습니다. 꼭 필요한 정보가 빠졌을 때만 짧은 질문 하나를 하고, 그렇지 않으면 바로 JSON으로 답해 주세요.

휩휩이 무엇인가

휩휩은 브라우저 확장입니다. 제가 쓰는 웹챗(ChatGPT·Claude·Gemini·Grok·Perplexity) 위에 패널을 띄우고, 저장해 둔 절차를 그 챗 안에서 대신 실행합니다. 입력창에 글을 쓰고, 보내고, 답을 기다리고, 답을 읽어 일부를 저장하고, 결과를 보여 줍니다.

휩휩은 API를 부르지 않습니다. 모든 일이 실제 챗 페이지에서, 제가 직접 입력한 것과 똑같이 일어납니다. 그래서 휩은 사람이 그 페이지에서 할 수 있는 일을 카드 하나씩 할 수 있을 뿐입니다.

카드가 어떻게 이어지나

챗과 대화하기. prompt_write는 입력창에 글을 넣습니다(보내지는 않습니다). submit은 그 글을 보내고 답이 다 나올 때까지 기다립니다. submit 뒤에는 답을 쓸 수 있습니다.

답 남기기. var_save"valueSource": "var.last.assistant"를 주면 가장 최근 답 전체를 변수에 저장합니다. 결과를 남기는 기본 방법입니다. ask_and_extract는 답에서 짧은 이름 붙은 값(제목, 점수, 분류)을 뽑을 때 씁니다 — 프롬프트 끝에 값을 태그로 덧붙이라는 지시를 더하고 그 값을 읽습니다. 긴 답 전체를 담는 데 쓰지 마세요. extract_response는 별도 임시 탭에서 구조화된 JSON을 받아 옵니다. 드물게만 쓰세요. validate는 최근 답이 형식(JSON, 정규식, 비어 있지 않음)을 지켰는지 보고, 아니면 챗에게 다시 요청합니다.

저에게 묻기. 두 가지입니다.

  1. user_input 변수를 프롬프트에 토큰으로 넣습니다. 휩이 실행되기 전에 휩휩이 그 휩에 필요한 user_input 변수마다 작은 입력 폼을 보여 줍니다. 기본이고 보통 가장 좋습니다.
  2. input_prompt는 실행 도중, 그 카드가 있는 자리에서 묻습니다. 그 순간에만 의미가 있는 질문 (예: 답을 읽은 뒤 "이 스크랩 이름은?")이거나, "alwaysAsk": true로 이미 채워진 값을 확인받을 때 씁니다.

choice_prompt는 선택지에서 고르게 합니다. 고정 목록(options에 한 줄에 하나)이나 목록 변수의 항목에서 고를 수 있습니다.

결과 보여 주기. show_result_modal은 변수로 만든 글을 창으로 띄웁니다. 제가 복사할 것 같으면 "copyButton": "copy_body"를 주세요.

대화 옮겨 다니기. new_chat은 같은 서비스에서 새 대화를 엽니다. open_service는 다른 서비스로 갑니다. open_url은 주소를 엽니다. tag_current_chat은 실행이 서 있는 대화에 역할을 붙입니다. go_to_role은 그 역할을 가진 대화로 실행을 옮깁니다. 역할은 어떤 휩이 go_to_role로 가기 전에 먼저 tag_current_chat으로 붙어 있어야 합니다. 그래서 역할이 둘인 셋은 보통 역할마다 짧은 "시작" 휩을 두어 그 챗에 역할을 알려 주고 태그를 붙입니다: prompt_write(이 대화에서 너는 누구다) → submittag_current_chat.

목록. "valueType": "array" 변수는 레코드 목록을 담습니다. append_item은 레코드를 더하고 (fields는 이름/값 쌍 목록, autoId는 레코드마다 id를 붙입니다), upsert_itemid로 더하거나 바꾸고, patch_item은 레코드 하나의 일부 필드를 바꾸고, remove_item은 하나를 지웁니다. derive_index는 목록을 글로 바꿔(항목마다 한 줄, <<item.field>> 토큰이 든 템플릿으로) 다른 변수에 저장합니다. 그래야 프롬프트나 결과 창이 그 목록을 보여 줄 수 있습니다. 여러 번 실행에 걸쳐 무언가를 기억하는 셋(노트, 라이브러리, 기록)은 목록으로 만듭니다.

변수.

토큰

카드 글 안에서 변수는 **<<var.key>>**로 씁니다 — 양쪽에 꺾쇠 두 개씩입니다. 목록 템플릿 안에서는 <<item.field>>입니다. <<now>>는 오늘 날짜입니다. 중괄호로 토큰을 쓰지 마세요. <<…>>는 휩휩이 알아서 바꿉니다.

JSON 모양

{
  "format": "whipwhip.authoring/1",
  "name": "…",                       셋 이름, 제 언어로
  "description": "…",                선택, 한 문장
  "inline_guide": "…",               선택, 셋 쓰는 법
  "tags": [ { "name": "writer" } ],  역할. A–Z a–z 0–9 _ - 로 3–10자
  "variables": [ { "key": "…", "label": "…", "source": "…", "required": true } ],
  "whips": [
    {
      "label": "…",                  버튼 글, 짧게
      "description": "…",            선택
      "preflightStyle": "form",      선택: "form"(기본) 또는 "none"
      "scopeTags": [ "writer" ],     선택: 이 휩이 속한 역할 대화
      "actions": [ { "card": "prompt_write", "config": { "text": "…" } } ]
    }
  ]
}

id, usedVars, requiresVars, producesVars, askInline, 키, 서명, 버전은 쓰지 마세요. 휩휩이 채웁니다.

카드 레퍼런스

prompt_write

채팅창에 내용을 입력하거나 수정합니다.

submit

작성된 내용을 전송하고, 대기를 끄지 않았다면 AI의 응답을 기다립니다.

input_prompt

사용자에게 필요한 정보를 입력받습니다.

ask_and_extract

AI에게 질문하고 필요한 정보를 변수로 자동화하여 추출합니다.

extract_response

AI의 응답을 분석하여 구조화된 데이터로 변환합니다. 처리하는 동안 임시 탭이 포그라운드로 열립니다.

validate

응답이 형식을 지켰는지 보고 아니면 다시 요구합니다. 형식만 봅니다 — 내용이 맞는지는 판정할 수 없습니다.

send_to_services

같은 글을 고른 AI들에 보내고, 모든 답을 기다려 한 변수에 모읍니다. 지금 탭의 AI는 지금 탭에, 나머지는 뒤쪽 새 탭에 보냅니다.

var_save

작성기, AI 응답 등의 내용을 변수에 담아 저장합니다.

var_flush

저장된 모든 변수 값을 초기화합니다.

설정 없음 — "config": {}.

append_item

배열 변수에 항목을 추가합니다 (예: ADR 목록에 레코드 추가).

upsert_item

"id" 필드로 매칭해 배열 변수의 항목을 삽입하거나 갱신합니다.

patch_item

id로 매칭한 항목의 지정 필드만 수정하고 나머지 필드는 유지합니다 (예: 상태만 전환).

remove_item

"id"로 배열 변수의 항목을 제거합니다.

derive_index

배열 변수에서 항목당 한 줄씩 요약/인덱스 문자열을 만듭니다.

go_to_role

역할(태그)이 결속된 대화로 실행을 옮깁니다.

new_chat

현재 서비스에서 새 대화를 엽니다.

open_service

다른 AI 서비스로 전환합니다 (ChatGPT, Gemini, Claude…).

open_url

https:// 주소로 이동합니다.

tag_current_chat

현재 대화에 태그를 붙여 관리합니다.

choice_prompt

사용자에게 옵션 목록을 보여주고, 고른 값을 변수에 담습니다.

show_result_modal

변수에 저장된 값을 활용해 결과창을 띄웁니다.

import_whipset

변수에 든, 챗이 쓴 휩셋 JSON을 가져옵니다. 저장 전에 미리보기로 확인받습니다.

값 출처(var_save.valueSource)

builtin.date_today · builtin.date_iso · builtin.time_now · builtin.timestamp · builtin.day_of_week · builtin.page_url · builtin.page_title · builtin.page_domain · builtin.language · builtin.random_uuid · builtin.selection · composer · var.last.user · var.last.assistant

흔한 실수

예시

대화 하나: 초안을 다듬어 보여 주기

{
  "format": "whipwhip.authoring/1",
  "name": "초안 다듬기",
  "description": "거친 초안을 또렷하게 고쳐 쓰고 결과를 보여 줍니다.",
  "tags": [],
  "variables": [
    { "key": "draft", "label": "초안", "source": "user_input", "required": true },
    { "key": "polished", "label": "다듬은 글", "source": "set_by_action", "required": false }
  ],
  "whips": [
    {
      "label": "다듬기",
      "actions": [
        { "card": "prompt_write", "config": { "text": "아래 초안을 또렷하고 간결하게 고쳐 써 줘. 내 뜻과 말투는 지켜 줘. 고친 글만 답해.\n\n<<var.draft>>", "mode": "replace" } },
        { "card": "submit", "config": {} },
        { "card": "var_save", "config": { "valueSource": "var.last.assistant", "key": "polished" } },
        { "card": "show_result_modal", "config": { "title": "다듬은 글", "body": "<<var.polished>>", "copyButton": "copy_body" } }
      ]
    }
  ]
}

역할 둘: 서로 다른 챗의 작가와 비평가

{
  "format": "whipwhip.authoring/1",
  "name": "작가와 비평가",
  "inline_guide": "챗 하나를 열고 '작가 시작', 다른 챗을 열고 '비평가 시작'을 누르세요. 그다음 어디서든 '쓰고 검토받기'를 실행합니다.",
  "tags": [ { "name": "writer" }, { "name": "critic" } ],
  "variables": [
    { "key": "task", "label": "쓸 것", "source": "user_input", "required": true },
    { "key": "draft", "label": "초안", "source": "set_by_action", "required": false },
    { "key": "review", "label": "비평", "source": "set_by_action", "required": false },
    { "key": "final", "label": "최종본", "source": "set_by_action", "required": false }
  ],
  "whips": [
    {
      "label": "작가 시작",
      "actions": [
        { "card": "prompt_write", "config": { "text": "이 대화에서 너는 내 작가야. 완성된 초안을 쓰고, 내가 비평을 가져오면 고쳐 써. '좋아'라고만 답해.", "mode": "replace" } },
        { "card": "submit", "config": {} },
        { "card": "tag_current_chat", "config": { "tagName": "writer" } }
      ]
    },
    {
      "label": "비평가 시작",
      "actions": [
        { "card": "prompt_write", "config": { "text": "이 대화에서 너는 까다로운 비평가야. 초안을 보여 주면 가장 약한 지점을 짧은 번호 목록으로 짚어. '좋아'라고만 답해.", "mode": "replace" } },
        { "card": "submit", "config": {} },
        { "card": "tag_current_chat", "config": { "tagName": "critic" } }
      ]
    },
    {
      "label": "쓰고 검토받기",
      "actions": [
        { "card": "go_to_role", "config": { "tagName": "writer" } },
        { "card": "prompt_write", "config": { "text": "<<var.task>>", "mode": "replace" } },
        { "card": "submit", "config": {} },
        { "card": "var_save", "config": { "valueSource": "var.last.assistant", "key": "draft" } },
        { "card": "go_to_role", "config": { "tagName": "critic" } },
        { "card": "prompt_write", "config": { "text": "과제: <<var.task>>\n\n초안:\n<<var.draft>>", "mode": "replace" } },
        { "card": "submit", "config": {} },
        { "card": "var_save", "config": { "valueSource": "var.last.assistant", "key": "review" } },
        { "card": "go_to_role", "config": { "tagName": "writer" } },
        { "card": "prompt_write", "config": { "text": "이 비평을 반영해 초안을 고쳐 줘. 고친 전문을 답해.\n\n<<var.review>>", "mode": "replace" } },
        { "card": "submit", "config": {} },
        { "card": "var_save", "config": { "valueSource": "var.last.assistant", "key": "final" } },
        { "card": "show_result_modal", "config": { "title": "초안 · 비평 · 최종본", "body": "[초안]\n<<var.draft>>\n\n[비평]\n<<var.review>>\n\n[최종본]\n<<var.final>>", "copyButton": "copy_body" } }
      ]
    }
  ]
}

쌓이는 목록: 답 스크랩 노트

{
  "format": "whipwhip.authoring/1",
  "name": "답 스크랩 노트",
  "tags": [],
  "variables": [
    { "key": "clip", "label": "스크랩한 답", "source": "set_by_action", "required": false },
    { "key": "clip_title", "label": "제목", "source": "set_by_action", "required": false },
    { "key": "notes", "label": "노트", "source": "set_by_action", "valueType": "array", "required": false },
    { "key": "notes_index", "label": "노트 목록", "source": "set_by_action", "required": false },
    { "key": "notes_full", "label": "노트 전문", "source": "set_by_action", "required": false },
    { "key": "summary", "label": "요약", "source": "set_by_action", "required": false }
  ],
  "whips": [
    {
      "label": "이 답 저장",
      "actions": [
        { "card": "var_save", "config": { "valueSource": "var.last.assistant", "key": "clip" } },
        { "card": "input_prompt", "config": { "title": "이 답 저장", "selectedVars": [ { "key": "clip_title", "question": "짧은 제목을 붙여 주세요" } ], "inputStyle": "inline", "alwaysAsk": true } },
        { "card": "append_item", "config": { "key": "notes", "autoId": true, "idPrefix": "note-", "fields": [ { "name": "title", "value": "<<var.clip_title>>" }, { "name": "text", "value": "<<var.clip>>" }, { "name": "date", "value": "<<now>>" } ] } },
        { "card": "derive_index", "config": { "sourceKey": "notes", "key": "notes_index", "itemTemplate": "<<item.id>> — <<item.title>> (<<item.date>>)" } },
        { "card": "show_result_modal", "config": { "title": "노트", "body": "<<var.notes_index>>" } }
      ]
    },
    {
      "label": "노트 요약",
      "actions": [
        { "card": "derive_index", "config": { "sourceKey": "notes", "key": "notes_full", "itemTemplate": "### <<item.title>>\n<<item.text>>" } },
        { "card": "new_chat", "config": { "openMode": "current" } },
        { "card": "prompt_write", "config": { "text": "이 노트들에 공통으로 흐르는 것과 합치면 무엇이 되는지 정리해 줘.\n\n<<var.notes_full>>", "mode": "replace" } },
        { "card": "submit", "config": {} },
        { "card": "var_save", "config": { "valueSource": "var.last.assistant", "key": "summary" } },
        { "card": "show_result_modal", "config": { "title": "요약", "body": "<<var.summary>>", "copyButton": "copy_body" } }
      ]
    }
  ]
}

출력 규칙

  1. 제가 어떤 휩을 어떤 순서로 누를지 먼저 생각하고, 동작하는 가장 작은 셋을 설계하세요.
  2. 이름·라벨·질문·프롬프트·결과 제목은 제가 요청을 쓴 언어로 쓰세요. 카드 이름, 필드 이름, 변수 키, 태그 이름은 이 안내에 적힌 그대로 둡니다.
  3. 휩셋 전체를 담은 JSON 코드블록 하나로 답하세요. 블록 뒤에 어떤 버튼부터 누르면 되는지 짧은 문장 두 개까지만 덧붙여도 됩니다.
  4. 제가 휩휩이 알려 준 고칠 곳 목록을 붙여넣으면, 전부 고쳐서 완전한 JSON을 다시 보내 주세요. 고친 부분만 보내지 마세요.

내 요청