Voicebar
A voice-first keyboard for Android that works alongside Gboard. Tap Voice, talk, and a tidy message lands in the box.
翻譯準備中
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證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.