Thanks for your interest in contributing to Pyra.js! This guide covers everything you need to get started.
- Node.js >= 18.0.0
- pnpm 10.x (the project uses
pnpm@10.17.1) - Git
# Clone the repository
git clone https://github.com/Natejsx/Pyra.git
cd Pyra
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Link the CLI globally for manual testing
pnpm dev:linkPyra is a pnpm workspace monorepo with four packages. They must be built in this order because each depends on the previous:
shared → core → adapter-react → cli
| Package | npm Name | Description |
|---|---|---|
packages/shared |
@pyra-js/shared |
Types, config loader, logger, network utilities |
packages/core |
@pyra-js/core |
Dev server, prod server, bundler, router, scanner, tracer, metrics |
packages/adapter-react |
@pyra-js/adapter-react |
React SSR adapter (renderToString, hydration) |
packages/cli |
@pyra-js/cli |
CLI commands, scaffolding, graph visualization, templates |
# Build all packages (respects dependency order)
pnpm build
# Build a single package
cd packages/core && pnpm build
# Watch mode (core only — useful during active development)
cd packages/core && pnpm dev
# Run the CLI without building
cd packages/cli && pnpm dev:run# Type check all packages via project references
pnpm typecheck
# Type check a single package
cd packages/shared && npx tsc --noEmit
cd packages/core && npx tsc --noEmit
cd packages/cli && npx tsc --noEmit# Link the CLI globally
pnpm dev:link
# Now you can use the CLI anywhere
pyra dev
pyra build
pyra doctor
# Unlink when done
pnpm dev:unlink# Remove all dist/ directories and build artifacts
pnpm clean- Always write TypeScript. No plain JavaScript source files.
- Define types explicitly. Avoid
anyunless absolutely necessary. - Use shared types from
@pyra-js/shared, import from'@pyra-js/shared'in core, adapter-react, and cli packages. - Prefer
interfaceovertypefor object shapes. - Use
export typefor type-only exports.
- All packages use ESM (
"type": "module"in package.json). - Use
.jsextensions in import paths (TypeScript requires this for ESM resolution):// Correct import { log } from './logger.js'; // Incorrect import { log } from './logger';
- Use
node:prefix for Node.js built-in modules:import fs from 'node:fs'; import path from 'node:path';
- Use double quotes for strings in source files.
- Use 2-space indentation.
- Use
picocolors(imported aspc) for terminal coloring, not chalk or other alternatives. - Use
logfrom@pyra-js/sharedfor user-facing console output:import { log } from '@pyra-js/shared'; log.info('Server started'); log.error('Build failed');
We follow Conventional Commits for clear git history:
Types
- feat: - New feature
- fix: - Bug fix
- docs: - Documentation changes
- style: - Code style changes (formatting, no logic change)
- refactor: - Code refactoring
- test: - Adding or updating tests
- chore: - Maintenance tasks, dependency updates Examples
- Route sentinel files:
page.tsx(pages),route.ts(API routes),layout.tsx(layouts),middleware.ts(middleware) - Config files:
pyra.config.tsis the primary config filename - Package entry points: Each package exports from
src/index.ts
- Core never imports React. The
PyraAdapterinterface is the boundary. Core calls adapter methods with opaquecomponentanddatavalues. - Shared has no dependencies on core or cli. It only provides types, config loading, and utilities.
- CLI depends on all other packages. It wires everything together (adapter, core, shared).
- Define it in
packages/shared/src/types.ts. - It's automatically exported via
export * from './types.js'inpackages/shared/src/index.ts. - Import it in other packages with
import type { YourType } from '@pyra-js/shared'.
- Create the file in
packages/core/src/. - Export public API from
packages/core/src/index.ts. - Use
export typefor type-only re-exports.
- Define the command in
packages/cli/src/bin.tsusing Commander.js. - For complex commands, create a separate file in
packages/cli/src/commands/. - Follow existing patterns: load config, use
isSilent()/useColor(), print banner, handle errors withprocess.exit(1).
- Create a directory under
packages/cli/templates/(e.g.,svelte-ts/). - Include at minimum:
package.json,pyra.config.ts,index.html, and asrc/directory. - Use
{{PROJECT_NAME}}as a placeholder inpackage.json, scaffolding replaces it. - Templates are copied to
dist/templates/during the CLI build viascripts/copy-templates.mjs.
Routes live in src/routes/ within a Pyra project:
src/routes/
page.tsx → /
layout.tsx → Root layout (wraps all pages)
middleware.ts → Root middleware (runs on all routes)
about/
page.tsx → /about
blog/
page.tsx → /blog
[slug]/
page.tsx → /blog/:slug (dynamic)
api/
users/
route.ts → /api/users (API endpoint)
(marketing)/
pricing/
page.tsx → /pricing (route group — parentheses stripped from URL)
The trie-based router matches URLs with this priority:
- Static segments - exact match (e.g.,
/blog/featured) - Dynamic segments - parameterized (e.g.,
/blog/:slug) - Catch-all segments - rest params (e.g.,
/docs/*path)
Request → Route Match → Middleware Chain → Compile → load() → Render → Inject Assets → Response
Each stage is instrumented by the RequestTracer for performance visibility.
docs/ARCHITECTURE.md- Full platform architecture and milestone roadmapdocs/CONFIG_SYSTEM.md- Configuration system detailsdocs/SSR.md- SSR implementation detailsCLAUDE.md- AI assistant context for the codebase
- Fork the repository and create a feature branch from
master. - Make your changes following the coding guidelines above.
- Ensure all packages build cleanly:
pnpm build - Ensure type checking passes:
pnpm typecheck - Write a clear commit message describing what changed and why.
- Open a pull request against
master.
File issues at github.com/Natejsx/Pyra/issues. Include:
- Steps to reproduce
- Expected vs actual behavior
- Node.js version and OS
- Relevant config or error output
Pyra.js is MIT licensed. By contributing, you agree that your contributions will be licensed under the same license.