A local-first Korean SMB workflow orchestrator โ Run pre-built workflows for daily office work entirely on your laptop. Your company data never leaves the machine.
๐ https://taskflow.kr โ ๋ค์ด๋ก๋ ยท ๊ฐ๊ฒฉ ยท ๋ฌธ์ ยท ํ ํ๋ฆฟ
ํ์ฌ ๋ฐ์ดํฐ๋ ๋ ธํธ๋ถ ์์๋ง. ํ๊ตญ์ด ์ฌ๋ฌด ์๋ํ, 8 ์ํฌํ๋ก ยท 3 ํ๋ฅด์๋ ์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅ.
๐ 2026-05-20 ์ถ์ โ A ์ฌ๋ฌด์ง ยท B 1์ธ ์์์ ยทํ๋ฆฌ๋์ ยท D SMB ์ฌ์ฅ 3 ํ๋ฅด์๋ ์นด๋ ๋ชจ๋ ์๋.
โฌ ๋ค์ด๋ก๋ ยท ๐ ๋ฌธ์ ยท ๐ฐ ๊ฐ๊ฒฉ ยท ๐ฏ 8 ์ํฌํ๋ก ยท ๐ LICENSE ยท โข TRADEMARK
| ํ๋ฅด์๋ | ์ง์ ํ์ด์ง | ํต์ฌ ์ํฌํ๋ก |
|---|---|---|
| A ์ฌ๋ฌด์ง ยท ์ด๋ฌด ยท ์ด์ํ | /sumu | meeting-actions ยท weekly-report ยท approval-triage |
| B 1์ธ ์์์ ยท ํ๋ฆฌ๋์ | /solo | quote-email ยท sales-followup ยท sns-replies |
| D SMB ์ฌ์ฅ ยท ๋ํ | /executive | sales-summary (๋งค์ผ) ยท weekly-report (๋ฐ๋ ์
์ฅ) |
๊ณตํต: sales-summaryยทinquiry-triage๋ ํ๋ฅด์๋ ๋น์ค๋ง ๋ค๋ฅผ ๋ฟ 3 ํ๋ฅด์๋ ๋ชจ๋ ์ฌ์ฉ. ์์ธํ ๋งคํ์ Bundled workflows.
- ํ์ฌ ๋ฐ์ดํฐ๊ฐ ๋ ธํธ๋ถ ๋ฐ์ผ๋ก ์ ๋๊ฐ (local-first) โ Notion AIยทChatGPTยท๋คผํผ์ ํด๋ผ์ฐ๋ SaaS.
- ํ๊ตญ์ด ์ฌ๋ฌด ์ํฌํ๋ก 8์ข ๋ฒ๋ค โ n8nยทMakeยทZapier๋ ๋น ํ์ด์ง์์ ์์.
start.bat๋๋ธํด๋ฆญ ์ง์ โ ๋น๊ฐ๋ฐ์๋ 5๋ถ ์์ ์ฒซ ๊ฒฐ๊ณผ.
๋ฐ๋ณต ์ ๋ฌด ์คํธ๋ ์ค๋ฅผ ์ค์ด๋ ๋ก์ปฌ ์ํฌํ๋ก์ฐ ๋ฌ๋. LLM ํธ์ถ๊ณผ ์ ธ ๋ช ๋ น์ YAML ํ ํ์ผ๋ก ์ฎ์ด ๋ธ๋ผ์ฐ์ ์์ ์คํํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ SSE๋ก ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐํฉ๋๋ค. ๋จ์ผ ์ฌ์ฉ์ยท๋จ์ผ ๋จธ์ ยทDAG ์์ยทํ ์์.
๊ถ์ฅ: taskflow.kr/download์์ zip ๋ฐ๊ธฐ โ ์์ถ ํ๊ณ start.bat ๋๋ธํด๋ฆญ. Anthropic API ํค๋ง ์
๋ ฅํ๋ฉด ๋.
๊ฐ๋ฐ์: git clone https://github.com/wndnjs3865/flowagent.git && pnpm install && pnpm dev
๋๋ฉ์ธ ์ฉ์ด (Workflow, Step, Run, Runner, Agent) ๋ CONTEXT.md ์ ์ ์๋ผ ์์ด์. ์ฝ๋, ์ปค๋ฐ, PR ์ ๋ชฉ์์ ๊ทธ๋๋ก ์ฌ์ฉํ์ธ์.
์ด README๋ ๋ ์ข ๋ฅ์ ๋ ์๋ฅผ ์ํด ๋ถ๋ฆฌ๋ผ ์์ต๋๋ค. ๋ณธ์ธ ๊ฒฝ๋ก๋ง ๋ฐ๋ผ๊ฐ์๋ฉด ๋ฉ๋๋ค.
| ๋๊ตฌ | ์์ ์์น | ๋ชฉํ |
|---|---|---|
| ์ผ๋ฐ ์ฌ์ฉ์ (๋น๊ฐ๋ฐ์, ์ฌ๋ฌดยท์ด๋ฌดยท์์ ์ง์) โ ๋ ธํธ๋ถ์์ 8 ์ํฌํ๋ก ๋ฐ๋ชจ๋ฅผ ์ง์ ๋๋ ค๋ณด๊ณ ์ถ์ | ๋ฐ๋ก ์๋ ์ผ๋ฐ ์ฌ์ฉ์์ฉ 5๋ถ ์์ ๊ฐ์ด๋ | ์ค์น โ 8 ์ํฌํ๋ก ๋ฐ๋ชจ ์คํ. customize๋ ๋ฏธํ ์ ์ฒญ์ผ๋ก |
| ๊ฐ๋ฐ์ / Pilot ์ด์์ โ ์ฝ๋ ์์ , ์ ์ํฌํ๋ก์ฐ ์์ฑ, ๋ฏธํ ์์ฐยทcustomize ์งํ | Developer quickstart โ Demo path (Pilot ์ด์์์ฉ) โ Writing a workflow | 8 ์ํฌํ๋ก ์ธ ์ฌ๋ก๋ฅผ yaml๋ก, 4์ฃผ Pilot ์งํ, ์ฝ๋ ๊ธฐ์ฌ |
์ ๋ ๊ฒฝ๋ก ๋ชจ๋์ ๊ณตํต์ผ๋ก ์ ์ฉํ ์น์ : 1๋ถ ๋ฐ๋ชจ ์์, Bundled workflows, Run logs, Limits.
๋น๊ฐ๋ฐ์๋ GitHubยทPowerShellยทํฐ๋ฏธ๋์ ๋ชจ๋ฅด๊ณ ๋ ธํธ๋ถ์์ 8 ์ํฌํ๋ก ๋ฐ๋ชจ๋ฅผ ์ง์ ์คํํ ์ ์๊ฒ ๋ง๋ ํ๋ฆ.
1๏ธโฃ ๐ฆ flowagent ZIP ๋ค์ด๋ก๋
์ ํฐ ๋งํฌ๋ฅผ ํด๋ฆญํ๋ฉด flowagent-main.zip ์ด ์๋์ผ๋ก ๋ฐ์์ง๋๋ค.
๋ค์ด๋ก๋ ํด๋๋ก ๊ฐ์ zip ํ์ผ์ ์ฐํด๋ฆญ โ "๋ชจ๋ ํ์ผ ์์ถ ํ๊ธฐ" โ ์์น๋ C:\flowagent ๊ฐ์ด ํ๊ธยท๊ณต๋ฐฑ ์๋ ํด๋ ๊ถ์ฅ.
๋ค์ 4๋จ๊ณ๊ฐ ์๋์ผ๋ก ์งํ๋ฉ๋๋ค. ํ ์ค๋ฅธ์ชฝ "๋ณธ์ธ์ด ํ ์ผ"๋ง ํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
| ์๋ ์งํ | ๋ณธ์ธ์ด ํ ์ผ |
|---|---|
| Node.js ์ค์น ์ฌ๋ถ ํ์ธ | ์์ผ๋ฉด nodejs.org๊ฐ ์๋์ผ๋ก ์ด๋ฆผ โ LTS ์ด๋ก ๋ฒํผ์ผ๋ก ์ค์นํ ๋ค start.bat ๋ค์ ๋๋ธํด๋ฆญ |
| pnpm ์๋ ์ค์น (corepack ๋๋ npm) | (์์) |
๋ฉ๋ชจ์ฅ ์๋ ์คํ โ .env ํ์ผ ์ด๋ฆผ |
ANTHROPIC_API_KEY= ๋ค์ ๋ณธ์ธ ํค ๋ถ์ฌ๋ฃ๊ณ Ctrl+S โ ๋ฉ๋ชจ์ฅ ๋ซ๊ธฐ (ํค ๋ฐ๊ธ 1๋ถ โ Create Key โ sk-ant-โฆ ๋ณต์ฌ) |
| ์์กด์ฑ ์ค์น + ์๋ฒ ์์ + ๋ธ๋ผ์ฐ์ ์๋ ์ด๊ธฐ | ๋ธ๋ผ์ฐ์ ์ 5์ฅ ์นด๋ ๋ณด์ด๋ฉด ์นด๋ 1๊ฐ โ Run |
๊ฒ์ ์ฐฝ์ ๋ซ์ง ๋ง์ธ์ โ ์๋ฒ๊ฐ ๊บผ์ง๋๋ค.
(SmartScreen์ด start.bat ์คํ ๊ฒฝ๊ณ ๋ฅผ ๋์ฐ๋ฉด ์ถ๊ฐ ์ ๋ณด โ ์คํ.)
8 ์ํฌํ๋ก ๋ชจ๋ ๋ ธํธ๋ถ ์ ํ์ผ์ LLM ์ ๋ ฅ์ผ๋ก ์๋๋ค. ๊ทธ ํ์ผ์ ๋ณธ์ธ ๋ฐ์ดํฐ๋ก ๊ฐ์ ์ด๋ฆยท๊ฐ์ ํ์์ผ๋ก ๋ฎ์ด์ฐ๋ฉด ๋ณธ์ธ ๋ฐ์ดํฐ ๊ฒฐ๊ณผ๊ฐ ์ฆ์ ๋์ต๋๋ค.
| ์ํฌํ๋ก์ฐ | ๋ฐ๊ฟ ํ์ผ | ํ์ |
|---|---|---|
meeting-actions |
workflows\fixtures\meeting-notes-2026-w19.md |
ํ๊ตญ์ด ํ์๋ก (.md) |
weekly-report |
workflows\fixtures\weekly-progress-2026-w19.md |
ํ ์ฃผ ์งํ ๋ ธํธ (.md) |
sales-summary |
workflows\fixtures\sales-2026-04.csv |
CSV (Excel ์ ์ฅ ์ "CSV UTF-8") |
inquiry-triage |
workflows\fixtures\inquiries-2026-05.csv |
CSV โ id,์ ์์ผ์,๊ณ ๊ฐ๋ช
,๋ฌธ์๋ด์ฉ |
approval-triage |
workflows\fixtures\inbox-approvals-2026-05.md |
๊ฒฐ์ฌ ์์ฒญ (.md, ## REQ-001 ํ์) |
quote-email |
workflows\fixtures\project-brief-2026-w20.md |
ํ๋ก์ ํธ brief + ๋ณธ์ธ ๋จ๊ฐ (.md) |
sales-followup |
workflows\fixtures\client-meeting-2026-w22.md |
๋ฏธํ raw ๋ ธํธ (.md) |
sns-replies |
workflows\fixtures\sns-comments-2026-w23.md |
SNS ๋๊ธยทDM raw export (.md) |
- ์ ํ์์ 1๊ฐ ์ ํ โ Explorer์์ ํด๋น ํ์ผ ๋๋ธํด๋ฆญํด ์ด๊ธฐ
- ๋ณธ์ธ ๋ฐ์ดํฐ๋ก ๋ด์ฉ ๋ฐ๊พธ๊ณ ์ ์ฅ
- ๋ธ๋ผ์ฐ์ ์๋ก๊ณ ์นจ โ ๊ฐ์ ์นด๋ โ Run
๋ฏธํ ์ ์ฒญ โ wndnjs3865@naver.com (๋๋ ํ์ด์ง ์๋จ Pilot ๋ฏธํ ์ ์ฒญ ๋ฐฐ๋). 30๋ถ ์์ ๊ท์ฌ ๋ฐ์ดํฐ๋ก YAML ํ๋ ํจ๊ป ๋ง๋ค์ด ๋๋ฆฝ๋๋ค โ ํ์ฌ ๋ฐ์ดํฐ๋ ๋ ธํธ๋ถ์ ๋ฒ์ด๋์ง ์์ต๋๋ค.
- "Node.js๊ฐ ์ค์น๋์ง ์์์ต๋๋ค" โ nodejs.org๊ฐ ์๋์ผ๋ก ์ด๋ฆผ. LTS ์ค์น ํ
start.bat๋ค์ ๋๋ธํด๋ฆญ. - ๊ฒ์ ์ฐฝ์ "API ํค" ์ค๋ฅ โ ํด๋์
.envํ์ผ์ ๋ฉ๋ชจ์ฅ์ผ๋ก ๋ค์ ์ด์ดANTHROPIC_API_KEY=๋ค ํค (์๋ค ๊ณต๋ฐฑยท๋ฐ์ดํ ์์ด) ํ์ธ ํ ์ ์ฅ โstart.bat๋ค์. - ๋ธ๋ผ์ฐ์ "์ฌ์ดํธ ์ฐ๊ฒฐ ๋ถ๊ฐ" โ ๊ฒ์ ์ฐฝ์
FlowAgent listening on โฆ์ค ์๋์ง ํ์ธ. ์์ผ๋ฉดstart.bat๋ค์ ๋๋ธํด๋ฆญ. - ๊ฒ์ ์ฐฝ ๋ซํ๋ฒ๋ฆผ โ ์๋ฒ๊ฐ ๊บผ์ก์ต๋๋ค.
start.bat๋ค์ ๋๋ธํด๋ฆญ. - ํ๊ตญ์ด ๊นจ์ง โ ๋ธ๋ผ์ฐ์
Ctrl+R์๋ก๊ณ ์นจ.
pnpm install
cp .env.example .env
# edit .env and put your Anthropic API key in ANTHROPIC_API_KEY=
pnpm dev
# open http://localhost:3000.env is loaded automatically via tsx --env-file=.env โ no dotenv dependency needed.
Required env:
| Var | Purpose |
|---|---|
ANTHROPIC_API_KEY |
Used by llm steps. Without it, runs fail at the first llm step. |
PORT |
HTTP port (default 3000). |
FLOWAGENT_WORKFLOWS_DIR |
Directory scanned for *.yaml workflows (default workflows). |
FLOWAGENT_RUNS_DIR |
Directory where per-run JSONL audit logs are written (default runs). Created on demand. |
FLOWAGENT_PILOT_CONTACT_EMAIL |
Email used by the Listing page "Pilot ๋ฏธํ
์ ์ฒญ" CTA button. The server builds a mailto: link with a fixed Korean subject. Defaults to the FlowAgent official sales channel wndnjs3865@naver.com โ override only if you fork for your own sales. |
FLOWAGENT_SHARE_SECRET |
HMAC signing secret for /share/* URLs โ used to send dashboard results to a phone (spec ยง 5 ์ต์
2). Must be at least 32 characters โ shorter values throw at runtime. When unset, the share UI is hidden and /share/* routes return 503. Generate with openssl rand -base64 32 (or PowerShell [Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))) and keep it in .env, never commit. |
FLOWAGENT_PUBLIC_ORIGIN |
Optional public origin (e.g. https://flowagent.example.com) used when building share URLs. Useful behind a reverse proxy where the Node server sees localhost but the user-facing URL is the public domain. When unset, x-forwarded-proto + x-forwarded-host headers are honored if both present, falling back to the request URL itself. |
๊ธฐ๋ณธ 5์ข ์ํฌํ๋ก์ฐ ์ํ ๋ฐ๋ชจ. ๋ ธํธ๋ถ์์ 5๋ถ ์์ โ ์ค์ ๊ฒฐ๊ณผ๊น์ง ํ ํ๋ฉด. (B ํ๋ฅด์๋ 3์ข ์ ์ฐจ๊ธฐ ์์์ ํฌํจ ์์ .)
์์์ ์ง์ ๋ นํยทํธ์งยท์ ๋ก๋ํฉ๋๋ค. ์ ์ฐจ๋ ๋ค์ ๋ ๋ฌธ์ ๋ฐ๋ผ๊ฐ๋ฉด 30๋ถ:
- Storyboard โ
docs/sales/pilot-demo-storyboard.mdโ ์ด ๋จ์ ์ปทยท๋ด๋ ์ด์ ยท๋ นํ ๋๊ตฌยทํธ์ง ๊ฐ์ด๋ยทfallback. ์ฌ์ ์ ๊ฒ 60์ด + 1๋ถ ๋ถํ 8๋จ๊ณ. - Asset ํธ์คํ
โ
assets/README.mdโ GitHub Release ์ ๋ก๋ ์ ์ฐจ, ํ์ผ๋ช ๊ท์ฝ(pilot-demo-<์ฉ๋>-<duration>.<ext>), 1MB ์ด์ ๋ฐ์ด๋๋ฆฌ๋ repo commit ๊ธ์ง.
์์ฝ ํ๋ฆ:
# 1. ์ฌ์ ์ ๊ฒ (60์ด) โ storyboard "์ฌ์ ์ ๊ฒ" ์น์
๊ทธ๋๋ก
rm -f runs/*.jsonl && pnpm dev > /dev/null 2>&1 &
sleep 3 && curl -sf http://localhost:3000/ > /dev/null && echo OK
# 2. OBS / QuickTime์ผ๋ก 1920ร1080 30fps ๋
นํ (storyboard ๋ฐ๋ผ 75์ด โ 60์ด ์ปท ํธ์ง)
# 3. GitHub Release์ ์
๋ก๋
gh release create v0.1.0-demo --title "Pilot demo assets v0.1" \
--notes "1๋ถ ๋ฐ๋ชจ ์์" ./pilot-demo-1min.mp4
# 4. README ์ <video src="..."> ์ URL์ ์ asset URL๋ก ๊ต์ฒด
gh release view v0.1.0-demo --json assets --jq '.assets[0].browser_download_url'๊ธฐ๋ณธ 5์ข ์ํฌํ๋ก์ฐ ์ค์๊ฐ ์คํ ๊ฒ์ฆ ๊ฒฐ๊ณผ (์์ storyboard ์ธก์ ๊ธฐ์ค): weekly-report 9์ด / meeting-actions 10์ด / sales-summary 15์ด / inquiry-triage 24์ด / approval-triage 17์ด โ ์ด 75์ด. ์ปท ํธ์ง์ผ๋ก 60์ด ์์ถ. (B ํ๋ฅด์๋ 3์ข timing์ ์ฐจ๊ธฐ ์ธก์ ์ ์ถ๊ฐ.)
The fastest path from clone to a result you can show a Pilot stakeholder. Total: 5 minutes including prereqs, 3 minutes if Node/pnpm are already installed.
- Node.js 20.6 or newer (
node --version) โ needed fortsx --env-file. - pnpm (
npm i -g pnpmif missing). - Anthropic API key from https://console.anthropic.com/settings/keys.
์ด ํ๋ก์ ํธ์ shell step์ OS-์ค๋ฆฝ node -e "..." ํ ์ค๋ก ํต์ผ๋ผ ์์ด ์ถ๊ฐ๋ก Git BashยทWSL ์ค์น๊ฐ ํ์ ์์ต๋๋ค. Windows ํ์ค PowerShellยทcmd ์ด๋ ์ชฝ์์๋ 8 ์ํฌํ๋ก ๋ชจ๋ ๊ทธ๋๋ก ๋์ํฉ๋๋ค.
| ๋จ๊ณ | ๋ช ๋ น (PowerShell ๋๋ cmd) |
|---|---|
| 1. Node.js ์ค์น | https://nodejs.org/ "LTS" installer ๋๋ winget install OpenJS.NodeJS.LTS |
| 2. pnpm ์ค์น | npm i -g pnpm |
| 3. ํ๋ก์ ํธ ๋ฐ๊ธฐ | git clone https://github.com/wndnjs3865/flowagent && cd flowagent |
| 4. ์์กด์ฑ ์ค์น | pnpm install |
5. .env ์์ฑ |
copy .env.example .env (cmd) ๋๋ Copy-Item .env.example .env (PowerShell) โ ๊ทธ ํ .env ์ด์ด ANTHROPIC_API_KEY=sk-ant-... ๋ถ์ฌ๋ฃ๊ธฐ |
| 6. ์๋ฒ ์คํ | pnpm dev |
| 7. ๋ธ๋ผ์ฐ์ | http://localhost:3000 |
PowerShell ์คํ์ ์ฑ
์ด์ ์ โ pnpm.ps1์ด ์ฐจ๋จ๋๋ฉด ํ ๋ฒ๋ง:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned์ดํ pnpm dev ์ ์. cmd์์๋ ์ด ๋ฌธ์ ์์.
git clone <this repo> && cd flowagentpnpm installcp .env.example .env, then open.envand paste your key intoANTHROPIC_API_KEY=sk-ant-...pnpm devโ you should seeFlowAgent listening on http://localhost:3000. Leave it running.- Open http://localhost:3000 in a browser. You'll see 5 bundled workflows in the list.
- Click
meeting-actionsโ Run. Each step streams into the log box live (step-startโstep-outputโstep-end). The full run takes ~20 seconds. - After the run finishes, open
runs/<runId>.jsonlin your editor. The exact events you just saw are on disk, one JSON object per line, ready to replay or share.
Try sales-summary for an executive-summary demo, inquiry-triage for a CS-desk demo, or
approval-triage for an office-manager demo. Each finishes in under 30 seconds.
What you should see at the end of step 6 (the Slack-format step of meeting-actions), in Korean,
ready to paste:
์ด๋ฒ ์ฃผ ์ก์
์์ดํ
์ ๋ฆฌํด๋๋ฆด๊ฒ์ ๐
*์ดํ์ฅ*
โข [5/16] ๋จ๊ณจ ๊ณ ๊ฐ ์ฌ์ํ ์ ๊ณต ๋ฐฉ์ ์ด์ ์์ฑ
โข [5/18] ์ฟ ํก ๊ด๊ณ ๋น ์ฌํธ์ฑ ์ ํ์ ์ ๋ณด๊ณ
*๋ฐ๋งค๋์ *
โข [5/15] ๋ง์ผํ
์ฃผ๋์ด ์ฑ์ฉ๊ณต๊ณ ์ด์ ์์ฑ
...
๋ฏธํ 30๋ถ ์ , ํ๋ฉด ๊ณต์ ์์ ์ง์ ์ ์๋ 4๊ฐ์ง๋ฅผ ํ์ธํฉ๋๋ค. ๋ผ์ด๋ธ ์์ฐ์ด ๋๊ธฐ์ง ์๊ฒ ํ๋ ์ต์ ๊ฐ๋.
# 1. API ํค ๋์ ํ์ธ โ ๋น ๊ฒฐ๊ณผ๋ฉด .env์ ANTHROPIC_API_KEY๋ฅผ ๋ค์ ํ์ธ
curl -s -o /dev/null -w "key=%{http_code}\n" -H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" https://api.anthropic.com/v1/models | grep -E "200|key="
# 2. ์๋ฒ ์ด์์๋์ง โ 200์ด์ด์ผ ํจ
curl -s -o /dev/null -w "server=%{http_code}\n" http://localhost:3000/
# 3. runs/ ๋น์ด์๋์ง โ ์ ์ถ๋ ฅ์ด ํ๋์ ๋ณด์ด๊ฒ
ls runs/*.jsonl 2>/dev/null | wc -l # 0์ด๋ฉด OK, ์๋๋ฉด mv runs runs.bak && mkdir runs
# 4. ๋ธ๋ผ์ฐ์ zoom 125%+ โ ํ๋ฉด ๊ณต์ ์ ๊ฐ๋
์ฑํ๋ฉด ๊ณต์ ํ๋ฉด์ ์๋ ๋ฉํธ๋ฅผ ์์๋๋ก ๋ฐ๋ผ ์ฝ์ผ์ธ์. ์ด 3๋ถ, ์์ฐ 3๊ฑด.
(0:00, ์ธํธ๋ก โ 20์ด) "FlowAgent๋ ๋ ธํธ๋ถ ํ ๋์์ ๋๋ ์ํฌํ๋ก์ฐ ๋์ฐ๋ฏธ์์. ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ธ๋ถ SaaS์ ์ฌ๋ฆฌ์ง ์์ต๋๋ค. ๋ฐ๋ณต๋๋ ์ฌ๋ฌด ์ ๋ฌด๋ฅผ ๋งค์ผ ๊ฐ์ ์์ผ๋ก ๋ค์ ํ์ง ์๊ฒ ๋ง๋๋ ๊ฒ ๋ชฉํ์์."
(0:20, ์์ฐ 1 ยท meeting-actions โ 50์ด) Run ๋๋ฅด๋ฉฐ: "์ด์ ํ์๋ก์ ๊ทธ๋๋ก ๋ฃ์ด ๋ณธ ๊ฑฐ์์. ๋จ ๋ช ์ด ๋ง์ ๋ด๋น์๋ณ ์ก์ ์์ดํ ์ด ํ๊ตญ์ด๋ก ์ ๋ฆฌ๋๊ณ , Slack์ ๊ทธ๋๋ก ๋ถ์ฌ๋ฃ์ ์ ์๋ ํ์๊น์ง ๋์ต๋๋ค."
(1:10, ์์ฐ 2 ยท sales-summary โ 50์ด) Run ๋๋ฅด๋ฉฐ: "์ด๋ฒ์ 4์ ๋งค์ถ CSV์์. ์ฑ๋๋ณ ์ด์์น๋ฅผ ์ง์ด์ฃผ๊ณ , ๊ฒฝ์์ง ๋ณด๊ณ ์ฉ 3๋ฌธ์ฅ ์์ฝ์ด ์๋์ผ๋ก ๋ง๋ค์ด์ง๋๋ค."
(2:00, ์์ฐ 3 ยท inquiry-triage โ 50์ด) Run ๋๋ฅด๋ฉฐ: "๊ณ ๊ฐ ๋ฌธ์ 6๊ฑด์ด์์. ์นดํ ๊ณ ๋ฆฌยท๊ธด๊ธ๋๋ก ๋ถ๋ฅ๋ ํ๊ฐ ๋จผ์ ๋์ค๊ณ , ์นดํ ๊ณ ๋ฆฌ๋ณ ๋ต๋ณ ์ด์๊น์ง ํ ๋ฒ์ ๋ง๋ค์ด์ง๋๋ค. CS ๋ด๋น์๊ฐ ํค๋ง ๋ค๋ฌ์ผ๋ฉด ๋์ด์์."
(2:50, ํด๋ก์ง โ 30์ด)
runs/ํด๋ ์ด๋ฉฐ: "๋ณด์๋ค์ํผ ์ถ๋ ฅ์ ๋ชจ๋ ์๋์ผ๋ก ๋์คํฌ์ ์ ์ฅ๋ฉ๋๋ค. ํ ๋ฌ ๋ค์ '์ด ์๋ํ๊ฐ ์๊ฐ์ ์ผ๋ง๋ ์๊ผ๋์ง' ๋ฆฌํฌํธ๋ ๋ช ๋ น ํ ์ค๋ก ๋ฝ์ ์ ์์ด์. ๋ค์ ์ฃผ์ ๊ท์ฌ ๋ฐ์ดํฐ 1๊ฑด์ผ๋ก ๊ฐ์ด ๋ง๋ค์ด ๋ณด๋ฉด ์ด๋ ์ธ์?"
์๋ ํ์ฌ๊ฐ ์ด๋ ๋ถ์๋ฅผ ๋ฐ๋ ค์ค๋์ง ๋ฏธ๋ฆฌ ์๋ฉด ์์ฐ์ ๋ฐ๊ฟ์ ์ฒซ ์ํฉํธ๋ฅผ ์ต๋ํํฉ๋๋ค.
| ์๋ | ์ถ์ฒ ์์ฐ ์์ (3๋ถ) | ํด๋ก์ง ๊ฐ์กฐ์ |
|---|---|---|
| CSํ์ฅ / ์ด์ํ์ฅ | inquiry-triage โ meeting-actions โ approval-triage |
"๋งค์ผ ๋ต๋ณ ํค ํต์ผ + ์ฐ์ ์์ ๋ถ๋ฅ + ๊ฒฐ์ฌ ๋๋ฝ ๋ฐฉ์ง" |
| ์ฌ๋ฌดยท์ด๋ฌดยทCFO | sales-summary โ approval-triage โ weekly-report |
"์๋ง 1-pager ์๋ํ + ๊ฒฐ์ฌ ์๋ ๊ฐ์ํ + ์ฃผ๊ฐ ๋ณด๊ณ ํ์คํ" |
| ๋ํยท์ค๋ฌด ๋งค๋์ | weekly-report โ meeting-actions โ sales-summary |
"๋ณด๊ณ ์๋ํ 3์ข ์ธํธ โ ์ฃผ๊ฐ/ํ์/์๊ฐ" |
| ์กํ(ํผํฉ) | ์ ๋ฒ์ฉ ์คํฌ๋ฆฝํธ ๊ทธ๋๋ก | ๋ฐ์ดํฐ ์์น + 5๋ถ ์์ + JSONL ๊ฐ์ฌ ๋ก๊ทธ |
| ์ฆ์ | ํ ์ค ๋ณต๊ตฌ | ์ ๋๋ฉด |
|---|---|---|
step-end ... ok:false ์ฒซ LLM ๋จ๊ณ ์คํจ |
"API ํค ํ๋ ์ด๊ณผ์์" โ weekly-report ๋์ 1๋จ๊ณ๋ง์ธ shell-only ์ฌ๋ก๋ก ์ฐํ |
runs/*.jsonl ๋ฏธ๋ฆฌ ์บก์ฒํด ๋ ์ด์ ์ฑ๊ณต ๊ฒฐ๊ณผ๋ฅผ ํ๋ฉด์ ๋์ |
| ๋ธ๋ผ์ฐ์ ์ ํ๊ตญ์ด ๊นจ์ง | ์๋ก๊ณ ์นจ (Ctrl/Cmd+R) โ Tailwind CDN ์บ์ ๋ฌธ์ 90% | ๋ค๋ฅธ ์ํฌํ๋ก์ฐ๋ก ์ฆ์ ์ ํ, ๊นจ์ง์ ๋ฏธํ ํ ์ฒ๋ฆฌ |
| SSE๊ฐ ๋ฉ์ถค (3์ด ์ด์ ์ถ๋ ฅ ์์) | "์ ์ LLM ์๋ต ๋๊ธฐ ์ค์ ๋๋ค" ํ ๋ง๋ + ์ฐํ๋ก ๋ค๋ฅธ ํญ ์ด์ด ๋ ๋ฒ์งธ ์ํฌํ๋ก์ฐ Run | ์ฒซ ํญ์ ๊ทธ๋๋ก ๋๊ณ ๋ ๋ฒ์งธ ํญ์์ ์งํ |
| ์๋ฒ ์์ฒด ์ฃฝ์ | ํฐ๋ฏธ๋ pnpm dev ์ฌ์คํ(2์ด) |
"๋ก์ปฌ ํ๊ฒฝ ๋ณ์๊ฐ ๊ผฌ์ฌ์์" ์์ง + ์บก์ฒ๋ณธ์ผ๋ก ๋ง๋ฌด๋ฆฌ |
- ์ด README ๋งํฌ (
#demo-path-first-run-in-5-minutes๋ก anchor) docs/sales/pilot-onepager.md๋ฅผ PDF๋ก ๋ณํํด ์ฒจ๋ถ โ ํ๊ตญ์ด ํฐํธ ํฌํจ:pandoc docs/sales/pilot-onepager.md -o docs/sales/pilot-onepager.pdf --pdf-engine=weasyprint --metadata title="FlowAgent โ Pilot 1-pager"(์ฌ์ ์ค์น:apt-get install -y pandoc weasyprint)- ๋ฏธํ
์ค ์์ฑํ ๊ท์ฌ ์ผ์ด์ค 1๊ฑด์ YAML ์ด์ (
workflows/<customer-slug>-draft.yamlํํ๋ก ์ฒจ๋ถ) - ๋ค์ ๋ฏธํ ํ๋ณด ์ผ์ 3๊ฐ (1์ฃผ์ฐจ ์ค์น ๋ฏธํ ์ฉ)
- ๋ค์ outreachยท์ค์น ๋ฏธํ
์ ์ ์ด๋ฉ์ผ โ ํ
ํ๋ฆฟ
docs/sales/pilot-outreach-email.md์ฌ์ฉ.{{ํ์ฌ๋ช }}/{{๋ด๋น์๋ช }}/{{ํ๋ณด1ยท2ยท3}}/{{๋ฐ์ ์๋ช }}์๋ฆฌํ์์๋ง ์นํํ๊ณ PDF ์ฒจ๋ถ ํ ๋ฐ์ก. Follow-upยทWarm introยท์ค์น ๋ฏธํ 3๊ฐ์ง ๋ณํ์ด ๊ฐ์ ํ์ผ ํ๋จ์ ์์.
The workflows/ directory ships eight end-to-end workflows covering the most common Korean SMB
office tasks for all three target personas (A ์ฌ๋ฌด์ง ยท B 1์ธ ์์์
ยท D ์ฌ์ฅ). All use Korean
fixtures under workflows/fixtures/ and English LLM prompts that emit Korean output
(see feedback_demo_fixture_language rule for why).
| Workflow | What it does | Persona (spec ยง 3) | ์์ ์ฃผ๋ ๋ฐ๋ณต ์ ๋ฌด ์คํธ๋ ์ค |
|---|---|---|---|
weekly-report |
ํ ์ฃผ ์งํ ๋ ธํธ โ 4-section ๊ตฌ์กฐํ โ Slack ๊ณต์ ์ฉ ๋ฉ์์ง | ์ฌ๋ฌด์ง A โ โ โ ยท ์ฌ์ฅ D โ โ | ๋งค์ฃผ ๊ฐ์ ๋ณด๊ณ ์๋ฅผ ์ฒ์๋ถํฐ ๋ค์ ์ฐ๋ 30๋ถ |
meeting-actions |
ํ์๋ก โ ๋ด๋น์๋ณ ์ก์ ํ โ Slack ๋ณด๊ณ ํฌ๋งท | ์ฌ๋ฌด์ง A โ โ โ ยท ์ฌ์ฅ D โ โ | ํ์ ๋๋๊ณ ํ์๋ก ๋ค์ ์ฝ์ผ๋ฉฐ ์ก์ ์ ์ถ๋ฆฌ๋ ์ธ์ง ๋ถํ |
sales-summary |
์๊ฐ ๋งค์ถ CSV โ ์ฑ๋ยท์ด์์น ๋ถ์ โ ๊ฒฝ์์ง 3-๋ฌธ์ฅ ์์ฝ | ์ฌ์ฅ D โ โ โ ยท ์ฌ๋ฌด์ง A โ โ ยท ์์์ B โ โ | ์๋ง๋ง๋ค ์ด์์น ์ฐพ๊ณ 1-pager ๋ง๋๋ ์๋ฐ |
inquiry-triage |
๊ณ ๊ฐ ๋ฌธ์ CSV โ ์นดํ ๊ณ ๋ฆฌยท๊ธด๊ธ๋ ๋ถ๋ฅ + ์นดํ ๊ณ ๋ฆฌ๋ณ ๋ต๋ณ ์ด์ | ์์์ B โ โ โ ยท ์ฌ๋ฌด์ง A โ โ | ๋งค์ผ ๊ฐ์ ํค์ผ๋ก ๋ต๋ณ ์ฐ๊ณ ์ฐ์ ์์ ๋งค๊ธฐ๋ ํผ๋ก |
approval-triage |
๊ฒฐ์ฌ ๋๊ธฐํจ โ ์๋์น์ธยท๊ฒํ ยท์ ๋ณด๋ถ์กฑ ๋ถ๋ฅ + ์ค๋์ brief | ์ฌ๋ฌด์ง A โ โ โ ยท ์ฌ์ฅ D โ โ | ๊ฒฐ์ฌํจ์ ์ค์ ์์ฒญ์ ํ๋์ฉ ์ฝ๊ณ ํ๋จํ๋ ์ธ์ง ๋ถํ |
| Workflow | What it does | Persona (spec ยง 3) | ์์ ์ฃผ๋ ๋ฐ๋ณต ์ ๋ฌด ์คํธ๋ ์ค |
|---|---|---|---|
quote-email |
ํ๋ก์ ํธ brief + ๋ณธ์ธ ๋จ๊ฐ ๊ฐ์ด๋ โ ๊ฒฌ์ ํญ๋ชฉยท๊ธ์ก ์ฐ์ โ ๊ณ ๊ฐ ํ์ ๋ฉ์ผ ์ด์ | ์์์ B โ โ โ | ๋งค๋ฒ ๋น์ทํ ๊ฒฌ์ ๋ฉ์ผ ๋ค์ ์ฐ๋ฉฐ ๋จ๊ฐยท์ผ์ ยท์ธ๊ธ ์กฐ๊ฑด ๋น ๋จ๋ฆฌ๋ ๋ถ์ |
sales-followup |
๊ณ ๊ฐ ๋ฏธํ ยทํตํ raw ๋ ธํธ โ ๋ค์ ์ก์ ยท์ฝ์ยท์ถ๊ฐ ๊ฒฌ์ ๋ถ๋ฆฌ + follow-up ๋ฉ์ผ + ์ผ์ ์ ์ | ์์์ B โ โ โ | ๋ฏธํ ๋๋๊ณ ๋จธ๋ฆฟ์ ํฉ์ด์ง ์ก์ ยท์ฝ์ยท๋ค์ ์ผ์ ์ ๋ฉ๋ชจ๋ก ๋ชป ์ฎ๊ธฐ๋ ๋ถ๋ด |
sns-replies |
์ธ์คํยท๋ธ๋ก๊ทธ ํ ์ฃผ๊ฐ ๋๊ธยทDM raw ๋ชฉ๋ก โ ์คํธ ๊ฑฐ๋ฆ + ์นดํ ๊ณ ๋ฆฌ๋ณ ๋ต๊ธ ์ด์ + ํ์ ยท๊ฒฌ์ lead ๋ณ๋ ์ถ์ | ์์์ B โ โ โ | ๋งค์ผ ๋ค์ด์ค๋ ์ธ์คํ DMยท๋ธ๋ก๊ทธ ๋๊ธ์ ์ผ์ผ์ด ๋ต๊ธ ํค ๋ง์ถ๊ณ ์คํธ ๊ฑฐ๋ฅด๊ณ ์ง์ง lead ๋์น์ง ์๋ ํผ๋ก |
To adapt one for a real Pilot case, edit the file in workflows/fixtures/ to the customer's own data โ
the YAML prompts stay the same. The customer's data never leaves their machine.
๊ท์ฌ ์ฌ๋ก 1๊ฑด์ ๋ฏธํ ์๋ฆฌ์์ ๊ฐ์ด ์ํฌํ๋ก์ฐ๋ก ๋ง๋๋ ์๋. ๋น๊ฐ๋ฐ์๋ ์ด์์์ ํจ๊ป 3๋จ๊ณ๋ก ๋ฐ๋ผ์ต๋๋ค. ๋ณธ์ธ์ด ์ฑ์ฐ๋ ์นธ์ 5๊ฐ(ํ๊ตญ์ด), ์๋ฌธ LLM ํ๋กฌํํธ 4๊ฐ๋ ์ด์์๊ฐ ๊ฐ์ด ์ฑ์์ค๋๋ค.
1๋จ๊ณ โ ๋ณต์ฌ (PowerShellยทํฐ๋ฏธ๋ ํ ์ค, <ํ์ฌ> ์๋ฆฌ์ ๋ณธ์ธ ํ์ฌ ์๋ฌธ ์ฝ์ด)
cp workflows/_pilot-draft-template.yaml workflows/acme-draft.yaml2๋จ๊ณ โ fixture 1๊ฑด ๋๊ธฐ
๋ณธ์ธ ๋ฐ์ดํฐ ํ์ผ(ํ์๋ก .md / ๋งค์ถ .csv / ๋ฌธ์ .csv / ๊ฒฐ์ฌ .md ์ค ํ๋)์ ์๋ ์์น์ ๊ฐ์ ์ด๋ฆ์ผ๋ก ์ ์ฅ:
workflows/fixtures/acme-sample.md
3๋จ๊ณ โ ์๋ฆฌํ์์ ์ฑ์ฐ๊ธฐ (์๋ ํ ์ฐธ์กฐ)
| ์ฑ์ฐ๋ ์ฌ๋ | placeholder | ์์ | ์ด๋์ ์ฐ์ |
|---|---|---|---|
| ๋ณธ์ธ | {{customer-slug}} |
acme |
renameยทfixture ํ์ผ๋ช ๊ณผ ์ผ์น (์๋ฌธ ์๋ฌธ์) |
| ๋ณธ์ธ | {{ํ์ฅ์}} |
md / csv |
์ fixture ํ์ฅ์ |
| ๋ณธ์ธ | {{๋ด๋น์_ํ๋ฅด์๋}} |
์ด์ / ์ฌ๋ฌด๊ด๋ฆฌ |
์นด๋ ํ๋ฅด์๋ ํํฐ |
| ๋ณธ์ธ | {{๊ท์ฌ๊ฐ_๊ฒช๋_๋ฐ๋ณต_์
๋ฌด_ํ_์ค}} |
๋งค์ฃผ ๋์ผํ ์์ ๋ณด๊ณ ์ ๋ค์ ์ฐ๊ธฐ |
์นด๋ stressRelieved |
| ๋ณธ์ธ | {{ํ์ฌ๋ช
}} |
Acme |
๊ฒฐ๊ณผ wrap ํค๋ |
| ๋ณธ์ธ | {{์ํฌํ๋ก์ฐ_์ ๋ชฉ}} |
์ฃผ๊ฐ ์ก์
์ ๋ฆฌ |
๊ฒฐ๊ณผ wrap ํค๋ |
| ์ด์์ | {{์
๋ ฅ_์ข
๋ฅ_์๋ฌธ}} |
a Korean weekly meeting note |
2๋จ๊ณ LLM prompt |
| ์ด์์ | {{์ถ์ถ_๋ชฉํ_์๋ฌธ}} |
every action item with owner and deadline |
2๋จ๊ณ LLM prompt |
| ์ด์์ | {{์ถ๋ ฅ_ํ์_์๋ฌธ}} |
Korean Markdown table |
2๋จ๊ณ LLM prompt |
| ์ด์์ | {{์ ๋ฌ_์ฑ๋_์๋ฌธ}} |
Slack-ready Korean message |
4๋จ๊ณ LLM prompt |
์๋ฃ ํ โ ๋ธ๋ผ์ฐ์ listing(/) ์๋ก๊ณ ์นจ โ ์ ์นด๋ ์๋ ๋ฑ์ฅ โ Run.
_ prefix ํ์ผ์ listing/route์์ ์๋ ์ ์ธ (src/workflows-dir.ts). ์๋ ์์ฒด๋ listing์ ์ ๋ณด์ด๊ณ /workflows/_pilot-draft-templateยท/run ๋ชจ๋ 404. ๋ฐ๋ชจ ์ค ๋ฏธ์์ฑ placeholder๊ฐ ๊ณ ๊ฐ์๊ฒ ๋
ธ์ถ๋ ์ํ ์์. ๋ณ๋ ๋น๊ณต๊ฐ ์๋๋ฅผ ๋ ๋๋ ค๋ฉด ๋์ผํ๊ฒ _ prefix๋ก ์์ํ๋ ํ์ผ๋ช
์ ์ฌ์ฉ.
Drop a <name>.yaml file in workflows/. The filename (without extension) becomes the URL slug; the
name: field is the human-readable label shown in the UI. See
workflows/weekly-report.yaml for a working 3-step demo.
name: my-workflow
description: One-line summary shown on the list page.
steps:
- type: llm
name: draft # optional, used in event logs
prompt: |
Write a haiku about workflows.
- type: shell
name: wrap
command: |
node -e "process.stdout.write('=== Output ===\n' + {{prev}} + '\n')"
- type: llm
prompt: |
Translate to Korean:
{{prev}}{{prev}} is replaced with the previous Step's output. Different rules per step type:
-
llmstep โ{{prev}}is spliced into the prompt string verbatim. No escaping needed. -
shellstep โ{{prev}}is replaced with the JS expressionprocess.env.FLOWAGENT_PREV, and the previous output is passed via the child process's environment. The shell command must be anode -e "..."one-liner โ this makes commands cross-platform (PowerShell, cmd, Git Bash, sh, bash all execute identically) and neutralizes backticks,$(),$VAR, and semicolon chains inside untrusted LLM output because Node reads the value at runtime instead of the shell tokenizing it.# โ Recommended โ Node one-liner reads prev as a JS expression command: | node -e "process.stdout.write({{prev}})" # โ Wrap with a banner command: | node -e "process.stdout.write('=== Header ===\n' + {{prev}} + '\n=== End ===\n')" # โ Load a fixture file (replaces `cat <path>` from sh-only workflows) command: | node -e "process.stdout.write(require('fs').readFileSync('workflows/fixtures/data.csv','utf8'))" # โ Avoid โ sh-specific, fails on Windows PowerShell/cmd command: printf '%s' "{{prev}}" command: cat workflows/fixtures/data.csv
Place
{{prev}}unquoted as a bare token inside the Node expression โ it expands to a JS variable, not a string literal.
src/
spec.ts # Zod schema + loadWorkflow(filePath) โ YAML โ typed Workflow
runner.ts # runWorkflow() โ sequential execution + SSE-style event callback
runners.ts # createDefaultRunners() โ wires llm + shell step runners
workflows-dir.ts # listWorkflows(dir) โ file scanner
server.ts # Hono app factory (env-driven)
main.ts # HTTP entry โ @hono/node-server bind
routes/
workflows.ts # GET /, GET /workflows/:name, POST /workflows/:name/run (SSE)
steps/
llm.ts # Anthropic SDK call
shell.ts # child_process.exec with FLOWAGENT_PREV env-var injection
views/
layout.tsx # Tailwind CDN shell
index.tsx # workflow list page
run.tsx # workflow detail page + SSE client
error.tsx # 404 / 500 page
workflows/ # *.yaml โ your workflows live here
runs/ # <runId>.jsonl โ one line per SSE event, written live
docs/adr/ # architecture decisions
.claude/ # project skills, agents, commands (Claude Code config)
Every workflow run streams its events live to runs/<runId>.jsonl as well as over SSE. One JSON object
per line, in event order: step-start, step-output, step-end (ร number of steps), then done. The
file basename equals the runId reported in the done event.
# Replay the most recent run
tail -n +1 "$(ls -t runs/*.jsonl | head -1)" | jq .
# Show just the outputs for a given run
jq -r 'select(.kind=="step-output") | .output' runs/<runId>.jsonlDisk writes happen before SSE writes, so the log stays complete even if the client disconnects mid-run.
Pilot customers often want proof that automation actually saved time. The JSONL format makes this a one-liner:
# How many runs this month, and which workflows?
ls runs/2026-05-*.jsonl | wc -l
jq -r '.step.name // empty' runs/*.jsonl | sort | uniq -c | sort -rn
# Pull every Slack-ready output from this month for archival
jq -r 'select(.kind=="step-output" and .index==3) | .output' runs/2026-05-*.jsonlPair this with a calendar reminder ("๋งค์ 1์ผ ์๋ํ ํจ๊ณผ ๋ฆฌํฌํธ") and the customer has a recurring business-value artifact without touching the runner.
pnpm test # vitest, one shot
pnpm test:watch # vitest watch
pnpm typecheck # tsc --noEmit
pnpm dev # tsx watch with .env autoload
pnpm start # production-ish single shotTest layout mirrors source (*.test.ts next to the file). All step runners and routes have unit coverage;
the SSE route test exercises the full event sequence with fake runners.
See CLAUDE.md for the full agent-facing config. The short version:
- Align before you code โ
/grillfor non-trivial requests. - Spec โ Build โ Review โ one skill per lifecycle phase, see
.claude/skills/. - Maintainability first โ code should be readable by a developer who lands on this repo cold. Prefer editing existing files; surface assumptions; sanitize at every trust boundary.
- No DAG, no branching, no parallel steps. Linear only.
- No retry, no resume, no checkpointing.
- No auth โ bind to localhost only.
- Run logs are not rotated or pruned โ clean
runs/manually if it grows.