From b0eec07a01d6af4115c75a0a7f17e432c49a5cfc Mon Sep 17 00:00:00 2001 From: Dinh Long Nguyen Date: Wed, 20 Aug 2025 10:18:35 +0700 Subject: [PATCH] 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> --- CONTRIBUTING.md | 262 ++++++++++++++++++++++++++++-- core/CONTRIBUTING.md | 71 ++++++++ extensions/CONTRIBUTING.md | 137 ++++++++++++++++ src-tauri/CONTRIBUTING.md | 111 +++++++++++++ src-tauri/plugins/CONTRIBUTING.md | 119 ++++++++++++++ web-app/CONTRIBUTING.md | 128 +++++++++++++++ 6 files changed, 814 insertions(+), 14 deletions(-) create mode 100644 core/CONTRIBUTING.md create mode 100644 extensions/CONTRIBUTING.md create mode 100644 src-tauri/CONTRIBUTING.md create mode 100644 src-tauri/plugins/CONTRIBUTING.md create mode 100644 web-app/CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2a254fb49..16379e575 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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` 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! 🚀 diff --git a/core/CONTRIBUTING.md b/core/CONTRIBUTING.md new file mode 100644 index 000000000..4d0a16989 --- /dev/null +++ b/core/CONTRIBUTING.md @@ -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 diff --git a/extensions/CONTRIBUTING.md b/extensions/CONTRIBUTING.md new file mode 100644 index 000000000..ee5c5aa9f --- /dev/null +++ b/extensions/CONTRIBUTING.md @@ -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 \ No newline at end of file diff --git a/src-tauri/CONTRIBUTING.md b/src-tauri/CONTRIBUTING.md new file mode 100644 index 000000000..e9d68cfaf --- /dev/null +++ b/src-tauri/CONTRIBUTING.md @@ -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 { + 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 { + 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 { + 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` 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 \ No newline at end of file diff --git a/src-tauri/plugins/CONTRIBUTING.md b/src-tauri/plugins/CONTRIBUTING.md new file mode 100644 index 000000000..2f999d617 --- /dev/null +++ b/src-tauri/plugins/CONTRIBUTING.md @@ -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() -> TauriPlugin { + 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 { + Ok(format!("Result: {}", param)) +} +``` + +```typescript +import { invoke } from '@tauri-apps/api/core' + +export async function myCommand(param: string): Promise { + 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) \ No newline at end of file diff --git a/web-app/CONTRIBUTING.md b/web-app/CONTRIBUTING.md new file mode 100644 index 000000000..32d7779bd --- /dev/null +++ b/web-app/CONTRIBUTING.md @@ -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 = ({ title, onAction }) => { + return ( +
+

{title}

+ +
+ ) +} +``` + +### 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('') + +// Global state (Zustand) +export const useAppState = create((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
{processData(data)}
+}) + +// 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 (`