Thank you for your interest in contributing to the onX reference implementation.
- Fork and clone the repository
- Install dependencies:
npm install - Copy environment config:
cp .env.example .env.local - Start dev server:
npm run dev - Visit
http://localhost:3000
- Create a branch from
developfor your change - Make your changes with clear, focused commits
- Run the build to verify:
npm run build - Open a pull request with a description of what and why
- One concern per PR. Bug fix, feature, or refactor — not all three.
- Describe the change. What does it do? Why is it needed?
- Include test steps. How can a reviewer verify the change works?
- No secrets. Never commit API keys, credentials, or
.envfiles.
Juniper is built on two abstraction layers that make it extensible:
Implement the DataProvider interface in src/lib/data/provider.ts:
export class MyProvider implements DataProvider {
async getProducts(filter?: ProductFilter): Promise<PaginatedResult<Product>> { ... }
async getOrderById(id: string): Promise<Order | null> { ... }
// ... all DataProvider methods
}Register it in src/lib/onx-client.ts under the getProvider() switch statement.
Implement the LLMProvider interface in src/lib/ai/llm-provider.ts:
export class MyLLMProvider implements LLMProvider {
name = 'My Provider';
async chat(messages, tools, systemPrompt, executeToolCall) { ... }
}Register it in src/lib/ai/llm-provider.ts detection logic.
- TypeScript throughout — no
anyunless unavoidable - Tailwind CSS for styling
- ESLint for linting:
npm run lint - Meaningful variable and function names over comments
Open a GitHub issue with:
- Steps to reproduce
- Expected vs actual behavior
- Environment (OS, Node version, browser)
By contributing, you agree that your contributions will be licensed under the MIT License.