Voicebar
음성 우선 Android 키보드, Gboard와 함께 사용 음성 입력 후 정리된 메시지가 입력란에 들어갑니다
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Self-hosted Pomodoro timer, viewer task list, Twitch chat bot, and OBS overlays for co-working and body-doubling streams
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗DireWork is a personal project built for my own Twitch co-working and body-doubling streams. It combines a Pomodoro timer, viewer task list, and Twitch chat bot into a single self-hosted tool with customizable OBS overlays.
It is open source and supports Cloudflare's free plan for the core app, within the account's usage limits. Free-tier support is a project commitment; no paid Cloudflare service is required. Fork it and deploy your own instance: one streamer, one owner, one channel.
DireWork is always self-hosted. MrDemonWolf, Inc. does not offer hosted instances or a managed hosting service.
!task, !done, !timer start, and !timer eta. Reply
templates are editable (a few usage hints are fixed), and the task
and timer command groups can be turned off. The bot runs in a token-gated browser page (an
invisible widget in OBS or Moblin, or a dock in OBS or a pinned tab), so no always-on
server is needed.For full setup instructions including Twitch OAuth, bot account configuration, and OBS setup, see the Documentation.
Deploy on Cloudflare opens the guided setup. The core app supports the free tier; no paid service or local development setup is required. Initial setup needs your Twitch keys and GitHub secrets; the link does not provision resources with one click.
To try it locally first, follow Development.
| Command | Description |
|---|---|
!task <text> | Add a new task |
!done [number] | Mark your active (or a numbered) task done |
!edit <number> <text> | Edit the numbered task |
!remove <number> | Remove the numbered task |
!focus <number> | Make the numbered task your active task |
!start <number> | Start a task beside your focus (3 at once) |
!pause [number] | Pause your focus (or a numbered task) |
!check [@user] | Show your (or another user's) active task |
!today | Show your focus and next numbered tasks |
!next <text> | Complete active task and start a new one |
!help | Show the command help message |
| Command | Description |
|---|---|
!clear all | Clear all tasks |
!clear done | Clear completed tasks |
!clear @user | Remove all tasks from a specific user |
!mute | Pause the bot: ignore every command, post nothing |
!unmute | Resume the bot |
!block @user | Ignore a viewer's commands and remove their tasks |
!unblock @user | Let a blocked viewer use commands again |
| Command | Description |
|---|---|
!timer start [cycles] | Start the timer (optional cycle count 1-99) |
!timer pause | Pause the timer |
!timer resume | Resume the timer |
!timer skip | Skip the current phase |
!timer reset | Reset the timer |
!timer eta | Show time left in the current phase and the whole session |
See the full command reference
for all options and customizable bot responses. Viewers can run !dw help in chat at any
time for a 3-step starter guide, !dw help task (or any command) for a plain-language
explanation, and !dwhelp or !dwcommands for the full command list.
Go to /dashboard/bot to manage your bot account, edit the
response messages, enable or disable the task and timer command
groups, set up command aliases, and copy your bot page link.
The bot listens to chat while its page is open. Pick how you run it: the widget is
blank and transparent, so it can sit on any OBS or Moblin scene; the dock shows status
and controls in an OBS custom browser dock or a pinned tab. Keep to one
copy: a second one is harmless (DireWork runs each chat
message once, by its Twitch message id), but it doubles the
Worker requests every command costs.
Treat the bot console and overlay URLs as bearer credentials: anyone with a copied link can use it until you regenerate the corresponding token.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router), React 19, TypeScript 7 |
| Styling | Tailwind CSS v4, shadcn/ui |
| API | Hono + tRPC v11, TanStack React Query |
| Auth | Better Auth (Twitch OAuth) |
| Database | Cloudflare D1 (SQLite) + Drizzle ORM |
| Chat Bot | IRC-over-WebSocket in a token-gated browser page |
| Runtime | Cloudflare Workers (web via OpenNext) |
| Deploy | Alchemy (infrastructure-as-code) + GitHub Actions |
| Docs | Fumadocs |
| Monorepo | Turborepo + Bun workspaces |
Clone the repository:
git clone https://github.com/mrdemonwolf/dirework.git
cd dirework
Install dependencies:
bun install
Create your environment file:
cp .env.example packages/infra/.env
Fill in TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET from
dev.twitch.tv/console/apps,
and generate BETTER_AUTH_SECRET with openssl rand -base64 32.
Add http://localhost:3001/api/auth/callback/twitch and
http://localhost:3001/api/bot/callback/twitch as redirect URLs
on your Twitch app.
Start everything:
bun run dev
Alchemy runs the API worker (port 3000), the web app (port 3001), and a local D1 database with migrations applied.
bun run dev - Start all apps with a local D1 databasebun run dev:web - Start only the web app (standalone Next dev on port 3001; the API comes from bun run dev or a deployed origin)bun run build - Build all apps for productionbun run lint - Lint and format-check with Biomebun run audit:dependencies - Fail on unmitigated high-severity dependency advisoriesbun run lint:fix - Apply Biome's safe lint fixes and formattingbun run format - Format the whole repo with Biomebun run tokens - Regenerate the design-system outputs from design-system/tokens.jsonbun run check-types - Run TypeScript type checkingbun run test - Run unit tests across all packagesbun run test:coverage - Run tests with coverage thresholds enforcedbun run recovery:check - Check a synthetic local database export/import; does not access productionbun run clean - Remove generated build and type artifactsbun run db:generate - Generate a new Drizzle migration from schema changesbun run deploy - Deploy both workers and the database to Cloudflarebun run destroy - Tear down the Cloudflare deploymentbun run testDireWork deploys to Cloudflare Workers via GitHub Actions:
set seven repository secrets and two variables, push to main. Both
workers, the D1 database, and its migrations are managed by
Alchemy.
Sign in immediately after the first deploy. Until someone signs in, the instance is unclaimed and the first Twitch account to sign in (anyone's) becomes its owner. Don't share the URL before you've claimed it. If someone else claimed it, follow Recovering an instance someone else claimed.
See the Deployment guide for the step-by-step walkthrough (Cloudflare API token, Twitch redirect URLs, GitHub secrets, and the post-deploy checklist). On a fork, enable Actions first (GitHub turns workflows off on new forks), then run Actions → Deploy → Run workflow. To pick up new releases later, follow Updating your instance.
Before relying on an instance for a stream, complete the guide's post-deploy checklist, monitoring, and recovery checks. Free-tier quotas are shared across your Cloudflare account; leaving OBS sources open continues to use requests. See Free plan limits.
For repository documentation, start with the documentation map. It separates current guides and architecture decisions from dated historical reviews.
dirework/
├── apps/
│ ├── web/ # Next.js app on Workers (dashboard, overlays, bot page), port 3001
│ ├── server/ # Hono API worker (auth, tRPC, bot OAuth), port 3000
│ └── fumadocs/ # Documentation site, port 4000
├── packages/
│ ├── api/ # tRPC routers, services, bot command logic
│ ├── auth/ # Better Auth configuration
│ ├── db/ # Drizzle schema + D1 client + migrations
│ ├── env/ # Environment bindings + validation
│ ├── infra/ # Alchemy infrastructure (workers + D1)
│ ├── fonts/ # Self-hosted UI fonts shared by app and docs
│ ├── overlay-kit/ # Shared overlay geometry + clock formatting (web + docs)
│ ├── e2e/ # Local Worker browser tests and synthetic recovery drill
│ └── config/ # Shared TypeScript configuration
Report vulnerabilities privately and follow the production operator checklist in SECURITY.md. Never include credentials, bearer URLs, personal data, or exploit details in a public issue.
If you have any questions, suggestions, or feedback:
Made with love by MrDemonWolf, Inc.