- Introduced new planning files including PROJECT.md, REQUIREMENTS.md, ROADMAP.md, and STATE.md to outline the vision and requirements for SSH multi-context workspaces. - Added ARCHITECTURE.md and CONCERNS.md to detail the codebase structure and address technical debt, known bugs, and security considerations. - Created CONVENTIONS.md to establish coding standards and practices for the project. - Updated .gitignore to exclude demo files and added configuration for planning tools. This commit lays the groundwork for enhancing SSH functionality and user experience in managing multiple workspaces.
10 KiB
Coding Conventions
Analysis Date: 2026-02-12
Naming Patterns
Files:
- Services/Components: PascalCase -
ChunkBuilder.ts,ProjectScanner.ts,AIChatGroup.tsx - Utilities: camelCase -
pathDecoder.ts,tokenizer.ts,formatters.ts - Type definitions: camelCase -
messages.ts,chunks.ts,data.ts - Test files:
*.test.ts- mirrors source file name
Functions:
- Standard functions: camelCase -
encodePath,extractProjectName,formatDuration - Type guards:
isXxx-isParsedRealUserMessage,isAIChunk,isValidEncodedPath - Builder functions:
buildXxx-buildChunks,buildUserChunk,buildSessionPath - Getter functions:
getXxx-getProjectsBasePath,getExpandedDisplayItemIds - React components: Arrow functions with PascalCase names
Variables:
- Standard: camelCase -
chunkBuilder,sessionId,projectPath - Constants: UPPER_SNAKE_CASE -
EMPTY_METRICS,HARD_NOISE_TAGS,CONFIG_GET - React components: PascalCase -
AIChatGroup,TokenUsageDisplay - Unused parameters: Leading underscore -
_event,_arg
Types:
- Interfaces/Types: PascalCase -
ParsedMessage,EnhancedChunk,SessionMetrics - Interfaces: NO "I" prefix (modern convention) -
ToolCall, notIToolCall - Enum members: PascalCase or UPPER_CASE -
TriggerColor,EMPTY_STDOUT
Code Style
Formatting:
- Tool: Prettier 3.8.1
- Config:
/Users/bskim/claude-devtools/.prettierrc.json - Key settings:
- Semi: true (always use semicolons)
- Single quotes: true
- Tab width: 2 spaces
- Trailing comma: es5
- Print width: 100 characters
- Arrow parens: always
- End of line: lf
- Bracket spacing: true
- Bracket same line: false
- Tailwind plugin:
prettier-plugin-tailwindcss(auto-sorts classes)
Linting:
- Tool: ESLint 9.39.2 with typescript-eslint
- Config:
/Users/bskim/claude-devtools/eslint.config.js - Key rules:
- TypeScript strict mode enabled
- Type-aware linting via
projectService - React + Hooks + A11y rules
- Security plugin for AI-generated code
- SonarJS for code quality
- Module boundaries enforced (main/renderer/preload/shared separation)
- Import sorting via
simple-import-sort - No default exports (prefer named exports)
- Explicit function return types (warn)
- Explicit module boundary types (warn)
Import Organization
Order (enforced by simple-import-sort):
- Side effect imports (CSS, styles)
- Node.js builtins (
node:fs,node:path) - React packages (
react,react-dom) - External packages (
@?\\w) - Internal aliases (
@/) - Parent imports (
../) - Same-folder imports (
./) - Type imports (last)
Path Aliases:
@main/*→src/main/*@renderer/*→src/renderer/*@shared/*→src/shared/*@preload/*→src/preload/*
Example:
import React, { useCallback, useMemo } from 'react';
import { ChunkBuilder, ProjectScanner } from '@main/services';
import { useStore } from '@renderer/store';
import { formatDuration } from '@shared/utils/formatters';
import { DisplayItemList } from './DisplayItemList';
import type { EnhancedChunk } from '@main/types';
Import Restrictions:
- No deep relative imports (
../../../) - use path aliases - No circular dependencies (max depth: 3)
- Module boundaries enforced:
- Renderer → renderer + shared only
- Main → main + shared only
- Preload → preload + shared only
- Shared → shared + main (for type re-exports)
Type Conventions
Type Imports:
Use type modifier for type-only imports:
import { type EnhancedChunk, type ParsedMessage } from '@main/types';
Type Exports:
export type { Session, SessionDetail } from './types';
Function Return Types: Always specify for exported functions (warn-level enforcement):
export function buildChunks(messages: ParsedMessage[]): EnhancedChunk[] {
// ...
}
Type Guards: Use discriminated union pattern with type predicates:
export function isParsedRealUserMessage(msg: ParsedMessage): boolean {
return msg.type === 'user' && !msg.isMeta && typeof msg.content === 'string';
}
export function isUserChunk(chunk: Chunk | EnhancedChunk): chunk is UserChunk {
return chunk.type === 'user';
}
Barrel Exports:
Services use barrel exports via index.ts:
// src/main/services/index.ts
export * from './analysis';
export * from './discovery';
export * from './error';
export * from './infrastructure';
export * from './parsing';
// Usage:
import { ChunkBuilder, ProjectScanner } from '@main/services';
Renderer utils/hooks/types do NOT have barrel exports - import directly from files.
Error Handling
Main Process:
try {
const result = await somethingRisky();
return result;
} catch (error) {
console.error('Operation failed:', error);
return safeDefault;
}
Renderer:
// Store error state
set({
sessionsError: error instanceof Error ? error.message : 'Operation failed',
sessionsLoading: false,
});
IPC Handlers:
// Validate parameters
if (!isValidProjectId(projectId)) {
throw new Error(`Invalid project ID: ${projectId}`);
}
// Return safe defaults on error
catch (error) {
logger.error('Handler failed:', error);
return [];
}
Logging
Framework: Custom logger via @shared/utils/logger
Pattern:
import { createLogger } from '@shared/utils/logger';
const logger = createLogger('Service:ChunkBuilder');
logger.info('Building chunks', { messageCount: messages.length });
logger.warn('Missing subagent', { taskId });
logger.error('Failed to parse', error);
Console Usage:
- Main process:
console.log/errorallowed (logging is expected) - Renderer: Avoid console - use logger or store error state
- Tests: Console mocked in setup, errors/warnings cause test failures
Comments
When to Comment:
- Complex business logic (chunk building, semantic step extraction)
- Non-obvious type guards (message classification rules)
- Workarounds or technical debt
- Public API documentation
JSDoc/TSDoc: Used extensively for exported functions and types:
/**
* Encodes an absolute path into Claude Code's directory naming format.
* Replaces all path separators (/ and \) with dashes.
*
* @param absolutePath - The absolute path to encode (e.g., "/Users/username/projectname")
* @returns The encoded directory name (e.g., "-Users-username-projectname")
*/
export function encodePath(absolutePath: string): string {
// ...
}
Section Headers: Used to organize large files:
// =============================================================================
// Chunk Building
// =============================================================================
Function Design
Size: Keep focused and composable. Services orchestrate specialized modules.
Parameters:
- Use explicit types, no
any(except in tests) - Optional parameters last
- Use destructuring for options objects
Return Values:
- Always specify return type for exported functions
- Prefer explicit returns over implicit
- Return safe defaults instead of throwing (where appropriate)
React Components:
// Prefer arrow functions for components
export const AIChatGroup: React.FC<AIChatGroupProps> = ({ aiGroup, userGroup }) => {
// Component implementation
};
Component Props:
interface AIChatGroupProps {
aiGroup: AIGroup;
userGroup?: UserGroup;
onNavigate?: (messageId: string) => void;
}
Module Design
Exports:
- Prefer named exports over default exports
- Barrel exports for service domains
- Direct exports for renderer utils/hooks
File Organization:
// Imports
import { ... } from '...';
// Types/Interfaces
export interface MyInterface { ... }
// Constants
export const MY_CONSTANT = ...;
// Functions
export function myFunction() { ... }
// Classes
export class MyClass { ... }
Services Pattern:
export class ChunkBuilder {
buildChunks(messages: ParsedMessage[]): EnhancedChunk[] {
// Implementation
}
buildSessionDetail(session: Session): SessionDetail {
// Implementation
}
}
React Conventions
Component Structure:
// Imports
import React, { useCallback, useMemo } from 'react';
// Types
interface ComponentProps { ... }
// Component
export const Component: React.FC<ComponentProps> = ({ prop1, prop2 }) => {
// Hooks first
const store = useStore();
const [state, setState] = useState();
// Memoized values
const computed = useMemo(() => ..., [deps]);
// Callbacks
const handleClick = useCallback(() => ..., [deps]);
// Render
return <div>...</div>;
};
Hooks Rules:
- Always use exhaustive deps (error-level enforcement)
- Custom hooks start with
use:useTabUI,useAutoScrollBottom - Keep hooks focused and composable
State Management (Zustand):
// Slice pattern
export interface SessionSlice {
// State
sessions: Session[];
selectedSessionId: string | null;
sessionsLoading: boolean;
sessionsError: string | null;
// Actions
fetchSessions: (projectId: string) => Promise<void>;
selectSession: (id: string) => void;
}
Tailwind CSS
Use theme-aware classes:
<div className="bg-surface text-text border-border">
<div className="bg-surface-raised text-text-secondary">
Auto-sorted by Prettier plugin: Classes automatically ordered by Prettier's Tailwind plugin.
Custom CSS variables:
Defined in src/renderer/index.css - use via Tailwind classes:
--color-surface→bg-surface--color-text→text-text--color-border→border-border
Security
Enabled Rules:
security/detect-eval-with-expression: errorsecurity/detect-child-process: warn- File system access: allowed (desktop app requirement)
- Dynamic patterns: allowed (intentional in this app)
Parameter Mutation:
Prevented via no-param-reassign except for:
draft(Immer patterns)acc(reduce accumulators)state(Zustand)
Convention analysis: 2026-02-12