Electron λ°μ€ν¬ν± μ±μΌλ‘ Claude CLIλ₯Ό ν€λλ¦¬μ€ λͺ¨λλ‘ μ€ννκ³ , stream-json νμμ μ€μκ° μΆλ ₯μ μΉ UIλ‘ νμΈν μ μλ λꡬμ λλ€.
μ΄ νλ‘μ νΈλ λͺ¨λ Έλ ν¬ κ΅¬μ‘°λ‘ κ΅¬μ±λμ΄ μμ΅λλ€:
- GUI μ± (root): Electron κΈ°λ° λ°μ€ν¬ν± μ ν리μΌμ΄μ
- @context-action/code-api: Claude CLI ν΄λΌμ΄μΈνΈ λΌμ΄λΈλ¬λ¦¬ (μ¬μ¬μ© κ°λ₯)
- β λ³λ ¬ μ€ν κ΄λ¦¬: μ¬λ¬ Claude CLI νλ‘μΈμ€ λμ μ€ν λ° λͺ¨λν°λ§
- β μ€μκ° μ€νΈλ¦¬λ°: Stream JSON νμ± λ° μ€μκ° μ΄λ²€νΈ μ²λ¦¬
- β μ€ν μ΄λ ₯ μΆμ : μΈμ ID κΈ°λ° λͺ¨λ μ€ν λ΄μ κ΄λ¦¬
- β νλ‘μΈμ€ μ μ΄: μ€ν μ€ νλ‘μΈμ€ μ’ λ£ λ° μ 리
- β
μΈλ°ν κΆν μ μ΄: settings.json κΈ°λ° μμ ν μλν (
--dangerously-skip-permissionsλΆνμ) - β MCP μλ² μ ν: μμ λ³ μ΅μ νλ MCP μλ² μ€μ (λΆμ/κ°λ°/μ΅μ)
- β μΈμ κ΄λ¦¬: νλ‘μ νΈλ³ μΈμ μ‘°ν λ° μ΄μ΄κ°κΈ° μ§μ
- β MCP μ€μ νΈμ§: νλ‘μ νΈλ³ MCP μλ² μ€μ κ΄λ¦¬
- β μμ‘΄μ± λΆμ: μμ μ νμν νμΌ λ° λ¬Έμ μμ‘΄μ± μ¬μ μ μ
- β 컨ν μ€νΈ λ°°μ : Execute μ μλ 컨ν μ€νΈ ꡬμ±
- β μμ μμ ν λΉ: Area μ€μ μΌλ‘ λΆνμν 컨ν μ€νΈ μ°¨λ¨
- β μ±κ³΅ κΈ°μ€ κ²μ¦: 체ν¬λ¦¬μ€νΈ κΈ°λ° κ²°κ³Ό κ²μ¦
- β 리뷰 μμ€ν : λ¦¬λ·°μ΄ μ§μ λ° μ°μΆλ¬Ό κ²ν
- β λͺ¨λν μν€ν μ²: μ¬μ¬μ© κ°λ₯ν λ 립 λͺ¨λ μ€κ³
- β μμ ν νμ μμ μ±: TypeScriptλ‘ μμ±λ νμ μΈμ΄νν μ½λ
- β Electron IPC ν΅μ : Main/Renderer νλ‘μΈμ€ κ° μμ ν ν΅μ
# μ€μΉ
npm install
# κ°λ° λͺ¨λ μ€ν
npm start
# macOS ν¨ν€μ§ (ν
μ€νΈμ©)
npm run package:mac
# macOS λ°°ν¬μ© λΉλ (DMG + ZIP νμΌ μμ±)
npm run build:mac
# λλ
npm run make# 1. DMG νμΌ μ΄κΈ°
open "out/make/Claude Code Spec.dmg"
# 2. μ±μ Applications ν΄λλ‘ λλκ·Έ
# 3. 보μ μ€μ
xattr -cr "/Applications/Claude Code Spec.app"
# 4. μ€ν
open -a "Claude Code Spec"μμΈ μ€μΉ κ°μ΄λ: INSTALL.md | λΉλ κ°μ΄λ: BUILD_GUIDE.md
νλ‘μ νΈλ μ΄λ―Έ κΆν μ€μ κ³Ό MCP μλ²κ° ꡬμ±λμ΄ μμ΅λλ€:
- κΆν μ€μ :
.claude/settings.json(ν 곡μ ) - MCP μλ²:
.claude/.mcp-*.json(μ©λλ³ μ€μ )
μμΈ κ°μ΄λ: SETUP.md
- νλ‘μ νΈ λλ ν 리 μ ν: Browse λ²νΌ λλ μ§μ μ λ ₯
- 쿼리 μ λ ₯: Claudeμκ² μμ²ν μμ μ λ ₯
- Execute ν΄λ¦: Claude CLIκ° μ€νλκ³ μ€μκ° μλ΅ νμ
μ€ν λͺ λ Ή μμ:
claude -p "μ½λ λΆμ" \
--output-format stream-json \
--mcp-config .claude/.mcp-dev.json \
--strict-mcp-configνλ‘μ νΈλ .claude/settings.jsonμΌλ‘ μμ νκ² μλνλ©λλ€:
{
"permissions": {
"allow": [
"Read(./src/**)",
"Write(./src/**)",
"Bash(npm run test)"
],
"deny": [
"Read(./.env)",
"Bash(rm:*)"
]
}
}μ₯μ :
- β
--dangerously-skip-permissionsλΆνμ - β λ―Όκ°ν νμΌ λ³΄νΈ
- β ν μ μ± κ³΅μ κ°λ₯
Claude CLIμμ ν΅μ μ λ΄λΉνλ ν΅μ¬ λͺ¨λλ€μ λ 립μ μΈ λΌμ΄λΈλ¬λ¦¬λ‘ λΆλ¦¬λμ΄ μμ΅λλ€.
μμΈν μ¬μ©λ²μ packages/code-api/README.mdλ₯Ό μ°Έκ³ νμΈμ.
import {
// ν΄λΌμ΄μΈνΈ
ClaudeClient,
ProcessManager,
SessionManager,
// νμ
StreamParser,
// νμ
λ° νμ
κ°λ
type StreamEvent,
type SystemInitEvent,
type AssistantEvent,
isSystemInitEvent,
isAssistantEvent,
extractTextFromMessage,
// 쿼리 API (ꡬ쑰νλ μΆλ ₯)
ClaudeQueryAPI,
// μ€ν€λ§ λΉλ
buildSchemaPrompt,
zodSchemaToPrompt,
validateWithZod,
} from '@context-action/code-api';import { ClaudeClient } from '@context-action/code-api';
const client = new ClaudeClient({
cwd: '/path/to/project',
sessionId: 'previous-session-id', // optional
onStream: (event) => console.log(event),
onError: (error) => console.error(error),
onClose: (code) => console.log('Done:', code),
});
client.execute('List files in this directory');import { ClaudeQueryAPI } from '@context-action/code-api';
import { z } from 'zod';
const api = new ClaudeQueryAPI();
// Zod μ€ν€λ§λ‘ νμ
μμ ν 쿼리
const schema = z.object({
file: z.string(),
linesOfCode: z.number().min(0),
language: z.enum(['typescript', 'javascript', 'python']),
});
const result = await api.queryWithZod(
'/path/to/project',
'Analyze src/main.ts',
schema
);
console.log(result.data); // νμ
μμ : { file: string, linesOfCode: number, ... }βββββββββββββββ βββββββββββββββ
β Renderer β β Main β
β (React) β β (Node.js) β
βββββββββββββββ βββββββββββββββ
β β
β claude:execute β
ββββββββββββββββββββββββββββββββ>β
β β
β βββββββΌββββββ
β β Claude β
β β Client β
β βββββββ¬ββββββ
β β
β claude:stream (events) β
β<ββββββββββββββββββββββββββββββββ
β β
β claude:complete β
β<ββββββββββββββββββββββββββββββββ
1. User Input (Query)
β
2. ClaudeClient.execute()
β
3. spawn('claude', ['-p', query, '--output-format', 'stream-json', '--verbose'])
β
4. stdout (line-by-line JSON)
β
5. StreamParser.processChunk()
β
6. Parsed StreamEvent
β
7. IPC: claude:stream
β
8. React UI Update
Claude CLIκ° μΆλ ₯νλ μ£Όμ μ΄λ²€νΈ:
{
type: 'system',
subtype: 'init',
session_id: string,
cwd: string,
tools: string[],
model: string,
// ...
}{
type: 'assistant',
message: {
content: Array<TextContent | ToolUseContent>,
usage: { input_tokens, output_tokens },
// ...
}
}{
type: 'result',
subtype: 'success' | 'error',
result: string,
duration_ms: number,
total_cost_usd: number,
// ...
}- Electron: λ°μ€ν¬ν± μ± νλ μμν¬
- React 19: UI λΌμ΄λΈλ¬λ¦¬
- TypeScript: νμ μμ μ±
- Vite: λΉλ λꡬ
- Node.js child_process: Claude CLI μ€ν
claude-code-spec/
βββ packages/
β βββ code-api/ # π¦ Claude CLI ν΄λΌμ΄μΈνΈ λΌμ΄λΈλ¬λ¦¬
β βββ src/
β β βββ client/ # ClaudeClient
β β βββ parser/ # StreamParser, types
β β βββ process/ # ProcessManager
β β βββ session/ # SessionManager
β β βββ query/ # ClaudeQueryAPI
β β βββ schema/ # Schema builders (Zod, JSON)
β β βββ errors/ # Error classes
β β βββ index.ts # Public API
β βββ examples/ # μ¬μ© μμ
β βββ tests/ # ν
μ€νΈ
β βββ dist/ # λΉλ μΆλ ₯ (CJS/ESM/DTS)
β
βββ src/ # π₯οΈ GUI μ± (Electron + React)
β βββ lib/
β β βββ taskParser.ts # Task λ§ν¬λ€μ΄ νμ±
β β βββ agentParser.ts # Agent μ μ νμ±
β β βββ ...
β βββ services/
β β βββ appSettings.ts # μ± μ€μ κ΄λ¦¬
β β βββ AppLogger.ts # λ‘κΉ
β β βββ ...
β βββ ipc/
β β βββ IPCRouter.ts # IPC λΌμ°ν
β β βββ handlers/ # IPC νΈλ€λ¬
β β βββ claudeHandlers.ts
β β βββ taskHandlers.ts
β β βββ ...
β βββ preload/
β β βββ apis/ # Preload API λͺ¨λ
β β βββ claude.ts
β β βββ task.ts
β β βββ ...
β βββ pages/ # React νμ΄μ§
β β βββ ExecutionsPage.tsx
β β βββ TasksPage.tsx
β β βββ ...
β βββ components/ # React μ»΄ν¬λνΈ
β βββ main.ts # Electron Main Process
β βββ preload.ts # IPC Bridge
β βββ App.tsx # React App
β
βββ docs/ # λ¬Έμ
βββ package.json # Workspace 루νΈ
βββ README.md # μ΄ νμΌ
Tasksλ Claude CLI μ€ν μ νμν μμ‘΄μ±, 컨ν μ€νΈ, μμ μμμ μ¬μ μ μ μνμ¬ ν¨μ¨μ μΈ Executeλ₯Ό κ°λ₯νκ² ν©λλ€.
1. Task μ μ (μμ‘΄μ± λΆμ)
ββ References: νμν λͺ¨λ νμΌ λͺ
μ
ββ Area: μμ
λ²μ μ ν (컨ν
μ€νΈ μ°¨λ¨)
ββ Success Criteria: κ²μ¦ κ°λ₯ν μλ£ μ‘°κ±΄
2. Execute μ€ν
ββ Task μ ν
ββ μλ 컨ν
μ€νΈ κ΅¬μ± (References κΈ°λ°)
ββ λ²μ μ ν (Area κΈ°λ°)
ββ Claude CLI μ€ν
3. κ²°κ³Ό κ²μ¦
ββ Success Criteria νμΈ
---
id: task-001
title: μ¬μ©μ μΈμ¦ API ꡬν
area: src/auth # 컨ν
μ€νΈ μ ν λ²μ
assigned_agent: claude-sonnet-4
reviewer: claude-opus-4
status: in_progress
---
## References
# Execute μ μλμΌλ‘ 컨ν
μ€νΈμ ν¬ν¨λ¨
- /docs/api-spec.md
- /src/types/user.ts
- /src/types/auth.ts
- /src/utils/jwt.ts
- /tests/auth.test.ts
## Success Criteria
- [ ] JWT ν ν° μμ± λ° κ²μ¦ ꡬν
- [ ] λ¨μ ν
μ€νΈ 컀λ²λ¦¬μ§ 85% μ΄μ
- [ ] API μλ΅ μκ° < 200ms
## Description
μμ
μμΈ μ€λͺ
λ° κ΅¬ν μꡬμ¬ν...| νλͺ© | μΌλ° Execute | Task κΈ°λ° Execute |
|---|---|---|
| 컨ν μ€νΈ | μλ μ§μ νμ | μλ κ΅¬μ± (References) |
| μμ λ²μ | λΆλͺ ν | Areaλ‘ λͺ νν μ ν |
| μμ‘΄μ± | λ§€λ² νμ | μ¬μ λΆμλ¨ |
| μ¬μ€ν | λ°λ³΅ μ€μ | Task μ¬μ¬μ© |
| κ²μ¦ | μλ νμΈ | Success Criteria μλ |
Area μ€μ μΌλ‘ λΆνμν νμΌ μ°¨λ¨:
area: src/auth # src/auth μΈλΆ νμΌ μλ μ°¨λ¨ν¨κ³Ό:
- ν ν° μ μ½ (νμν νμΌλ§ λ‘λ)
- λΉ λ₯Έ μ€ν (컨ν μ€νΈ ν¬κΈ° κ°μ)
- μ€μ λ°©μ§ (μμ λ²μ λͺ νν)
# μμ‘΄μ± μ€μΉ
npm install
# κ°λ° λͺ¨λ μ€ν (Vite dev server + Electron)
npm start
# λλ²κ·Έ λͺ¨λ μ€ν (DEBUG=true νκ²½λ³μ)
npm run start:debugnpm startλ Electron Forgeλ₯Ό ν΅ν΄ Vite dev serverμ Electron νλ‘μΈμ€λ₯Ό λμμ μμν©λλ€. Viteκ° HMRμ μ 곡νλ―λ‘ React μ½λ μμ μ μλμΌλ‘ λ°μλ©λλ€.
# macOS ν¨ν€μ§ (ν
μ€νΈμ©)
npm run package:mac
# macOS λ°°ν¬μ© λΉλ (DMG + ZIP)
npm run build:mac
# lint
npm run lint
npm run lint:fix
# ν
μ€νΈ
npm test
npm run test:ui
npm run test:coverageκ°λ°/λΆμ μ μ©λμ λ§λ MCP μ€μ μ μ νν©λλ€:
| μ€μ νμΌ | μ©λ | ν¬ν¨ μλ² |
|---|---|---|
.claude/.mcp-dev.json |
κ°λ° | serena + context7 |
.claude/.mcp-analysis.json |
λΆμ | serena + sequential-thinking |
.claude/.mcp-e2e.json |
E2E ν μ€νΈ | μ 체 |
.claude/.mcp-ui.json |
UI κ°λ° | UI κ΄λ ¨ |
.claude/.mcp-empty.json |
μ΅μ | μμ |
CLIμμ μ§μ μ¬μ©:
claude --mcp-config .claude/.mcp-dev.json --strict-mcp-config -p "λΆμ μμ²"cd packages/code-api
# λΌμ΄λΈλ¬λ¦¬ λΉλ
npm run build
# ν
μ€νΈ μ€ν
npm test
# μμ μ€ν
npm run example:query
npm run example:json# npm linkλ‘ λ‘컬 κ°λ°
cd packages/code-api
npm link
cd your-other-project
npm link @context-action/code-api// λ€λ₯Έ νλ‘μ νΈμμ μ¬μ©
import { ClaudeClient, ProcessManager } from '@context-action/code-api';
const client = new ClaudeClient({ ... });src-old/λ μ΄μ μν€ν
μ²μ μ 체 μμ€μ½λλ₯Ό 보κ΄νλ μμΉ΄μ΄λΈ λλ ν 리μ
λλ€. λκ·λͺ¨ 리ν©ν λ§ κ³Όμ μμ κΈ°μ‘΄ μ½λλ₯Ό μ°Έμ‘°μ©μΌλ‘ 보쑴ν΄λ κ²μΌλ‘, λΉλλ μ€νμλ ν¬ν¨λμ§ μμ΅λλ€.
κΈ°μ‘΄ μν€ν μ²μμ μ κ±°λ λͺ¨λ:
- Agent/Task/Skill κ΄λ¦¬: AgentLoader, TaskLifecycleManager, SkillRepositoryManager λ±
- LangGraph μμ§: LangGraphEngine, WorkflowEngine, κ·Έλν μκ°ν
- CentralDatabase: μ€μ λ°μ΄ν°λ² μ΄μ€ λ° μΏΌλ¦¬ μμ€ν
- μ μ© νμ΄μ§: AgentsPage, TasksPage, SkillsPage, WorkflowPage, BookmarksPage λ± ~20κ° νμ΄μ§
- κΈ°ν μλΉμ€: AppLogger, SessionAnalyzer, ExecutionQueue, AgentTracker λ±
μλ‘ μΆκ°λ λͺ¨λ:
- λ©ν° CLI μ§μ: Claude/Codex/Gemini ν΅ν© (
ToolContext,sessionProvider,MultiCliExecutionService) - Tool Registry: λꡬ κ²μ λ° μΈλ²€ν 리 (
ToolRegistry,OptionInventoryManager) - μΈμ
λΆλ₯κΈ°: λ‘κ·Έ μνΈλ¦¬ λΆλ₯ λ° λ λλ§ (
sessionClassifier,ClassifiedLogEntry) - μΈμ
νλ‘λ°μ΄λ: CLIλ³ μΈμ
λ‘λ (
claudeSessions,codexSessions,geminiSessions)
| νμ΄μ§ | νμΌ | μ€λͺ |
|---|---|---|
| Execute | ExecutePage.tsx |
CLI μ€ν λ° μ€νΈλ¦¬λ° |
| Sessions | SessionsPage.tsx |
μΈμ λ‘κ·Έ μ‘°ν λ° λΆλ₯ λ·°μ΄ |
| MCP Configs | McpConfigsPage.tsx |
MCP μλ² μ€μ κ΄λ¦¬ |
| Skills | SkillsPage.tsx |
CLI λ²μ νμΈ/μ λ°μ΄νΈ, μ€μΉλ μ€ν¬ νμ±ν κ΄λ¦¬ |
| Ref Hooks | ReferenceHooksPage.tsx |
MoAI/Ralph hook λ νΌλ°μ€ μ‘°ν λ° λ―Έλ¦¬λ³΄κΈ° |
| Ref Styles | ReferenceOutputStylesPage.tsx |
MoAI/Ralph output style/theme λ νΌλ°μ€ μ‘°ν |
| Ref Skills | ReferenceSkillsPage.tsx |
MoAI/Ralph SKILL.md λ νΌλ°μ€ μ‘°ν |
| Settings | SettingsPage.tsx |
μ± μ€μ |
src-old/μ μ½λλ νμ¬ μν€ν μ²μ νΈνλμ§ μμ΅λλ€- import κ²½λ‘, νμ μ μ, IPC μ±λμ΄ λͺ¨λ λ³κ²½λμμ΅λλ€
- κΈ°λ₯ 볡μμ΄ νμν κ²½μ° νμ¬ μν€ν μ²μ λ§κ² μ¬μμ±ν΄μΌ ν©λλ€
- 리ν©ν λ§μ΄ μλ£λλ©΄
src-old/λ μμ ν μ μμ΅λλ€
- λΉλ λ° μ€μΉ κ°μ΄λ - macOS μ± λΉλ λ° λ°°ν¬ λ°©λ²
- μ€μ κ°μ΄λ - κΆν λ° MCP μλ² μ€μ λ°©λ²
- MCP μ€μ κ°μ΄λ - μμ λ³ MCP μλ² μ ν
- MCP Tools Reference - μ 체 λꡬ λͺ©λ‘
- μ€ν μ λ΅ - μ΅μ νλ μ€ν ν¨ν΄
- κΆν μ€μ - μΈλ°ν κΆν μ μ΄
- νλ‘μ νΈ λΉμ - νλ‘μ νΈ λͺ©ν λ° λΉμ
MIT