Add contributing section for jan (#6231) (#6232)

* Add contributing section for jan

* Update CONTRIBUTING.md

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
This commit is contained in:
Dinh Long Nguyen 2025-08-20 10:18:35 +07:00 committed by GitHub
parent a6e5273c7a
commit b0eec07a01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 814 additions and 14 deletions

View File

@ -1,32 +1,266 @@
# Contributing to jan
# Contributing to Jan
First off, thank you for considering contributing to jan. It's people like you that make jan such an amazing project.
First off, thank you for considering contributing to Jan. It's people like you that make Jan such an amazing project.
Jan is an AI assistant that can run 100% offline on your device. Think ChatGPT, but private, local, and under your complete control. If you're thinking about contributing, you're already awesome - let's make AI accessible to everyone, one commit at a time.
## Quick Links to Component Guides
- **[Web App](./web-app/CONTRIBUTING.md)** - React UI and logic
- **[Core SDK](./core/CONTRIBUTING.md)** - TypeScript SDK and extension system
- **[Extensions](./extensions/CONTRIBUTING.md)** - Supportive modules for the frontend
- **[Tauri Backend](./src-tauri/CONTRIBUTING.md)** - Rust native integration
- **[Tauri Plugins](./src-tauri/plugins/CONTRIBUTING.md)** - Hardware and system plugins
## How Jan Actually Works
Jan is a desktop app that runs local AI models. Here's how the components actually connect:
```
┌──────────────────────────────────────────────────────────┐
│ Web App (Frontend) │
│ (web-app/) │
│ • React UI │
│ • Chat Interface │
│ • Settings Pages │
│ • Model Hub │
└────────────┬─────────────────────────────┬───────────────┘
│ │
│ imports │ imports
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ Core SDK │ │ Extensions │
│ (core/) │ │ (extensions/) │
│ │ │ │
│ • TypeScript APIs │◄─────│ • Assistant Mgmt │
│ • Extension System │ uses │ • Conversations │
│ • Event Bus │ │ • Downloads │
│ • Type Definitions │ │ • LlamaCPP │
└──────────┬───────────┘ └───────────┬──────────┘
│ │
│ ┌──────────────────────┐ │
│ │ Web App │ │
│ └──────────┬───────────┘ │
│ │ │
└──────────────┼───────────────┘
Tauri IPC
(invoke commands)
┌───────────────────────────────────────────────────────────┐
│ Tauri Backend (Rust) │
│ (src-tauri/) │
│ │
│ • Window Management • File System Access │
│ • Process Control • System Integration │
│ • IPC Command Handler • Security & Permissions │
└───────────────────────────┬───────────────────────────────┘
┌───────────────────────────────────────────────────────────┐
│ Tauri Plugins (Rust) │
│ (src-tauri/plugins/) │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Hardware Plugin │ │ LlamaCPP Plugin │ │
│ │ │ │ │ │
│ │ • CPU/GPU Info │ │ • Process Mgmt │ │
│ │ • Memory Stats │ │ • Model Loading │ │
│ │ • System Info │ │ • Inference │ │
│ └──────────────────┘ └──────────────────┘ │
└───────────────────────────────────────────────────────────┘
```
### The Communication Flow
1. **JavaScript Layer Relationships**:
- Web App imports Core SDK and Extensions as JavaScript modules
- Extensions use Core SDK for shared functionality
- All run in the browser/webview context
2. **All Three → Backend**: Through Tauri IPC
- **Web App** → Backend: `await invoke('app_command', data)`
- **Core SDK** → Backend: `await invoke('core_command', data)`
- **Extensions** → Backend: `await invoke('ext_command', data)`
- Each component can independently call backend commands
3. **Backend → Plugins**: Native Rust integration
- Backend loads plugins as Rust libraries
- Direct function calls, no IPC overhead
4. **Response Flow**:
- Plugin → Backend → IPC → Requester (Web App/Core/Extension) → UI updates
### Real-World Example: Loading a Model
Here's what actually happens when you click "Download Llama 3":
1. **Web App** (`web-app/`) - User clicks download button
2. **Extension** (`extensions/download-extension`) - Handles the download logic
3. **Tauri Backend** (`src-tauri/`) - Actually downloads the file to disk
4. **Extension** (`extensions/llamacpp-extension`) - Prepares model for loading
5. **Tauri Plugin** (`src-tauri/plugins/llamacpp`) - Starts llama.cpp process
6. **Hardware Plugin** (`src-tauri/plugins/hardware`) - Detects GPU, optimizes settings
7. **Model ready!** - User can start chatting
## Project Structure
```
jan/
├── web-app/ # React frontend (what users see)
├── src-tauri/ # Rust backend (system integration)
│ ├── src/core/ # Core Tauri commands
│ └── plugins/ # Tauri plugins (hardware, llamacpp)
├── core/ # TypeScript SDK (API layer)
├── extensions/ # JavaScript extensions
│ ├── assistant-extension/
│ ├── conversational-extension/
│ ├── download-extension/
│ └── llamacpp-extension/
├── docs/ # Documentation website
├── website/ # Marketing website
├── autoqa/ # Automated testing
├── scripts/ # Build utilities
├── package.json # Root workspace configuration
├── Makefile # Build automation commands
├── mise.toml # Mise tool configuration
├── LICENSE # Apache 2.0 license
└── README.md # Project overview
```
## Development Setup
### The Scenic Route (Build from Source)
**Prerequisites:**
- Node.js ≥ 20.0.0
- Yarn ≥ 1.22.0
- Rust (for Tauri)
- Make ≥ 3.81
**Option 1: The Easy Way (Make)**
```bash
git clone https://github.com/menloresearch/jan
cd jan
make dev
```
**Option 2: The Easier Way (Mise)**
```bash
git clone https://github.com/menloresearch/jan
cd jan
# Install mise
curl https://mise.run | sh
# Let mise handle everything
mise install # installs Node.js, Rust, and other tools
mise dev # runs the full development setup
```
## How Can I Contribute?
### Reporting Bugs
- **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/menloresearch/jan/issues).
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/menloresearch/jan/issues/new).
- **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/menloresearch/jan/issues)
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/menloresearch/jan/issues/new)
- Include your system specs and error logs - it helps a ton
### Suggesting Enhancements
- Open a new issue with a clear title and description.
- Open a new issue with a clear title and description
- Explain why this enhancement would be useful
- Include mockups or examples if you can
### Your First Code Contribution
- Fork the repo.
- Create a new branch (`git checkout -b feature-name`).
- Commit your changes (`git commit -am 'Add some feature'`).
- Push to the branch (`git push origin feature-name`).
- Open a new Pull Request.
**Choose Your Adventure:**
- **Frontend UI and logic**`web-app/`
- **Shared API declarations**`core/`
- **Backend system integration**`src-tauri/`
- **Business logic features**`extensions/`
- **Dedicated backend handler**`src-tauri/plugins/`
## Styleguides
**The Process:**
1. Fork the repo
2. Create a new branch (`git checkout -b feature-name`)
3. Make your changes (and write tests!)
4. Commit your changes (`git commit -am 'Add some feature'`)
5. Push to the branch (`git push origin feature-name`)
6. Open a new Pull Request against `dev` branch
### Git Commit Messages
## Testing
- Use the present tense ("Add feature" not "Added feature").
```bash
yarn test # All tests
cd src-tauri && cargo test # Rust tests
cd autoqa && python main.py # End-to-end tests
```
## Code Standards
### TypeScript/JavaScript
- TypeScript required (we're not animals)
- ESLint + Prettier
- Functional React components
- Proper typing (no `any` - seriously!)
### Rust
- `cargo fmt` + `cargo clippy`
- `Result<T, E>` for error handling
- Document public APIs
## Git Conventions
### Branches
- `main` - stable releases
- `dev` - development (target this for PRs)
- `feature/*` - new features
- `fix/*` - bug fixes
### Commit Messages
- Use the present tense ("Add feature" not "Added feature")
- Be descriptive but concise
- Reference issues when applicable
Examples:
```
feat: add support for Qwen models
fix: resolve memory leak in model loading
docs: update installation instructions
```
## Troubleshooting
If things go sideways:
1. **Check our [troubleshooting docs](https://jan.ai/docs/troubleshooting)**
2. **Clear everything and start fresh:** `make clean` then `make dev`
3. **Copy your error logs and system specs**
4. **Ask for help in our [Discord](https://discord.gg/FTk2MvZwJH)** `#🆘|jan-help` channel
Common issues:
- **Build failures**: Check Node.js and Rust versions
- **Extension not loading**: Verify it's properly registered
- **Model not working**: Check hardware requirements and GPU drivers
## Getting Help
- [Documentation](https://jan.ai/docs) - The manual you should read
- [Discord Community](https://discord.gg/jan) - Where the community lives
- [GitHub Issues](https://github.com/janhq/jan/issues) - Report bugs here
- [GitHub Discussions](https://github.com/janhq/jan/discussions) - Ask questions
## License
Apache 2.0 - Because sharing is caring. See [LICENSE](./LICENSE) for the legal stuff.
## Additional Notes
Thank you for contributing to jan!
We're building something pretty cool here - an AI assistant that respects your privacy and runs entirely on your machine. Every contribution, no matter how small, helps make AI more accessible to everyone.
Thanks for being part of the journey. Let's build the future of local AI together! 🚀

71
core/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,71 @@
# Contributing to Jan Core
[← Back to Main Contributing Guide](../CONTRIBUTING.md)
TypeScript SDK providing extension system, APIs, and type definitions for all Jan components.
## Key Directories
- **`/src/browser`** - Core APIs (events, extensions, file system)
- **`/src/browser/extensions`** - Built-in extensions (assistant, inference, conversational)
- **`/src/types`** - TypeScript type definitions
- **`/src/test`** - Testing utilities
## Development
### Key Principles
1. **Platform Agnostic** - Works everywhere (browser, Node.js)
2. **Extension-Based** - New features = new extensions
3. **Type Everything** - TypeScript required
4. **Event-Driven** - Components communicate via events
### Building & Testing
```bash
# Build the SDK
yarn build
# Run tests
yarn test
# Watch mode
yarn test:watch
```
### Event System
```typescript
// Emit events
events.emit('model:loaded', { modelId: 'llama-3' })
// Listen for events
events.on('model:loaded', (data) => {
console.log('Model loaded:', data.modelId)
})
```
## Testing
```typescript
describe('MyFeature', () => {
it('should do something', () => {
const result = doSomething()
expect(result).toBe('expected')
})
})
```
## Best Practices
- Keep it simple
- Use TypeScript fully (no `any`)
- Write tests for critical features
- Follow existing patterns
- Export new modules in index files
## Dependencies
- **TypeScript** - Type safety
- **Rolldown** - Bundling
- **Vitest** - Testing

137
extensions/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,137 @@
# Contributing to Jan Extensions
[← Back to Main Contributing Guide](../CONTRIBUTING.md)
Extensions add specific features to Jan as self-contained modules.
## Current Extensions
### `/assistant-extension`
- Assistant CRUD operations
- `src/index.ts` - Main implementation
### `/conversational-extension`
- Message handling, conversation state
- `src/index.ts` - Chat logic
### `/download-extension`
- Model downloads with progress tracking
- `src/index.ts` - Download logic
- `settings.json` - Download settings
### `/llamacpp-extension`
- Local model inference via llama.cpp
- `src/index.ts` - Entry point
- `src/backend.ts` - llama.cpp integration
- `settings.json` - Model settings
## Creating Extensions
### Setup
```bash
mkdir my-extension
cd my-extension
yarn init
```
### Structure
```
my-extension/
├── package.json
├── rolldown.config.mjs
├── src/index.ts
└── settings.json (optional)
```
### Basic Extension
```typescript
import { Extension } from '@janhq/core'
export default class MyExtension extends Extension {
async onLoad() {
// Extension initialization
}
async onUnload() {
// Cleanup
}
}
```
## Building & Testing
```bash
# Build extension
yarn build
# Run tests
yarn test
```
## Common Patterns
### Service Registration
```typescript
async onLoad() {
this.registerService('myService', {
doSomething: async () => 'result'
})
}
```
### Event Handling
```typescript
async onLoad() {
this.on('model:loaded', (model) => {
console.log('Model loaded:', model.id)
})
}
```
## Extension Lifecycle
1. **Jan starts** → Discovers extensions
2. **Loading** → Calls `onLoad()` method
3. **Active** → Extension responds to events
4. **Unloading** → Calls `onUnload()` on shutdown
## Debugging Extensions
```bash
# Check if extension loaded
console.log(window.core.extensions)
# Debug extension events
this.on('*', console.log)
# Check extension services
console.log(window.core.api)
```
## Common Issues
**Extension not loading?**
- Check package.json format: `@janhq/extension-name`
- Ensure `onLoad()` doesn't throw errors
- Verify exports in index.ts
**Events not working?**
- Check event name spelling
- Ensure listeners are set up in `onLoad()`
## Best Practices
- Keep extensions focused on one feature
- Use async/await for all operations
- Clean up resources in onUnload()
- Handle errors gracefully
- Don't depend on other extensions
## Dependencies
- **@janhq/core** - Core SDK and extension system
- **TypeScript** - Type safety
- **Rolldown** - Bundling

111
src-tauri/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,111 @@
# Contributing to Tauri Backend
[← Back to Main Contributing Guide](../CONTRIBUTING.md)
Rust backend that handles native system integration, file operations, and process management.
## Key Modules
- **`/src/core/app`** - App state and commands
- **`/src/core/downloads`** - Model download management
- **`/src/core/filesystem`** - File system operations
- **`/src/core/mcp`** - Model Context Protocol
- **`/src/core/server`** - Local API server
- **`/src/core/system`** - System information and utilities
- **`/src/core/threads`** - Conversation management
- **`/utils`** - Shared utility crate (CLI, crypto, HTTP, path utils). Used by plugins and the main backend.
- **`/plugins`** - Native Tauri plugins ([see plugins guide](./plugins/CONTRIBUTING.md))
## Development
### Adding Tauri Commands
```rust
#[tauri::command]
async fn my_command(param: String) -> Result<String, String> {
Ok(format!("Processed: {}", param))
}
// Register in lib.rs
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![my_command])
```
## Building & Testing
```bash
# Development
yarn tauri dev
# Build
yarn tauri build
# Run tests
cargo test
```
### State Management
```rust
#[tauri::command]
async fn get_data(state: State<'_, AppState>) -> Result<Data, Error> {
state.get_data().await
}
```
### Error Handling
```rust
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}
```
## Debugging
```rust
// Enable debug logging
env::set_var("RUST_LOG", "debug");
// Debug print in commands
#[tauri::command]
async fn my_command() -> Result<String, String> {
println!("Command called"); // Shows in terminal
dbg!("Debug info");
Ok("result".to_string())
}
```
## Platform-Specific Notes
**Windows**: Requires Visual Studio Build Tools
**macOS**: Needs Xcode command line tools
**Linux**: May need additional system packages
```rust
#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;
```
## Common Issues
**Build failures**: Check Rust toolchain version
**IPC errors**: Ensure command names match frontend calls
**Permission errors**: Update capabilities configuration
## Best Practices
- Always use `Result<T, E>` for fallible operations
- Validate all input from frontend
- Use async for I/O operations
- Follow Rust naming conventions
- Document public APIs
## Dependencies
- **Tauri** - Desktop app framework
- **Tokio** - Async runtime
- **Serde** - JSON serialization
- **thiserror** - Error handling

View File

@ -0,0 +1,119 @@
# Contributing to Tauri Plugins
[← Back to Main Contributing Guide](../../CONTRIBUTING.md) | [← Back to Tauri Guide](../CONTRIBUTING.md)
Native Rust plugins for hardware access, process management, and system integration.
## Current Plugins
### `/tauri-plugin-hardware`
- Hardware detection (CPU, GPU, memory)
### `/tauri-plugin-llamacpp`
- llama.cpp process management and model inference
## Plugin Structure
```
tauri-plugin-name/
├── Cargo.toml
├── src/lib.rs # Plugin entry point
├── src/commands.rs # Tauri commands
├── guest-js/index.ts # JavaScript API
└── permissions/default.toml
```
## Development
### Creating Plugins
Assuming that your new plugin name is `my-plugin`
```bash
# with npx
npx @tauri-apps/cli plugin new my-plugin
# with cargo
cargo tauri plugin new my-plugin
cd tauri-plugin-my-plugin
```
### Plugin Registration
```rust
use tauri::{plugin::{Builder, TauriPlugin}, Runtime};
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("my-plugin")
.invoke_handler(tauri::generate_handler![commands::my_command])
.build()
}
```
### Commands & JavaScript API
```rust
#[tauri::command]
pub async fn my_command(param: String) -> Result<String, Error> {
Ok(format!("Result: {}", param))
}
```
```typescript
import { invoke } from '@tauri-apps/api/core'
export async function myCommand(param: string): Promise<string> {
return await invoke('plugin:my-plugin|my_command', { param })
}
```
### Building & Testing
```bash
cargo build # Build plugin
yarn build # Build JavaScript
cargo test # Run tests
```
## Security Considerations
```toml
# permissions/default.toml - Be specific
[[permission]]
identifier = "allow-hardware-info"
description = "Read system hardware information"
# Never use wildcards in production
# ❌ identifier = "allow-*"
# ✅ identifier = "allow-specific-action"
```
## Testing Plugins
```bash
# Test plugin in isolation
cd tauri-plugin-my-plugin
cargo test
# Test with main app
cd ../../
yarn tauri dev
# Test JavaScript API
yarn build && node -e "const plugin = require('./dist-js'); console.log(plugin)"
```
## Best Practices
- Use secure permission configurations
- Validate all command inputs
- Handle platform differences properly
- Clean up resources in Drop implementations
- Test on all target platforms
## Dependencies
- **Tauri** - Plugin framework
- **Serde** - JSON serialization
- **Tokio** - Async runtime (if needed)

128
web-app/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,128 @@
# Contributing to Jan Web App
[← Back to Main Contributing Guide](../CONTRIBUTING.md)
React frontend using TypeScript, TanStack Router, Radix UI, and Tailwind CSS. State is managed by React State and Zustand.
## Key Directories
- **`/src/components/ui`** - UI components (buttons, dialogs, inputs)
- **`/src/containers`** - Complex feature components (ChatInput, ThreadContent)
- **`/src/hooks`** - Custom React hooks (useChat, useThreads, useAppState)
- **`/src/routes`** - TanStack Router pages
- **`/src/services`** - API layer for backend communication
- **`/src/types`** - TypeScript definitions
## Development
### Component Example
```tsx
interface Props {
title: string
onAction?: () => void
}
export const MyComponent: React.FC<Props> = ({ title, onAction }) => {
return (
<div className="flex items-center gap-2">
<h2>{title}</h2>
<Button onClick={onAction}>Action</Button>
</div>
)
}
```
### Routing
```tsx
export const Route = createFileRoute('/settings/general')({
component: GeneralSettings
})
```
### Building & Testing
```bash
# Development
yarn dev
yarn build
yarn test
```
### State Management
```tsx
// Local state
const [value, setValue] = useState<string>('')
// Global state (Zustand)
export const useAppState = create<AppState>((set) => ({
data: null,
setData: (data) => set({ data })
}))
```
### Tauri Integration
```tsx
import { invoke } from '@tauri-apps/api/tauri'
const result = await invoke('command_name', { param: 'value' })
```
## Performance Tips
```tsx
// Use React.memo for expensive components
const ExpensiveComponent = React.memo(({ data }) => {
return <div>{processData(data)}</div>
})
// Debounce frequent updates
const debouncedValue = useDebounce(searchTerm, 300)
// Virtual scrolling for large lists
import { VariableSizeList } from 'react-window'
```
## Debugging
```bash
# React DevTools
# Install browser extension, then:
# - Inspect component tree
# - Debug hooks and state
# - Profile performance
# Debug Tauri commands
console.log(await window.__TAURI__.invoke('command_name'))
# Check for console errors
# Press F12 → Console tab
```
## Accessibility Guidelines
- Use semantic HTML (`<button>`, `<nav>`, `<main>`)
- Add ARIA labels: `aria-label`, `aria-describedby`
- Ensure keyboard navigation works
- Test with screen readers
- Maintain color contrast ratios
## Best Practices
- Keep components small and focused
- Use TypeScript fully (no `any`)
- Handle loading and error states
- Follow accessibility guidelines
- Extract business logic into hooks
## Dependencies
- **React** - UI framework
- **TypeScript** - Type safety
- **TanStack Router** - Type-safe routing
- **Radix UI** - Accessible components
- **Tailwind CSS** - Utility-first styling
- **Zustand** - State management