Contributing
Prerequisites
- Bun (latest)
- OpenCode CLI (for running reviews locally)
- A GitHub App with webhook secret (for testing webhook handling)
Setup
git clone https://github.com/Karnak19/fouine.git
cd fouine
bun install
cp .env.example .env
# edit .env with your credentialsDevelopment
bun run dev # start the server with --watch (auto-reload)
bun run typecheck # TypeScript type checking (tsc --noEmit)
bun run test # run the test suite
bun run build # build the dashboard into apps/web/distEach of these is a turbo run <task> across the workspaces.
The dashboard has no dev server of its own. bun run dev starts only the backend, and Elysia serves the SPA from apps/web/src with Bun transpiling the .tsx on the fly. In production (NODE_ENV=production) it serves the prebuilt apps/web/dist instead. Both paths are resolved from the server module's own location rather than the working directory, so they survive turbo and Docker running with a different cwd.
Project structure
The repository is a Bun-workspaces monorepo driven by Turborepo. TypeScript settings are shared through tsconfig.base.json at the root, which each workspace extends.
apps/server/ # @fouine/server — Bun + Elysia backend
├── src/
│ ├── index.ts # Entry point
│ ├── config.ts # Env-based configuration
│ ├── db.ts # SQLite schema + queries
│ ├── settings.ts # Dashboard settings resolver
│ ├── git/worktree.ts # Bare repo + worktree management
│ ├── github/index.ts # Octokit App, installation tokens
│ ├── review/
│ │ ├── runner.ts # Review orchestrator
│ │ ├── opencode.ts # OpenCode SDK client
│ │ ├── prompt.ts # Prompt builder
│ │ └── types.ts # Review types
│ └── server/
│ ├── app.ts # Elysia server + static files
│ ├── api.ts # REST API routes
│ ├── webhook.ts # GitHub webhook handler
│ ├── events.ts # Server-sent event stream
│ └── log.ts # Structured logger
├── tests/setup.ts # Hermetic test environment
└── opencode-config/ # Custom OpenCode agent config
├── agent/ # Reviewer and improver agent definitions
├── plugin/ # bash-timeout cap
└── tools/
├── post_comment.ts # PR summary comment
└── post_review.ts # Inline review comments
apps/web/ # @fouine/web — React dashboard (SPA)
└── src/
├── index.tsx # Entry point
├── components/ui/ # UI primitives
├── lib/ # API client, utils, formatters
└── routes/ # TanStack Router routes
apps/docs/ # fouine-docs — this VitePress site
packages/shared/ # @fouine/shared — row and response types used by
# both the backend and the dashboardpackages/shared holds the database-row and API-response shapes the dashboard used to re-declare by hand. Import them with import type from either app so the two stay in step.
Path aliases: ~/* resolves to apps/server/src/* inside the backend, @/* resolves to apps/web/src/* inside the dashboard. Each alias works only within its own workspace.
Testing
Tests are co-located with source files (*.test.ts). The test setup in apps/server/tests/setup.ts creates a hermetic environment with temp directories and stubbed env vars; apps/server/bunfig.toml preloads it, and a root bunfig.toml does the same so a bare bun test works from the repository root.
bun run test # run all tests through turbo
bun test apps/server/src/db.test.ts # run a specific test fileGuidelines
- Run
bun run typecheckbefore submitting — strict mode is enabled - Keep tests hermetic — no real network calls, no shared state
- Follow existing code style — the project uses Elysia conventions, SQLite prepared statements, and structured JSON logging
- One concern per PR — keep changes focused
License
MIT
