Converted from Claude Code boilerplate to opencode: - CLAUDE.md -> AGENTS.md (opencode instructions) - .claude/settings.json -> opencode.json (permissions schema) - .claude/agents/ -> .opencode/agent/ (subagents with mode: subagent) - .claude/commands/ -> .opencode/command/ (slash commands with ) - .claude/skills/ -> .opencode/skills/ (7 skills, removed allowed-tools) - DevContainer updated to install opencode - All .claude/ paths and Claude Code references updated
8.5 KiB
8.5 KiB
Development Guidelines
Coding Conventions
Naming Conventions
Variables and Functions
TypeScript/JavaScript:
// ✅ Good example
const userProfileData = fetchUserProfile();
function calculateTotalPrice(items: CartItem[]): number { }
// ❌ Bad example
const data = fetch();
function calc(arr: any[]): number { }
Principles:
- Variables: camelCase, noun or noun phrase
- Functions: camelCase, start with a verb
- Constants: UPPER_SNAKE_CASE
- Boolean: start with
is,has, orshould
Classes and Interfaces
// Class: PascalCase, noun
class TaskManager { }
class UserAuthenticationService { }
// Interface: PascalCase, with or without the I prefix
interface ITaskRepository { }
interface Task { }
// Type alias: PascalCase
type TaskStatus = 'todo' | 'in_progress' | 'completed';
Code Formatting
Indentation: [2 spaces / 4 spaces / tabs]
Line length: maximum [80/100/120] characters
Example:
// [language] code formatting example
[code example]
Comment Conventions
Function and class documentation:
/**
* Calculate the total number of tasks
*
* @param tasks - Array of tasks to count
* @param filter - Filter condition (optional)
* @returns Total number of tasks
* @throws {ValidationError} When the task array is invalid
*/
function countTasks(
tasks: Task[],
filter?: TaskFilter
): number {
// Implementation
}
Inline comments:
// ✅ Good example: explain why you do it
// Invalidate the cache to fetch the latest data
cache.clear();
// ❌ Bad example: what you are doing (obvious from the code)
// Clear the cache
cache.clear();
Error Handling
Principles:
- Expected errors: define an appropriate error class
- Unexpected errors: propagate upward
- Do not ignore errors
Example:
// Error class definition
class ValidationError extends Error {
constructor(
message: string,
public field: string,
public value: unknown
) {
super(message);
this.name = 'ValidationError';
}
}
// Error handling
try {
const task = await taskService.create(data);
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation error [${error.field}]: ${error.message}`);
// Provide feedback to the user
} else {
console.error('Unexpected error:', error);
throw error; // Propagate upward
}
}
Git Workflow Rules
Branching Strategy
Branch types:
main: ready to deploy to productiondevelop: latest development statefeature/[feature-name]: new feature developmentfix/[fix-description]: bug fixesrefactor/[target]: refactoring
Flow:
main
└─ develop
├─ feature/task-management
├─ feature/user-auth
└─ fix/task-validation
Commit Message Conventions
Format:
<type>(<scope>): <subject>
<body>
<footer>
Type:
feat: new featurefix: bug fixdocs: documentationstyle: code formattingrefactor: refactoringtest: adding or fixing testschore: build, supporting tools, etc.
Example:
feat(task): add a task priority setting feature
Allowed users to set a priority (high/medium/low) on tasks.
- Added a priority field to the Task model
- Added a --priority option to the CLI
- Implemented sorting by priority
Closes #123
Pull Request Process
Checks before creating:
- All tests pass
- No lint errors
- Type checking passes
- Conflicts are resolved
PR template:
## Overview
[A brief description of the changes]
## Reason for Change
[Why this change is necessary]
## Changes
- [change 1]
- [change 2]
## Testing
- [ ] Unit tests added
- [ ] Manual testing performed
## Screenshots (if applicable)
[image]
## Related Issue
Closes #[issue number]
Review process:
- Self-review
- Run automated tests
- Assign reviewers
- Address review feedback
- Merge after approval
Test Strategy
Test Types
Unit Tests
Target: individual functions and classes
Coverage target: [80/90/100]%
Example:
describe('TaskService', () => {
describe('create', () => {
it('can create a task with valid data', async () => {
const service = new TaskService(mockRepository);
const task = await service.create({
title: 'Test task',
description: 'Description',
});
expect(task.id).toBeDefined();
expect(task.title).toBe('Test task');
});
it('throws ValidationError when the title is empty', async () => {
const service = new TaskService(mockRepository);
await expect(
service.create({ title: '' })
).rejects.toThrow(ValidationError);
});
});
});
Integration Tests
Target: coordination of multiple components
Example:
describe('Task CRUD', () => {
it('can create, read, update, and delete a task', async () => {
// Create
const created = await taskService.create({ title: 'Test' });
// Read
const found = await taskService.findById(created.id);
expect(found?.title).toBe('Test');
// Update
await taskService.update(created.id, { title: 'Updated' });
const updated = await taskService.findById(created.id);
expect(updated?.title).toBe('Updated');
// Delete
await taskService.delete(created.id);
const deleted = await taskService.findById(created.id);
expect(deleted).toBeNull();
});
});
E2E Tests
Target: the entire user scenario
Example:
describe('Task management flow', () => {
it('a user can add and complete a task', async () => {
// Add a task
await cli.run(['add', 'New task']);
expect(output).toContain('Task added');
// Display the task list
await cli.run(['list']);
expect(output).toContain('New task');
// Complete the task
await cli.run(['complete', '1']);
expect(output).toContain('Task completed');
});
});
Test Naming Conventions
Pattern: [target]_[condition]_[expectedResult]
Example:
// ✅ Good example
it('create_emptyTitle_throwsValidationError', () => { });
it('findById_existingId_returnsTask', () => { });
it('delete_nonExistentId_throwsNotFoundError', () => { });
// ❌ Bad example
it('test1', () => { });
it('works', () => { });
it('should work correctly', () => { });
Using Mocks and Stubs
Principles:
- Mock external dependencies (API, DB, file system)
- Use the real implementation for business logic
Example:
// Mock the repository
const mockRepository: ITaskRepository = {
save: jest.fn(),
findById: jest.fn(),
findAll: jest.fn(),
delete: jest.fn(),
};
// The service uses the real implementation
const service = new TaskService(mockRepository);
Code Review Criteria
Review Points
Functionality:
- Does it meet the requirements?
- Are edge cases considered?
- Is error handling appropriate?
Readability:
- Is the naming clear?
- Are the comments appropriate?
- Is complex logic explained?
Maintainability:
- Is there any duplicate code?
- Are responsibilities clearly separated?
- Is the impact scope of changes limited?
Performance:
- Are there any unnecessary computations?
- Is there any possibility of a memory leak?
- Are database queries optimized?
Security:
- Is input validation appropriate?
- Is any sensitive information hardcoded?
- Are permission checks implemented?
How to Write Review Comments
Constructive feedback:
## ✅ Good example
With this implementation, performance may degrade as the number of tasks grows.
How about considering a search that uses an index instead?
## ❌ Bad example
This way of writing it is not good.
Indicate priority:
[required]: must be fixed[recommended]: fix recommended[suggestion]: please consider[question]: a question for understanding
Development Environment Setup
Required Tools
| Tool | Version | Installation method |
|---|---|---|
| tool 1 | [version] | [command] |
| tool 2 | [version] | [command] |
Setup Procedure
# 1. Clone the repository
git clone [URL]
cd [project-name]
# 2. Install dependencies
[install command]
# 3. Set environment variables
cp .env.example .env
# Edit the .env file
# 4. Start the development server
[start command]