{"id":50915006,"url":"https://github.com/clockworklabs/scrabblebot","last_synced_at":"2026-06-16T14:01:10.788Z","repository":{"id":362801766,"uuid":"1260849757","full_name":"clockworklabs/scrabblebot","owner":"clockworklabs","description":"Scrabble-style auction game for AI bots, built on SpacetimeDB","archived":false,"fork":false,"pushed_at":"2026-06-06T00:35:21.000Z","size":596,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-06T02:17:41.128Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clockworklabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-06T00:12:11.000Z","updated_at":"2026-06-06T00:18:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/clockworklabs/scrabblebot","commit_stats":null,"previous_names":["clockworklabs/scrabblebot"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/clockworklabs/scrabblebot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clockworklabs%2Fscrabblebot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clockworklabs%2Fscrabblebot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clockworklabs%2Fscrabblebot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clockworklabs%2Fscrabblebot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clockworklabs","download_url":"https://codeload.github.com/clockworklabs/scrabblebot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clockworklabs%2Fscrabblebot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34408788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-16T14:01:09.794Z","updated_at":"2026-06-16T14:01:10.771Z","avatar_url":"https://github.com/clockworklabs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ScrabbleBot\n\nA Scrabble-style auction game where AI bots compete for letters.\n\nEach round the module reveals one letter from a shared Scrabble bag and runs a\n1-second sealed-bid auction. The highest bidder wins the letter, adds it to\ntheir rack, and pays (Vickrey or first-price). Bots play words from their\ncollected letters at any time to earn currency, which funds future bids. Long\nwords pay a superlinear bonus, so hoarding is rewarded.\n\nBuilt on [SpacetimeDB](https://spacetimedb.com): rules, timing, lobby\nformation, dictionary — all inside a Rust module. Bots are external\nSpacetimeDB clients (any language); the spectator UI is a Vite + React app.\n\nLive at **[scrabblebot.vercel.app](https://scrabblebot.vercel.app)** ·\nBot-writing docs: **[/docs](https://scrabblebot.vercel.app/docs)**\n\n## Repo layout\n\nThe web client lives at the repo root (standard SpacetimeDB project shape);\nthe module is nested inside it.\n\n| Path | What it is |\n|---|---|\n| `src/`, `index.html`, `vite.config.ts` | Vite + React spectator UI |\n| `spacetimedb/` | Rust module — schema, reducers, scheduled lobby + auction ticks, dictionary |\n| `bot-starter/` | TypeScript starter bot — fork \u0026 edit `src/strategy.ts` |\n\n## How a match comes together\n\nThere's a single rolling **lobby** that's always open for 60 seconds at a\ntime:\n\n- Real bots `join_lobby()` at any time.\n- If 6 real bots join → match starts immediately.\n- If the timer expires → match starts with whoever's there, padded out to 6\n  with idle simulated bots.\n- A fresh lobby opens the moment the previous one resolves.\n\nThis means matches run continuously without anyone having to manually\nschedule them. Bots that finish a match just call `join_lobby()` again.\n\n## The rules\n\n- **Auction:** 1-second sealed-bid window per letter. Highest bid wins; on\n  ties, the earlier submission wins.\n- **Payment:** Vickrey by default (winner pays the runner-up's bid; reserve\n  1). First-price is configurable per lobby.\n- **Currency:** start at 100 per match. Reward for a word = base score ×\n  length multiplier (1.0× ≤3 letters → 3.0× ≥7 letters). Reward goes into\n  both `balance` (spendable) and `score` (ranking).\n- **Letters:** standard 98-tile Scrabble bag (no blanks). Match ends when the\n  bag empties. Tiles nobody bids on go back to the bag.\n- **Visibility:** `Holding` and `BagLetter` are private. Bots see only their\n  own rack via the `my_rack` view; nobody can subscribe to the full bag\n  composition. The spectator reconstructs opponents' racks from public\n  `AuctionResult` + `WordPlay` events.\n- **Dictionary:** the public-domain\n  [ENABLE](https://en.wikipedia.org/wiki/Moby_Project#ENABLE) wordlist\n  (~173k words), embedded from `spacetimedb/wordlist.txt`. Swap in TWL or\n  SOWPODS if you have a license.\n- **Rating:** per-bot ELO updates pairwise at every match end (K=32).\n\n## Writing a bot (5-minute version)\n\nThree steps end-to-end:\n\n1. **Get a token** — on the live site, link your spacetimedb.com identity at\n   `/account`, then create a team at `/team/new`, then click *Generate token*\n   on `/team`. You'll get a SpacetimeDB JWT bound to a credential for your\n   team's bot persona (shown once).\n2. **Fork the starter** and plug the token in:\n   ```bash\n   git clone https://github.com/clockworklabs/scrabblebot\n   cd scrabblebot/bot-starter\n   npm install\n   npm run generate\n   BOT_NAME=alice BOT_TOKEN=\u003ctoken\u003e npm start\n   ```\n3. **Edit `bot-starter/src/strategy.ts`** — two functions:\n   - `decideBid(ctx)` — return how much to bid for the current letter.\n   - `chooseWord(ctx)` — pick a word to play from your rack.\n\nThat's it. Your bot will auto-join the lobby, play in matches as they form,\nand re-join after each one ends. Token is persisted to\n`.token-\u003cBOT_NAME\u003e` after the first run.\n\nFor a deeper writeup — what's visible to your bot, the reducer API, the\nSpacetimeDB connection snippet end-to-end — see **[/docs](https://scrabblebot.vercel.app/docs)**.\n\nBots can use any language SpacetimeDB has an SDK for (Rust, C#, TypeScript).\nThe starter is just convenience; the reducer interface is language-agnostic.\n\n## Running the project locally\n\nFor development work on the module or UI:\n\n```bash\nnpm install\nnpm run dev\n```\n\nThis launches `spacetime dev` against maincloud — auto-builds the module,\npublishes it, regenerates client bindings, and starts the Vite client on\nhttp://localhost:5173. Edit `spacetimedb/src/lib.rs` and changes flow\nstraight through to the browser.\n\nThe maincloud database name is set in `spacetime.local.json` (defaults to\n`scrabblebot`). The `init` reducer seeds a default admin and the simulated\nbot pool on every fresh database init.\n\n### Other npm scripts\n\n- `npm run dev:local` — same flow against a local `spacetime start` server.\n- `npm run publish` — one-shot publish to the configured server.\n- `npm run generate` — regenerate client bindings without the watcher.\n- `npm run build` / `npm run preview` — production build of the spectator.\n\n## Tournament mode\n\n`/admin` (admin-only) has a tournament launcher: Swiss rounds → top-N cut →\nsingle-elimination bracket → best-of-3 finals. Match size, Swiss round\ncount, and top cut are configurable. ELO ratings are updated independently\nof tournament standings.\n\n## Known limitations\n\n- `auction_tick` and `lobby_timeout_tick` are callable by any client today.\n  Fine for a hackathon, but a hardened deploy should gate them.\n- No human play — bots only.\n- Token-recovery for bots is via the *rotate* model: mint a new credential\n  on `/team` and the old token keeps working in parallel. The bot persona\n  itself survives.\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclockworklabs%2Fscrabblebot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclockworklabs%2Fscrabblebot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclockworklabs%2Fscrabblebot/lists"}