Thank you for your interest in contributing to Steroids. This guide will help you get started.
Be respectful. Be professional. Focus on the code, not the person.
- Node.js 20 LTS (nvm recommended)
- pnpm 9+ (
corepack enable pnpm) - Git 2.40+
# 1. Fork and clone the repository
git clone https://github.com/YOUR_USERNAME/steroids.git
cd steroids
# 2. Install dependencies
pnpm install
# 3. Set up environment
cp .env.example .env
# 4. Start development server
pnpm dev
# 5. Verify everything works
pnpm testInstall these extensions:
- ESLint
- Prettier
- Tailwind CSS IntelliSense
Recommended settings (.vscode/settings.json):
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.preferences.importModuleSpecifier": "relative"
}Steroids/
├── src/ # Steroids CLI implementation
├── API/ # API service (code)
├── WebUI/ # Web dashboard (code)
├── Monitor/ # Mac menu bar app (code)
├── pump/ # Data gathering CLI (code)
├── iron/ # Documentation scaffolding CLI (code)
├── docs/ # Documentation
└── tests/ # Test suites
# Feature
git checkout -b feature/add-project-search
# Bug fix
git checkout -b fix/task-status-toggle
# Documentation
git checkout -b docs/update-readmeFollow the coding standards in CLAUDE.md:
- Maximum 500 lines per file
- Single responsibility per module
- All dependencies injectable
- Tests for new functionality
# Run all tests
pnpm test
# Run specific test
pnpm test src/domain/entities/Project.test.ts
# Run with coverage
pnpm test:coverage
# Run E2E tests
pnpm test:e2eWe use Conventional Commits:
# Format: <type>(<scope>): <description>
# Types:
feat # New feature
fix # Bug fix
docs # Documentation only
style # Formatting, no code change
refactor # Code change that neither fixes nor adds
test # Adding or updating tests
chore # Maintenance tasks
# Examples:
git commit -m "feat(cli): add project search command"
git commit -m "fix(webui): resolve task toggle race condition"
git commit -m "docs: update installation instructions"
git commit -m "test(api): add integration tests for projects endpoint"git push origin feature/add-project-searchThen open a Pull Request on GitHub.
Use the same format as commits:
feat(cli): add project search command
Use this template:
## Summary
Brief description of changes.
## Changes
- Added X
- Updated Y
- Fixed Z
## Testing
How did you test this?
## Screenshots
(If applicable)
## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] No file exceeds 500 lines
- [ ] All tests pass locally- Automated checks must pass (CI, linting, tests)
- At least one maintainer approval required
- All conversations must be resolved
- Squash merge preferred
// Use explicit types for function parameters and returns
function calculateHealth(metrics: Metrics): number {
return metrics.score;
}
// Use readonly for immutable data
interface Project {
readonly id: string;
readonly name: string;
}
// Prefer interfaces over types for objects
interface ProjectProps {
name: string;
}
// Use type for unions/intersections
type Status = 'active' | 'inactive';// Use function components with explicit props
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
export function Button({ label, onClick, disabled = false }: ButtonProps) {
return (
<button onClick={onClick} disabled={disabled}>
{label}
</button>
);
}// One test = one assertion (or closely related assertions)
it('returns true when health score >= 80', () => {
const project = createTestProject({ healthScore: 80 });
expect(project.isHealthy()).toBe(true);
});
// Use descriptive test names
describe('Project', () => {
describe('isHealthy', () => {
it('returns true when healthScore >= 80');
it('returns false when healthScore < 80');
it('returns false when healthScore is null');
});
});Start with domain entities and value objects:
// src/domain/entities/NewFeature.ts
export class NewFeature {
// ...
}Add application logic:
// src/application/use-cases/NewFeatureUseCase.ts
export class NewFeatureUseCase {
constructor(private readonly repository: INewFeatureRepository) {}
async execute(input: Input): Promise<Output> {
// ...
}
}Implement repositories and external integrations:
// src/infrastructure/persistence/file/FileNewFeatureRepository.ts
export class FileNewFeatureRepository implements INewFeatureRepository {
// ...
}Add API routes or CLI commands:
// API route
fastify.get('/api/new-feature', handler);
// CLI command
program.command('new-feature').action(handler);Add tests at each layer:
tests/unit/domain/entities/NewFeature.test.ts
tests/unit/application/use-cases/NewFeatureUseCase.test.ts
tests/integration/api/new-feature.test.ts
- Create command file:
src/commands/mycommand.ts - Register in
src/index.ts - Add tests:
tests/integration/cli/mycommand.test.ts - Update README with usage
- Create route handler:
API/src/routes/myroute.ts - Add Zod schema for validation
- Register in router
- Add integration tests
- Update API documentation
# Rebuild TypeScript
pnpm build
# Or restart dev server
pnpm dev# Run with verbose output
pnpm test --reporter=verbose
# Run single test in isolation
pnpm test src/specific.test.ts# Find process using port 3000
lsof -i :3000
# Kill it
kill -9 <PID>- Questions: Open a Discussion
- Bugs: Open an Issue
- Security: Email security@unlikeother.ai
Contributors are recognized in:
- GitHub Contributors page
- Release notes for significant contributions
- AUTHORS file for major features
Thank you for contributing to Steroids!