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
Copy
# 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...}
Copy
// 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!;}
Copy
// 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.0.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 `; }}
Copy
// 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
Copy
// 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
Copy
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
Copy
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
Copy
---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
Copy
# 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
Copy
/** * 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>;
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!