Contributing to NikCLI helps build the future of AI-assisted development. Whether you’re fixing bugs, adding features, improving documentation, or creating agents, your contributions make a real difference for developers worldwide.
Getting Started
Set up your development environment and make your first contribution
Code Contributions
Guidelines for submitting high-quality code contributions
Agent Development
Create and contribute new AI agents to the ecosystem
Community
Join our vibrant community of contributors and maintainers
# Required softwareNode.js 18+ (LTS recommended)npm 9+ or yarn 1.22+Git 2.30+# Recommended toolsVS Code with extensions:- TypeScript and JavaScript Language Features- ESLint- Prettier- Jest Runner- GitLens# System resourcesRAM: 8GB minimum (16GB recommended)Storage: 10GB free space for developmentOS: macOS, Linux, or Windows with WSL2
# Clone the repositorygit clone https://github.com/cadcamfun/nikcli.gitcd nikcli# Install dependenciesnpm install# Set up development environmentcp .env.example .env.local# Edit .env.local with your API keys and configuration# Run initial setupnpm run setup:dev# Start development servernpm run dev# Run tests to verify setupnpm test
// Use strict TypeScript configuration// Always define explicit types for public APIsinterface AgentConfig { name: string; version: string; capabilities: AgentCapability[]; tools: ToolDefinition[];}// Use generic types when appropriateclass AgentManager<T extends BaseAgent> { private agents = new Map<string, T>(); register(agent: T): void { this.agents.set(agent.id, agent); } get(id: string): T | undefined { return this.agents.get(id); }}// Document complex functions with JSDoc/** * Executes an agent task with retry logic and error handling * @param agentId - The ID of the agent to execute * @param task - The task to execute * @param options - Execution options including retry and timeout settings * @returns Promise that resolves to the task result */async function executeAgentTask( agentId: string, task: AgentTask, options: ExecutionOptions = {}): Promise<AgentResult> { // Implementation...}
// Use custom error types for different scenariosexport class AgentExecutionError extends Error { constructor( message: string, public agentId: string, public taskId: string, public cause?: Error ) { super(message); this.name = 'AgentExecutionError'; }}// Implement proper error handling with recoveryasync function executeWithRetry<T>( operation: () => Promise<T>, maxRetries: number = 3, delay: number = 1000): Promise<T> { let lastError: Error; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await operation(); } catch (error) { lastError = error as Error; if (attempt === maxRetries) { throw new AgentExecutionError( `Operation failed after ${maxRetries} attempts`, 'unknown', 'unknown', lastError ); } await new Promise(resolve => setTimeout(resolve, delay * attempt)); } } throw lastError!;}
// Unit test exampleimport { describe, it, expect, beforeEach, jest } from '@jest/globals';import { AgentManager } from '../agent-manager';import { MockAgent } from '../../test-utils/mock-agent';describe('AgentManager', () => { let agentManager: AgentManager; let mockAgent: MockAgent; beforeEach(() => { agentManager = new AgentManager(); mockAgent = new MockAgent('test-agent'); }); describe('register', () => { it('should register an agent successfully', () => { agentManager.register(mockAgent); expect(agentManager.get('test-agent')).toBe(mockAgent); }); it('should throw error when registering duplicate agent', () => { agentManager.register(mockAgent); expect(() => agentManager.register(mockAgent)) .toThrow('Agent test-agent is already registered'); }); }); describe('execute', () => { it('should execute agent task successfully', async () => { const task = { id: 'task-1', description: 'Test task' }; const expectedResult = { success: true, output: 'Task completed' }; mockAgent.execute.mockResolvedValue(expectedResult); agentManager.register(mockAgent); const result = await agentManager.execute('test-agent', task); expect(result).toEqual(expectedResult); expect(mockAgent.execute).toHaveBeenCalledWith(task); }); });});
# Test coverage requirements- Unit tests: 90% statement coverage minimum- Integration tests: All service interactions- End-to-end tests: Critical user workflows- Performance tests: Response time benchmarks# Running different test suitesnpm run test:unit # Fast unit testsnpm run test:integration # Service integration tests npm run test:e2e # End-to-end browser testsnpm run test:performance # Performance benchmarksnpm run test:security # Security vulnerability tests# Test in different environmentsnpm run test:node-18 # Test on Node.js 18npm run test:node-20 # Test on Node.js 20npm run test:windows # Windows-specific testsnpm run test:linux # Linux-specific testsnpm run test:macos # macOS-specific tests
// src/cli/automation/agents/my-custom-agent.tsimport { BaseAgent, AgentCapability, AgentResult } from './base-agent';import { ToolRegistry } from '../tools/tool-registry';export class MyCustomAgent extends BaseAgent { constructor() { super({ id: 'my-custom-agent', name: 'My Custom Agent', description: 'Specialized agent for custom tasks', version: '1.6.0', capabilities: [ AgentCapability.CODE_GENERATION, AgentCapability.CODE_REVIEW, AgentCapability.TESTING ], specializations: ['custom-framework', 'domain-specific'], tools: [ 'file_operations', 'code_analysis', 'custom_validator' ] }); } async execute(task: AgentTask): Promise<AgentResult> { try { // Validate task requirements this.validateTask(task); // Process task with domain expertise const result = await this.processCustomTask(task); // Validate result quality await this.validateResult(result); return { success: true, result: result, confidence: this.calculateConfidence(result), suggestions: this.generateSuggestions(result) }; } catch (error) { return this.handleError(error, task); } } private async processCustomTask(task: AgentTask): Promise<any> { // Custom processing logic const context = await this.analyzeContext(task.context); const solution = await this.generateSolution(task.description, context); return await this.refineSolution(solution, task.requirements); } protected getSystemPrompt(): string { return ` You are a specialized agent expert in custom framework development. You have deep knowledge of: - Custom framework patterns and best practices - Domain-specific architecture patterns - Performance optimization techniques - Testing strategies for custom frameworks Always provide: - Clean, maintainable code - Comprehensive documentation - Appropriate test coverage - Performance considerations `; }}
// src/cli/register-agents.tsimport { AgentRegistry } from './core/agent-registry';import { MyCustomAgent } from './automation/agents/my-custom-agent';export function registerAllAgents(): void { const registry = AgentRegistry.getInstance(); // Register existing agents... // Register new custom agent registry.register(new MyCustomAgent()); // Agent is now available via: // /agent my-custom-agent "task description" // /agents (will list the new agent)}
Single Responsibility: Each agent should have a clear, focused purpose
// Good: Focused agentexport class ReactTestingAgent extends BaseAgent { // Specialized in React component testing only}// Avoid: Overly broad agentexport class FullStackEverythingAgent extends BaseAgent { // Tries to do too many different things}
Domain Expertise: Agents should have deep knowledge in their domain
protected getSystemPrompt(): string { return ` You are a React testing expert with deep knowledge of: - Jest and React Testing Library best practices - Component testing strategies (unit, integration) - Mock strategies for complex components - Testing hooks and context providers - Accessibility testing with jest-axe - Visual regression testing approaches `;}
Error Handling
async execute(task: AgentTask): Promise<AgentResult> { try { // Validate inputs if (!this.canHandleTask(task)) { return { success: false, error: 'This agent cannot handle the requested task type', suggestions: ['Try the universal-agent or a more appropriate specialist'] }; } // Execute with timeout protection const result = await Promise.race([ this.processTask(task), this.timeoutPromise(30000) // 30 second timeout ]); return result; } catch (error) { // Log error for debugging but don't expose internal details this.logger.error('Agent execution failed', { agentId: this.id, taskId: task.id, error }); return { success: false, error: 'An unexpected error occurred while processing the task', suggestions: [ 'Try rephrasing the request', 'Check if all required context is provided', 'Consider breaking the task into smaller parts' ] }; }}
Structure: Follow established patterns and organization
---title: 'Clear, Descriptive Title'description: 'Concise description of the content'icon: 'relevant-icon'---## OverviewBrief introduction with key benefits/features<CardGroup cols={2}> <!-- Feature highlights --></CardGroup>## Main Content Sections### Subsection<Tabs> <Tab title="Basic Usage"> <!-- Simple examples first --> </Tab> <Tab title="Advanced Usage"> <!-- Complex examples after --> </Tab></Tabs>## Next Steps<CardGroup cols={2}> <!-- Related documentation links --></CardGroup>
Code Examples: Always include working, tested examples
# Always show the actual command/agent react-expert "create a login component with validation"# Show expected output or results when helpful# ✓ Component created: src/components/LoginForm.tsx# ✓ Tests created: src/components/__tests__/LoginForm.test.tsx# ✓ Storybook story: src/stories/LoginForm.stories.tsx
/** * Executes an agent task with comprehensive error handling and validation * * @param agentId - Unique identifier for the agent to execute * @param task - Task object containing description and context * @param options - Optional execution parameters * @returns Promise resolving to the agent execution result * * @example * ```typescript * const result = await executeAgent('react-expert', { * description: 'Create a modal component', * context: { workspace: './src', files: ['types.ts'] } * }); * * if (result.success) { * console.log('Task completed:', result.output); * } * ``` * * @throws {AgentNotFoundError} When the specified agent doesn't exist * @throws {InvalidTaskError} When the task is malformed or incomplete */export async function executeAgent( agentId: string, task: AgentTask, options?: ExecutionOptions): Promise<AgentResult>;
Understand NikCLI’s architecture and design decisions
Extending NikCLI
Learn advanced techniques for extending NikCLI
GitHub Repository
Visit our repository to start contributing
Discord Community
Join our development community discussions
Start small with documentation fixes or bug reports, then gradually work up to feature contributions. Don’t hesitate to ask questions in Discord or GitHub Discussions - our community is here to help!