Thank you for your interest in contributing to OpenSpec! We're excited to work with the community to build the best open-source specification generation tool.
OpenSpec democratizes spec-driven development by replicating Kiro IDE's Spec Mode functionality, allowing developers to generate comprehensive technical specifications using any AI model from OpenRouter's API.
- Code of Conduct
- Getting Started
- Development Setup
- Development Workflow
- Code Style & Standards
- Testing Guidelines
- Commit Convention
- Pull Request Process
- Issue Reporting
- Code Review Guidelines
- Release Process
- Community & Support
We are committed to providing a welcoming and inclusive environment for all contributors. By participating in this project, you agree to abide by our Code of Conduct:
- Be respectful: Treat all community members with respect and kindness
- Be inclusive: Welcome newcomers and help them get up to speed
- Be collaborative: Work together towards common goals
- Be constructive: Provide helpful feedback and suggestions
- Be professional: Keep discussions focused and appropriate
Before contributing, ensure you have:
- Node.js 18+ installed (Download)
- Git installed and configured
- OpenRouter API key for testing (Get yours here)
- Basic knowledge of TypeScript, React, and Next.js
We welcome contributions in several areas:
- π Bug fixes - Help resolve issues and improve stability
- β¨ New features - Add functionality that aligns with our roadmap
- π Documentation - Improve guides, comments, and examples
- π§ͺ Testing - Add test coverage and improve test quality
- π¨ UI/UX - Enhance user experience and accessibility
- π§ Performance - Optimize performance and reduce bundle size
- π Internationalization - Add support for multiple languages
# Fork the repository on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/OpenSpec.git
cd OpenSpec
# Add upstream remote
git remote add upstream https://github.com/spenceriam/OpenSpec.git# Install all dependencies
npm install
# Verify installation
npm run lint # Should complete without errors
npm test # Should run test suiteOpenSpec is a client-side only application with no backend. All configuration happens in the browser:
- API Keys: Managed in browser memory (sessionStorage)
- No Environment Variables: All configuration is client-side
- No Database: Uses browser localStorage for persistence
# Start development server
npm run dev
# Open in browser
open http://localhost:3000main- Production-ready code, protected branchfeature/description- New featuresfix/description- Bug fixesdocs/description- Documentation updatestest/description- Test improvements
-
Sync with upstream
git checkout main git pull upstream main
-
Create feature branch
git checkout -b feature/your-feature-name
-
Make changes
- Write code following our style guidelines
- Add tests for new functionality
- Update documentation as needed
-
Test your changes
npm run lint # Check code style npm test # Run all tests npm run build # Verify build works
-
Commit and push
git add . git commit -m "feat: add your feature description" git push origin feature/your-feature-name
-
Create Pull Request
- Use our PR template
- Link related issues
- Request reviews from maintainers
// β
Good - Proper typing
interface WorkflowState {
currentPhase: 'requirements' | 'design' | 'tasks'
apiKey: string | null
modelId: string | null
}
// β Avoid - Using 'any'
const data: any = getWorkflowData()
// β
Good - JSDoc for complex functions
/**
* Generates requirements specification using OpenRouter API
* @param prompt - User's feature description
* @param contextFiles - Optional context files
* @returns Promise resolving to generated specification
*/
async function generateRequirements(
prompt: string,
contextFiles?: ContextFile[]
): Promise<SpecificationResult>// β
Good - Server Component (default)
export default function StaticPage() {
return <div>Static content</div>
}
// β
Good - Client Component (when needed)
'use client'
import { useState } from 'react'
export default function InteractiveComponent() {
const [state, setState] = useState('')
// ...
}
// β
Good - Custom hooks for logic
export function useSpecWorkflow() {
// Complex state logic here
}// β
Good - Component organization
import { forwardRef } from 'react'
import { cn } from '@/lib/utils'
interface ButtonProps {
variant?: 'default' | 'destructive' | 'outline'
size?: 'default' | 'sm' | 'lg'
// ... other props
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = 'default', size = 'default', ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = 'Button'
export { Button }// β
Good - Proper error handling
try {
const response = await openRouterClient.generateContent({
model: selectedModel,
messages: [...messages],
})
if (!response.choices?.[0]?.message?.content) {
throw new Error('Invalid API response format')
}
return response
} catch (error) {
console.error('API call failed:', error)
throw new Error(`Generation failed: ${error.message}`)
}- Use Tailwind CSS for all styling
- Follow shadcn/ui patterns for component consistency
- Dark theme first - ensure all components work in dark mode
- Responsive design - mobile-first approach
- Accessibility - proper ARIA labels and keyboard navigation
// β
Good - Comprehensive component test
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { ModelSelector } from '../ModelSelector'
describe('ModelSelector', () => {
const mockProps = {
apiKey: 'sk-or-v1-test-key',
selectedModel: null,
onModelSelect: jest.fn(),
}
beforeEach(() => {
jest.clearAllMocks()
})
it('renders loading state initially', () => {
render(<ModelSelector {...mockProps} />)
expect(screen.getByRole('status')).toBeInTheDocument()
})
it('selects model on click', async () => {
render(<ModelSelector {...mockProps} />)
await waitFor(() => {
expect(screen.getByText('Claude 3 Sonnet')).toBeInTheDocument()
})
fireEvent.click(screen.getByText('Claude 3 Sonnet'))
expect(mockProps.onModelSelect).toHaveBeenCalledWith('anthropic/claude-3-sonnet')
})
})- Unit Tests: Test individual functions and utilities
- Component Tests: Test React components with user interactions
- Integration Tests: Test OpenRouter API integration (mocked)
- Accessibility Tests: Verify ARIA compliance and keyboard navigation
- Error Handling: Test edge cases and error recovery
# Run all tests
npm test
# Run specific test suite
npm run test:unit # Unit tests only
npm run test:components # Component tests only
npm run test:integration # Integration tests only
# Run in watch mode
npm run test:watch
# Generate coverage report
npm run test:coverage
# CI/CD testing
npm run test:ciWe use Conventional Commits for clear commit history:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
- feat: New features
- fix: Bug fixes
- docs: Documentation changes
- style: Code formatting (no logic changes)
- refactor: Code refactoring
- test: Adding or updating tests
- chore: Maintenance tasks
- perf: Performance improvements
- ci: CI/CD changes
# Good commit messages
git commit -m "feat: add model selection persistence"
git commit -m "fix: resolve API key validation bug"
git commit -m "docs: update contribution guidelines"
git commit -m "test: add ModelSelector integration tests"
git commit -m "refactor: extract OpenRouter client logic"
# Detailed commit with body
git commit -m "feat: implement ZIP export functionality
- Add ZIP file generation for all specification files
- Include Mermaid diagrams as separate files
- Support both individual and bulk export options
Fixes #123"- Descriptive title following conventional commit format
- Detailed description explaining changes and motivation
- Link related issues using "Fixes #123" or "Relates to #123"
- Tests added for new functionality
- Documentation updated if needed
- Screenshots for UI changes
- Breaking changes clearly documented
## Description
Brief description of changes and motivation.
## Type of Change
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that causes existing functionality to change)
- [ ] Documentation update
## Testing
- [ ] Unit tests pass
- [ ] Component tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed
## Screenshots (if applicable)
Add screenshots for UI changes.
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Tests added for new functionality
- [ ] Documentation updated
- [ ] No breaking changes (or clearly documented)- Automated Checks: CI/CD runs linting, testing, and building
- Code Review: At least one maintainer reviews the code
- Testing: Reviewers test functionality manually if needed
- Approval: Approved PRs can be merged
- Merge: Squash and merge with conventional commit message
- Search existing issues for duplicates
- Check documentation and AGENTS.md
- Verify issue exists in latest version
- Prepare reproduction steps
**Describe the bug**
A clear description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
What you expected to happen.
**Screenshots**
If applicable, add screenshots.
**Environment:**
- OS: [e.g. macOS, Windows, Linux]
- Browser: [e.g. Chrome, Firefox, Safari]
- Version: [e.g. 22]
- Node.js version: [e.g. 18.17.0]
**Additional context**
Any other context about the problem.**Is your feature request related to a problem?**
A clear description of what the problem is.
**Describe the solution you'd like**
A clear description of what you want to happen.
**Describe alternatives you've considered**
Other solutions you've considered.
**Additional context**
Any other context or screenshots about the feature request.- Write clear PRs with good descriptions
- Keep changes focused - one feature/fix per PR
- Add tests for new functionality
- Update documentation as needed
- Respond to feedback promptly and constructively
- Be constructive - suggest improvements, don't just point out problems
- Ask questions - understand the motivation and approach
- Test functionality - verify changes work as expected
- Check edge cases - consider error handling and unusual inputs
- Approve when ready - don't hold up good changes unnecessarily
- Code follows style guidelines
- Logic is clear and well-documented
- Tests cover new functionality
- No obvious bugs or edge cases missed
- Performance considerations addressed
- Security implications considered
- Breaking changes properly documented
We follow Semantic Versioning:
- MAJOR (1.0.0): Breaking changes
- MINOR (0.1.0): New features (backward compatible)
- PATCH (0.0.1): Bug fixes (backward compatible)
- Version bump in package.json
- Update changelog with new features and fixes
- Create release with GitHub Releases
- Deploy to production (automated via Vercel)
- Announce on community channels
- Documentation: Check README.md and AGENTS.md
- Issues: GitHub Issues for bugs and feature requests
- Discussions: GitHub Discussions for questions and ideas
- Contact: Reach out to @spencer_i_am on X
We appreciate all contributions! Contributors will be:
- Listed in our contributor documentation
- Credited in release notes for significant contributions
- Invited to join our contributor community
- Recognized on social media for major contributions
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: Questions, ideas, and general discussion
- X/Twitter: Follow @spencer_i_am for updates
- Email: For security issues or private matters
- Next.js Documentation: nextjs.org/docs
- TypeScript Handbook: typescriptlang.org/docs
- Tailwind CSS: tailwindcss.com/docs
- shadcn/ui: ui.shadcn.com
- OpenRouter API: openrouter.ai/docs
- Jest Testing: jestjs.io/docs
- React Testing Library: testing-library.com/docs/react-testing-library/intro
Thank you for contributing to OpenSpec! π
Together, we're building the future of spec-driven development. Every contribution, no matter how small, helps make OpenSpec better for developers worldwide.
Made with β€οΈ for open source agentic coding