Karkas is an opinionated React 19 starter and a working demo app built on it. Most
templates stop once the app boots. Karkas also ships the conventions for growing the app and
the checks that enforce them. A lint rule bans importing React's state and effect hooks in
favor of Reatom, Steiger guards the Feature-Sliced Design layers, and the Storybook stories
you browse are the browser test suite. Run npm create karkas@latest and you start with
those decisions made and checked. The demo shows each one handling loading, errors,
retries, and cancelled requests.
Try the live demo, browse its Storybook, or read the landing site.
- State lives in Reatom. Atoms, actions, forms, persistence, async loaders, and routes
share one reactive model. An oxlint rule rejects named imports of
useState,useEffect,useMemo, seven other React hooks, andmemo. - Stories are the tests. Vitest runs Storybook stories in Chromium through Playwright. The demo has 142 integration stories with 262 tests that find elements by role and accessible name.
- One mock backend. MSW handlers serve the dev server, Storybook, the tests, and the published demo. None of them need a real API.
- Enforced architecture. Steiger checks Feature-Sliced Design layer and import boundaries. Fallow reports dead code, duplication, and complexity weighted by test coverage.
- Localized from the start. ParaglideJS compiles English and Spanish catalogs, and a build check fails if a canary message the app never imports ends up in the bundle.
- One gate.
mise run validateformats, lints, tests with coverage thresholds, typechecks, and runs Steiger and Fallow.hk checkis the fast pass: format, lint, typecheck, and a Fallow audit, without tests. hk runs it before every push.
A story from the demo. Storybook renders its error screen, and Vitest runs the same story as a test in Chromium:
export const HandlesArticlesLoadServerError = meta.story({
beforeEach({ msw }) {
msw.use(articleList.error) // the articles API answers 500
},
play: () => I.waitExit(role('status')),
})
HandlesArticlesLoadServerError.test('keeps error state when retry also fails', async () => {
await I.seeError()
await I.retry()
await I.waitExit(role('status'))
await I.seeError()
})- Getting started
- Stack
- Working on this repository
- Demo architecture
- Documentation
- CI, deployment, and releases
You need mise installed and activated in your shell, and Node.js 20.12 or newer to run the initializer. mise installs the rest of the project's toolchain, including Nub.
-
Enable mise experimental features. The generated
mise.tomluses mise's[deps]block, which requires them.mise settings experimental=true
-
Create the project. The initializer asks whether to set up a Git repository; pass
--gitor--no-gitto skip the question.npm create karkas@latest my-app cd my-app -
Trust the project's mise config and install its tools: Node, Nub, Vite+, hk, and a few helpers.
mise trust mise install
-
Install dependencies. Nub's prepare step also generates Panda CSS output, compiles ParaglideJS messages, and writes the MSW worker. Inside a Git repository it installs hk Git hooks too.
nub install
-
Start the app at http://localhost:5173. The login form comes pre-filled with the mock account.
mise run dev
Before running tests, install the Chromium build Playwright uses:
nub exec playwright install chromiumThen mise run storybook opens Storybook on port 6006, mise run test runs the stories as
tests in watch mode, and mise run validate runs the full local gate.
The initializer is published on npm as
create-karkas; see its
README for every option.
| Concern | Tool |
|---|---|
| Framework | React 19 |
| State and routing | Reatom |
| Architecture | Feature-Sliced Design, checked by Steiger |
| Styling | Panda CSS with Park UI |
| Localization | ParaglideJS |
| UI development | Storybook |
| Testing | Vitest browser mode with Playwright and Kahraman |
| Mocking | MSW |
| Build tooling | Vite+ |
| Package manager | Nub |
| Task workflows | mise |
| Quality | oxfmt, oxlint, TypeScript, hk, and Fallow |
This repository holds the demo app, the documentation site, and the create-karkas
initializer.
apps/demo/ Reference React application
packages/create-karkas/ npm initializer and curated project template
site/ Astro documentation and landing site
.config/ Monorepo-wide mise, hk, and Fallow configuration
docs/ Source-first stack documentation
Set up a clone. The root mise config also uses [deps], so it needs the same experimental
setting:
git clone https://github.com/apphane-dev/karkas.git
cd karkas
mise settings experimental=true
mise trust
mise install
nub install
nub exec --cwd apps/demo playwright install chromiumnub install generates Panda's styled system, compiles ParaglideJS messages, generates and
verifies the MSW worker, synchronizes Astro types, and installs hk hooks.
| Goal | Command |
|---|---|
| Run the demo | mise run dev |
| Run Storybook | mise run storybook |
| Run the site | mise run dev:site |
| Build every project | mise run build |
| Fast quality check | hk check |
| Auto-fix format and lint | hk fix |
| Full local validation | mise run validate |
| Build the initializer | mise run //packages/create-karkas:build |
| Test the initializer | mise run //packages/create-karkas:test |
mise exposes child-project tasks with names such as //apps/demo:build. Root tasks
orchestrate the whole repository.
The demo follows Feature-Sliced Design under apps/demo/src/:
| Layer | Responsibility |
|---|---|
app/ |
Application shell, global composition, integration stories, MSW browser setup |
pages/ |
Route-level composition, navigation, loading, and error states |
widgets/ |
Compositional blocks combining entities and shared UI |
entities/ |
Domain models, API calls, types, mocks, and Reatom atoms |
shared/ |
API, router, models, Kahraman extensions, mocks, and UI components |
paraglide/ |
Generated ParaglideJS output |
Each entity keeps its api/, model/, and mocks/ behind an index.ts public API.
User-observable integration tests live in apps/demo/src/app/integration/*.stories.tsx.
- Tooling: Vite+, mise, Nub, and hk responsibilities
- Testing: Storybook integration stories, Kahraman, and coverage
- Localization: ParaglideJS and message catalogs
- Reatom patterns: application state conventions
- Reatom extensions: reusable Reatom helpers
.github/workflows/test.yml runs a Fallow audit and mise run ci on pushes and pull
requests to main. .github/workflows/deploy.yml assembles the landing site, demo, and
Storybook into one Cloudflare Pages artifact.
.github/workflows/release.yml versions and publishes create-karkas with Changesets. npm
trusted publishing authenticates the workflow through GitHub OIDC, so it needs no NPM_TOKEN
secret, and every release carries npm provenance.