askimut - Turn-Based Game System#
A formally specified, test-driven turn-based game system built on SolidStart with AT Protocol integration.
🎯 Current Status: Core game logic complete with 67 passing tests. UI components implemented. Ready for PostgreSQL connection.
🎮 Game Features#
Core Gameplay (✅ Complete)#
- ✅ Turn-based message posting (2-8 players)
- ✅ Round-robin turn rotation
- ✅ "Done" action for scene completion
- ✅ Automatic scene/act/game progression
- ✅ Visual feedback (active player, done status)
- ✅ 67 tests passing - 100% spec coverage
Game Rules (From Formal Specification)#
- Games have 2-8 players and 1-10 acts
- Scenes have 2-3 players (even total = 2, odd total = 3)
- Players take turns posting messages
- After each message, next player becomes active
- Players can mark themselves "done"
- Scene ends when all players are done
- Act ends when all scenes are done
- Game ends when all acts are done
AT Protocol Features#
- Custom lexicons for game records
- OAuth authentication
- Firehose ingester for real-time synchronization
- PostgreSQL database with Drizzle ORM
🚀 Quick Start#
Run Tests (No Database Required)#
# Install dependencies
pnpm install
# Run all tests
pnpm test:run
# Expected output:
# ✓ 67 tests passing
Run Full App (Requires PostgreSQL)#
# 1. Start PostgreSQL
docker start askimut-db
# or: docker-compose up -d postgres
# 2. Push database schema
pnpm db:generate
pnpm db:push
# 3. Generate lexicon types (optional)
pnpm lexgen
# 4. Start dev server
pnpm dev
# 5. Create a game
# Navigate to: http://localhost:3000/game/new
Prerequisites#
- Node.js >= 20
- pnpm
- PostgreSQL (only needed for running the app, not tests)
🛠️ Development Process#
We follow a strict 5-step methodology for all features:
1. Alloy Modeling → specs/alloy/*.als
2. Database Schema → src/db/schema.ts + migrations
3. Type Definitions → test-types.ts, validation.ts
4. Behavioral Tests → Loop until all pass ✅
5. UI + TDD Loop → Integration test → UI → Pass ✅
See DEVELOPMENT_PROCESS.md for complete methodology.
Quick Reference: .dev-process-quick-ref.md
📚 Documentation#
Essential Reading#
- DEVELOPMENT_PROCESS.md - Our development methodology (required for contributors)
- .dev-process-quick-ref.md - Quick reference card
Implementation Details#
- IMPLEMENTATION.md - Technical implementation guide
- UI_SPEC_MAPPING.md - How UI fulfills spec requirements
- VISUAL_DEMO.md - Visual demonstration of features
- COMPLETE_SUMMARY.md - Comprehensive overview
- src/tests/README.md - Test suite documentation
Specifications#
- specs/alloy/base.als - Formal Alloy model
- specs/md/base.md - 8 game rules in plain English
📊 Test Coverage#
$ pnpm test:run
✓ src/__tests__/integration.test.ts (9 tests)
✓ src/__tests__/structural-constraints.test.ts (31 tests)
✓ src/__tests__/temporal-behavior.test.ts (27 tests)
Test Files 3 passed (3)
Tests 67 passed (67)
Coverage:
- 100% of Alloy predicates tested
- 100% of game rules tested
- All UI features have integration tests
🎯 Available Commands#
# Testing
pnpm test # Watch mode (TDD)
pnpm test:run # Run once
pnpm test:ui # Interactive UI
pnpm test:coverage # With coverage
# Development
pnpm dev # Start dev server
pnpm build # Build for production
pnpm start # Start production server
# Database
pnpm db:generate # Generate migrations
pnpm db:push # Push schema to database
# AT Protocol
pnpm lexgen # Generate lexicon types
pnpm ingester # Run firehose ingester
🗂️ Project Structure#
askimut/
├── specs/
│ ├── alloy/base.als # Formal specification
│ └── md/base.md # 8 rules in plain English
│
├── src/
│ ├── __tests__/
│ │ ├── utils/
│ │ │ ├── test-types.ts # Domain model types
│ │ │ └── test-helpers.ts # Alloy predicates → functions
│ │ ├── temporal-behavior.test.ts # 27 tests
│ │ ├── structural-constraints.test.ts # 31 tests
│ │ └── integration.test.ts # 9 tests
│ │
│ ├── db/
│ │ ├── schema.ts # 11 database tables
│ │ └── game.ts # Game CRUD operations
│ │
│ ├── routes/
│ │ ├── game/
│ │ │ ├── [id].tsx # Main game UI (text+post+done)
│ │ │ └── new.tsx # Game creation
│ │ └── index.tsx # Home page
│ │
│ ├── game-logic.ts # Business logic
│ └── api/ # Authentication
│
└── Documentation/ # 7 detailed docs
Testing with curl#
1. Create a Message via AT Protocol#
To push a message directly to your PDS using the AT Protocol API:
# First, get an access token by authenticating
# (Replace with your actual credentials and PDS URL)
# Create a session
curl -X POST https://bsky.social/xrpc/com.atproto.server.createSession \
-H "Content-Type: application/json" \
-d '{
"identifier": "your-handle.bsky.social",
"password": "your-app-password"
}'
# Extract the accessJwt from the response, then create a record
curl -X POST https://bsky.social/xrpc/com.atproto.repo.putRecord \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_JWT" \
-d '{
"repo": "your-handle.bsky.social",
"collection": "xyz.askimut.message",
"rkey": "'"$(date +%s)"'",
"record": {
"$type": "xyz.askimut.message",
"message": "Hello from curl!",
"createdAt": "'"$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)"'"
}
}'
2. Query Messages from Your Database#
Once the ingester picks up the message from the firehose:
# Check messages in the database
psql postgresql://postgres:postgres@localhost:5433/askimut \
-c "SELECT * FROM \"post\" ORDER BY \"indexedAt\" DESC LIMIT 10;"
3. Using the Web Interface#
Alternatively, you can:
- Visit http://localhost:3000
- Log in with your AT Protocol handle
- Post a message through the web form
- Watch the ingester pick it up from the firehose
Project Structure#
src/ingester.ts- Firehose subscription logicsrc/ingester-server.ts- Standalone ingester processsrc/id-resolver.ts- DID/handle resolution utilitiessrc/lexicon/- Generated lexicon typeslexicons/message.json- Custom lexicon definitionsrc/db/- Database schema and queriessrc/routes/- Web application routes
Lexicon#
This project uses a custom lexicon xyz.askimut.message:
{
"lexicon": 1,
"id": "xyz.askimut.message",
"defs": {
"main": {
"type": "record",
"key": "tid",
"record": {
"type": "object",
"required": ["message", "createdAt"],
"properties": {
"message": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"createdAt": { "type": "string", "format": "datetime" }
}
}
}
}
}
Environment Variables#
Create a .env file with:
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/askimut
COOKIE_SECRET=your-random-32-character-secret
HOST=0.0.0.0
PORT=3000
NITRO_HOST=127.0.0.1
NITRO_PORT=3000
Building#
pnpm build
pnpm start
🎉 Current Achievement#
This project demonstrates a complete specification-driven development workflow:
✅ Formal Specification (Alloy model) ✅ Database Schema (11 tables from spec) ✅ Type-Safe Logic (TypeScript + Valibot) ✅ 67 Passing Tests (100% coverage of specs) ✅ Working UI (Text input + Post button + Done button) ✅ Complete Documentation (7 detailed docs)
Key Innovation: Every game rule is proven correct by tests that directly implement the Alloy predicates.
📖 Learn More#
- Development Process: Start with DEVELOPMENT_PROCESS.md
- Quick Start: Run
pnpm test:runto see all 67 tests pass - Play a Game: Follow setup instructions and visit
/game/new
This project was created with the Solid CLI