Skip to main content
Cluely welcomes contributions from the community! While active maintenance is limited, quality pull requests are reviewed and merged.

Ways to Contribute

Bug Fixes

Fix crashes, errors, or unexpected behavior

New Features

Add AI model integrations, UI improvements, or new capabilities

Documentation

Improve guides, add examples, or fix typos

Translations

Help make Cluely accessible in more languages

Getting Started

1

Fork and Clone

# Fork the repository on GitHub first, then:
git clone https://github.com/YOUR_USERNAME/interview-coder-frontend.git
cd interview-coder-frontend
2

Install Dependencies

npm install
See the Building guide if you encounter issues.
3

Create a Branch

git checkout -b feature/your-feature-name
# or
git checkout -b fix/bug-description
Branch naming conventions:
  • feature/ - New features
  • fix/ - Bug fixes
  • docs/ - Documentation changes
  • refactor/ - Code improvements without behavior changes
4

Make Your Changes

Write code, test thoroughly, and commit frequently with clear messages.
5

Test Your Changes

# Run in development mode
npm start

# Test production build
npm run dist
6

Submit a Pull Request

Push to your fork and open a PR against the main branch.

Code Style and Standards

TypeScript Guidelines

// ✅ Explicit types for parameters and returns
export async function takeScreenshot(
  hideMainWindow: () => void,
  showMainWindow: () => void
): Promise<string> {
  // Implementation
}

// ✅ Interface for complex objects
interface ScreenshotMetadata {
  path: string
  preview: string
  question: string
}

// ✅ Use union types for limited options
type View = "queue" | "solutions" | "debug"

React Component Patterns

// ✅ Use functional components with TypeScript
interface QueueProps {
  setView: (view: "queue" | "solutions") => void
}

const Queue: React.FC<QueueProps> = ({ setView }) => {
  const [screenshots, setScreenshots] = useState<Screenshot[]>([])
  
  useEffect(() => {
    // Side effects here
  }, [])
  
  return (
    <div>
      {/* Component JSX */}
    </div>
  )
}

export default Queue

Electron Best Practices

// ✅ Main Process: Use handle for async operations
ipcMain.handle("take-screenshot", async () => {
  try {
    const screenshotPath = await appState.takeScreenshot()
    return { success: true, path: screenshotPath }
  } catch (error) {
    console.error("Screenshot error:", error)
    throw error
  }
})

// ✅ Main Process: Use send for events
mainWindow.webContents.send("screenshot-taken", { path, preview })

// ✅ Renderer: Invoke for requests
const result = await window.electronAPI.takeScreenshot()

// ✅ Renderer: Listen for events
window.electronAPI.onScreenshotTaken((event, data) => {
  console.log("Screenshot taken:", data.path)
})

File Organization

electron/
  ├── main.ts              # App initialization, AppState singleton
  ├── ipcHandlers.ts       # All IPC communication handlers
  ├── WindowHelper.ts      # Window management logic
  ├── ScreenshotHelper.ts  # Screenshot operations
  ├── LLMHelper.ts         # AI/LLM integrations
  ├── ProcessingHelper.ts  # AI processing pipeline
  └── shortcuts.ts         # Global keyboard shortcuts

src/
  ├── App.tsx              # Root component
  ├── main.tsx             # React entry point
  ├── _pages/              # Top-level page components
  │   ├── Queue.tsx
  │   ├── Solutions.tsx
  │   └── Debug.tsx
  ├── components/          # Reusable components
  │   ├── Queue/
  │   ├── Solutions/
  │   └── ui/              # Generic UI components
  └── context/             # React Context providers
Rules:
  • Helper classes go in electron/ with descriptive names
  • React pages go in src/_pages/
  • Reusable components go in src/components/
  • One component per file (except tiny sub-components)

Naming Conventions

TypeConventionExample
FilesPascalCase for componentsScreenshotHelper.ts
camelCase for utilitiesipcHandlers.ts
ClassesPascalCaseAppState, WindowHelper
InterfacesPascalCaseScreenshotMetadata
FunctionscamelCasetakeScreenshot()
VariablescamelCasescreenshotPath
ConstantsUPPER_SNAKE_CASEMAX_SCREENSHOTS
React ComponentsPascalCaseQueue, ScreenshotItem

Git Commit Guidelines

Commit Message Format

<type>(<scope>): <subject>

<body>

<footer>
Types:
  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, no logic change)
  • refactor: Code refactoring
  • perf: Performance improvements
  • test: Adding tests
  • chore: Build process, dependencies, etc.
# Feature
feat(llm): add support for Claude AI provider

Integrates Anthropic's Claude API as an alternative LLM provider.
Users can now switch between Gemini, Ollama, and Claude.

# Bug Fix
fix(screenshot): prevent window flicker during capture

Increases delay before screenshot to 100ms to ensure window is
fully hidden. Fixes issue #123.

# Documentation
docs(readme): update installation instructions for Windows

Adds troubleshooting section for common Windows build errors.

Commit Frequency

Commit often, push less frequentlyMake small, logical commits as you work. Each commit should represent a single conceptual change. You can always squash commits later if needed.

Pull Request Process

1

Ensure Your Code Meets Standards

  • TypeScript compiles without errors
  • No console warnings or errors
  • Code follows style guidelines
  • Commits have clear messages
2

Update Documentation

If you:
  • Add a new feature → Update relevant docs
  • Change configuration → Update setup guide
  • Fix a bug → Add to troubleshooting if relevant
3

Write a Clear PR Description

Use this template:
## Description
Brief summary of what this PR does and why.

## Changes
- List of specific changes
- Made in this PR

## Testing
- [ ] Tested on macOS
- [ ] Tested on Windows
- [ ] Tested on Linux
- [ ] Tested with Gemini API
- [ ] Tested with Ollama

## Screenshots (if UI changes)
[Add screenshots or GIFs]

## Related Issues
Closes #123
4

Request Review

Tag maintainers or wait for automated review assignment.
5

Address Feedback

  • Respond to review comments
  • Make requested changes
  • Push additional commits (don’t force push unless asked)
6

Merge

Once approved, a maintainer will merge your PR.

Testing Guidelines

Manual Testing Checklist

Before submitting a PR, test:
  • App launches without errors
  • Window shows/hides with Cmd/Ctrl+Shift+Space
  • Screenshots captured with Cmd/Ctrl+H
  • Screenshots appear in queue
  • AI analysis works (test with actual API key)
  • Solutions display correctly
  • App quits properly
  • Works with 0 screenshots
  • Works with maximum (5) screenshots
  • Handles missing API key gracefully
  • Handles network errors (disconnect WiFi)
  • Works across multiple monitors
  • Window repositions correctly after screen resolution change
  • macOS: Window stays on top in full-screen apps
  • Windows: UI loads correctly
  • Linux: Window is focusable and interactive
  • All platforms: Keyboard shortcuts work

Adding Automated Tests

While Cluely doesn’t have extensive automated tests yet, contributions adding tests are welcome! Potential areas for testing:
  • Unit tests for helper classes (ScreenshotHelper, LLMHelper)
  • Integration tests for IPC communication
  • E2E tests with Playwright or Spectron

Common Contribution Scenarios

Adding a New AI Provider

1

Update LLMHelper

Add your provider in electron/LLMHelper.ts:
private async callYourProvider(prompt: string): Promise<string> {
  const response = await fetch("https://api.yourprovider.com/v1/chat", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${this.yourProviderApiKey}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ prompt, model: this.yourProviderModel })
  })
  
  const data = await response.json()
  return data.response
}
2

Add Switch Method

public async switchToYourProvider(apiKey: string, model?: string) {
  this.yourProviderApiKey = apiKey
  if (model) this.yourProviderModel = model
  this.useYourProvider = true
  this.useOllama = false
  this.useOpenRouter = false
  console.log(`[LLMHelper] Switched to YourProvider`)
}
3

Update IPC Handlers

Add handler in electron/ipcHandlers.ts:
ipcMain.handle("switch-to-yourprovider", async (_, apiKey, model) => {
  try {
    await appState.processingHelper
      .getLLMHelper()
      .switchToYourProvider(apiKey, model)
    return { success: true }
  } catch (error: any) {
    return { success: false, error: error.message }
  }
})
4

Update UI

Add option to ModelSelector.tsx component.
5

Document Usage

Update README with setup instructions and .env variables.

Fixing a Bug

1

Reproduce the Issue

  • Create minimal test case
  • Identify affected files
  • Check console for error messages
2

Fix and Test

  • Make the smallest change that fixes the issue
  • Test the fix thoroughly
  • Ensure no regressions
3

Add Error Handling

If the bug was caused by missing error handling:
// Before
const data = await fetchData()

// After
try {
  const data = await fetchData()
  return data
} catch (error) {
  console.error("Failed to fetch data:", error)
  throw new Error(`Data fetch failed: ${error.message}`)
}

Improving UI/UX

1

Identify Pain Point

  • User feedback
  • Personal experience
  • Usability testing
2

Design Solution

  • Create mockups or wireframes
  • Consider accessibility
  • Maintain consistency with existing UI
3

Implement with TailwindCSS

<div className="flex items-center gap-2 p-4 rounded-lg bg-gray-800 hover:bg-gray-700 transition-colors">
  <Icon className="w-5 h-5 text-blue-400" />
  <span className="text-sm font-medium">Action</span>
</div>
4

Test Responsiveness

  • Test with different window sizes
  • Ensure keyboard navigation works
  • Verify with screen readers (if applicable)

Code Review Expectations

What Reviewers Look For

Functionality

  • Does it work as intended?
  • Are edge cases handled?
  • No new bugs introduced?

Code Quality

  • Follows style guidelines?
  • Well-structured and readable?
  • Appropriate error handling?

Performance

  • No unnecessary re-renders?
  • Efficient algorithms?
  • No memory leaks?

Maintainability

  • Clear variable/function names?
  • Commented where necessary?
  • Follows existing patterns?

Responding to Feedback

Be receptive to feedback! Code review is collaborative, not adversarial. If you disagree with a suggestion, explain your reasoning politely.
Good responses:
  • “Good catch! I’ll fix that.”
  • “I chose this approach because X, but I’m open to alternatives.”
  • “Can you clarify what you mean by…?”
Avoid:
  • Defensive reactions
  • Ignoring feedback
  • Making unrelated changes in review commits

Development Environment Setup

Recommended tools for Cluely development:

Code Editor

Visual Studio Code (recommended) Install extensions:
  • ESLint - Code linting
  • Prettier - Code formatting
  • TypeScript Vue Plugin - Better TypeScript support
  • Tailwind CSS IntelliSense - Tailwind autocomplete

VS Code Settings

Add to .vscode/settings.json:
{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "typescript.tsdk": "node_modules/typescript/lib",
  "files.associations": {
    "*.css": "tailwindcss"
  }
}

Resources

Electron Docs

Official Electron documentation

React Docs

React official documentation

TypeScript Handbook

Learn TypeScript fundamentals

Tailwind CSS

TailwindCSS utility classes

Getting Help

1

Search Existing Issues

Check if someone else has encountered the same problem on GitHub Issues.
2

Read the Docs

Review the Architecture and Building guides.
3

Ask on GitHub Discussions

Open a discussion for questions or ideas before submitting an issue.
4

Contact Maintainer

For commercial integrations or custom development, reach out on Twitter.

Recognition

Contributors are recognized in:
  • GitHub contributor graph
  • Release notes (for significant contributions)
  • README acknowledgments (for major features)
Thank you for contributing to Cluely! Every contribution, no matter how small, helps make the project better for everyone.

Ready to Build?

Head back to the building guide to start coding!

Build docs developers (and LLMs) love