Harness the powers that came before us to build what will come after.
- Mystical Board Interface - Tasks flow through six thematic columns from conception to completion
- Autonomous Task Execution - Integration with Sprites.dev to spawn Claude Code sessions
- AI Feedback Loop - Comment-based communication between humans and agents
- GitHub Integration - Auto-generates feature branches and pull requests
- Dark Occult Theme - Sleek, minimal UI with mystical aesthetics
Tasks progress through mystical columns:
- The Abyss - Backlog of tasks waiting in darkness
- The Altar - Tasks prepared and ready for execution
- The Ritual - Active execution (triggers Claude Code session)
- Cursed - Blocked tasks with errors
- The Trial - Completed tasks awaiting human review
- Vanquished - Successfully completed and approved
| Category | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| Language | TypeScript 5 |
| Functional | Effect-TS |
| Database | PostgreSQL via Drizzle ORM + @effect/sql |
| Auth | better-auth (Email OTP, passwordless) |
| Resend | |
| Styling | Tailwind CSS 4 |
| Telemetry | Sentry + OpenTelemetry |
| Analytics | PostHog |
| Testing | Vitest |
-
Clone and rename:
git clone <repo> my-project cd my-project rm -rf .git && git init git branch -M main
-
Install dependencies:
pnpm install
-
Set up environment:
cp .env.example .env.local cp .env.example .env.test # For e2e tests (use a separate test database)File Purpose .env.localDevelopment - used by Next.js, Drizzle, Vitest .env.testE2E tests - used by Playwright (separate test database) Both files are gitignored.
Variable Required Description DATABASE_URLYes PostgreSQL connection string DATABASE_SSLNo Enable SSL for database (default: false) BETTER_AUTH_SECRETYes Secret for better-auth session encryption NEXT_PUBLIC_PROJECT_URLYes Public URL of the application APP_NAMENo Application name (default: Init) EMAIL_SENDERYes Email sender address for auth emails RESEND_API_KEYNo Resend API key for sending emails ENCRYPTION_KEYYes 32-byte hex key for AES-256-GCM encryption SPRITES_TOKENYes Sprites.dev API authentication token SPRITE_TIMEOUT_MSNo Timeout for sprite operations (ms) OPENCODE_SETUP_REPO_URLYes GitHub repo URL for opencode commands/skills AWS_ACCESS_KEY_IDNo AWS credentials for S3 AWS_SECRET_ACCESS_KEYNo AWS credentials for S3 AWS_REGIONNo AWS region for S3 AWS_S3_BUCKETNo S3 bucket name for file uploads TELEGRAM_BOT_TOKENNo Telegram bot token for notifications TELEGRAM_CHAT_IDNo Telegram chat ID for notifications SENTRY_PROJECTNo Sentry project slug SENTRY_AUTH_TOKENNo Sentry auth token for source maps NEXT_PUBLIC_SENTRY_DSNNo Sentry DSN for error reporting NEXT_PUBLIC_POSTHOG_KEYNo PostHog project API key for analytics Auto-set by Vercel:
VERCEL_URL,VERCEL_BRANCH_URL -
Run development server:
pnpm dev
lib/
├── core/ # Core business logic (each subfolder has own errors)
│ └── post/ # Example: getPosts()
├── services/ # Infrastructure services
│ ├── auth/ # Authentication (better-auth)
│ ├── db/ # Database (Drizzle + Effect SQL)
│ ├── email/ # Email (Resend)
│ ├── s3/ # AWS S3 file storage
│ ├── telegram/ # Telegram notifications
│ ├── activity/ # Activity logging
│ └── telemetry/ # Error reporting & tracing
├── layers.ts # Effect layer composition
└── next-effect/ # Next.js + Effect utilities
app/
├── (auth)/ # Auth routes (login)
├── (dashboard)/ # Protected routes
├── api/
│ ├── auth/[...all]/ # Auth API handler
│ └── example/ # Example API route
└── page.tsx # Home page example
Schema is defined in lib/services/db/schema.ts. Migrations are stored in lib/services/db/migrations/.
Use db:push for rapid iteration - applies schema changes directly without migration files:
pnpm db:pushUse db:generate to create migration files, then apply them:
pnpm db:generate # Creates migration files from schema changes
pnpm db:push # Applies migrations to database- Edit
lib/services/db/schema.ts - Run
pnpm db:generateto create migration - Review generated migration in
lib/services/db/migrations/ - Run
pnpm db:pushto apply - Commit migration files
pnpm db:studio # Opens GUI to browse/edit dataasync function Content() {
await cookies()
return await NextEffect.runPromise(
Effect.gen(function* () {
const posts = yield* getPosts()
return <div>{/* render posts */}</div>
}).pipe(
Effect.provide(Layer.mergeAll(AppLayer)),
Effect.scoped,
Effect.matchEffect({
onFailure: error =>
Match.value(error._tag).pipe(
Match.when('UnauthenticatedError', () => NextEffect.redirect('/login')),
Match.orElse(() => Effect.succeed(<ErrorPage />))
),
onSuccess: Effect.succeed
})
)
)
}const handler = Effect.gen(function* () {
const posts = yield* getPosts()
return yield* HttpServerResponse.json({ posts })
}).pipe(
Effect.catchAll(error =>
Match.value(error).pipe(
Match.tag('UnauthenticatedError', () =>
HttpServerResponse.json({ error: 'Not authenticated' }, { status: 401 })
),
Match.orElse(() =>
HttpServerResponse.json({ error: 'Internal server error' }, { status: 500 })
)
)
)
)// lib/core/example/get-something.ts
export const getSomething = (id: string) =>
Effect.gen(function* () {
const { user } = yield* getSession()
const db = yield* DbLive
const result = yield* Effect.tryPromise(() =>
db.select().from(schema.something).where(eq(schema.something.id, id))
)
return result
}).pipe(Effect.withSpan('example.get-something'))- magoz/init - Magoz init