Marketing and portfolio site for Binary Semaphore, a small software team working across applied AI, distributed systems, and developer tools. Source for binarysemaphore.com.
Current focus: inode, a CLI knowledge base that retrieves notes, secrets, and commands by meaning instead of exact keywords.
- Next.js 16 (App Router) + TypeScript (strict)
- Tailwind CSS v4
- MDX content pipeline for
/threads - Vitest (unit) and Playwright (smoke)
- Deployed on Vercel
npm install
npm run dev # http://localhost:3000| Script | What it does |
|---|---|
npm run dev |
Local dev server |
npm run build |
Production build |
npm run start |
Serve the production build |
npm run lint |
ESLint |
npm run typecheck |
tsc --noEmit |
npm run test |
Unit tests (Vitest) |
npm run test:e2e |
Smoke tests (Playwright) |
src/app/— routes (/,/about,/services,/projects,/team,/contact,/threads, plus/projects/[slug],/team/[slug],/threads/[slug]),layout.tsx,globals.css.src/components/— section and UI components.src/lib/site.ts— single source of truth for all copy, links, the team, and projects. Edit copy here, not in components.src/content/threads/*.mdx— long-form posts; frontmatter parsed bysrc/lib/threads.ts.src/images/— optimized photography (statically imported for blur-up).public/tech/— technology logos for the stack section.e2e/— Playwright smoke tests.
All site copy and links live in src/lib/site.ts; components
read from it. Long-form writing lives as MDX under
src/content/threads.
Copy voice: plain and human, no em dashes, no marketing slogans. See
AGENTS.md for the full guidelines.
npm run test # Vitest unit tests (lib + site config invariants)
npm run test:e2e # Playwright smoke tests (key routes, nav, contact)Unit tests live next to the code as *.test.ts; smoke tests live in e2e/.
The backend is Supabase (hosted Postgres + Auth), called
from inside the app via @supabase/ssr. No separate service to host.
- Create a Supabase project and run
supabase/schema.sqlin its SQL editor. - Copy
.env.exampleto.env.localand fill inNEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY(Project Settings -> API). Add the same vars to the Vercel project env for production. - Clients live under
src/utils/supabase/:server.ts(Server Components / Route Handlers / server actions),client.ts(browser), andmiddleware.ts(session refresh, wired insrc/proxy.ts— Next 16's renamed middleware convention). They use the publishable key and respect row-level security.
Worked example: POST /api/contact
(src/app/api/contact/route.ts) validates a
submission and inserts it into the contact_messages table.
curl -X POST http://localhost:3000/api/contact \
-H 'content-type: application/json' \
-d '{"name":"Ada","email":"ada@example.com","message":"hi"}'Sign-in uses Supabase Auth with GitHub and Google OAuth. Flow: /login
(buttons) -> provider -> /auth/callback (exchanges the code for a session) ->
/account. Sign out posts to /auth/signout. Gate any page by calling
getCurrentUser() from src/utils/supabase/auth.ts
and redirecting to /login when it is null (see src/app/account/page.tsx).
To enable the providers (one-time, in dashboards):
- Supabase -> Authentication -> Providers: enable GitHub and Google and
paste each provider's Client ID/Secret.
- GitHub: create an OAuth App at
https://github.com/settings/developers. Authorization callback URL:https://<project-ref>.supabase.co/auth/v1/callback. - Google: create an OAuth client in Google Cloud Console (APIs & Services -> Credentials). Authorized redirect URI: the same Supabase callback URL.
- GitHub: create an OAuth App at
- Supabase -> Authentication -> URL Configuration: set the Site URL to the
production URL and add redirect URLs
https://binarysemaphore.com/auth/callbackandhttp://localhost:3000/auth/callback.
Work on a feature branch and open a pull request; main is updated only by
merging a reviewed PR. Husky hooks enforce quality locally: pre-commit runs
lint-staged (ESLint + Prettier on staged files), commit-msg checks the message
against Conventional Commits
(feat:, fix:, chore:, ...), and pre-push runs typecheck and unit tests.
GitHub Actions (.github/workflows/ci.yml) runs
lint, typecheck, and tests on every push and pull request, then deploys via the
Vercel CLI: a preview deployment for each PR and a production deployment on
main. Requires the VERCEL_TOKEN, VERCEL_ORG_ID, and VERCEL_PROJECT_ID
repository secrets.