oh-my-ag 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.agent/skills/_shared/api-contracts/README.md +56 -0
  2. package/.agent/skills/_shared/api-contracts/template.md +88 -0
  3. package/.agent/skills/_shared/clarification-protocol.md +217 -0
  4. package/.agent/skills/_shared/common-checklist.md +31 -0
  5. package/.agent/skills/_shared/context-budget.md +118 -0
  6. package/.agent/skills/_shared/context-loading.md +105 -0
  7. package/.agent/skills/_shared/difficulty-guide.md +55 -0
  8. package/.agent/skills/_shared/lessons-learned.md +113 -0
  9. package/.agent/skills/_shared/memory-protocol.md +79 -0
  10. package/.agent/skills/_shared/reasoning-templates.md +161 -0
  11. package/.agent/skills/_shared/skill-routing.md +80 -0
  12. package/.agent/skills/_shared/verify.sh +252 -0
  13. package/.agent/skills/backend-agent/SKILL.md +47 -0
  14. package/.agent/skills/backend-agent/resources/api-template.py +326 -0
  15. package/.agent/skills/backend-agent/resources/checklist.md +36 -0
  16. package/.agent/skills/backend-agent/resources/error-playbook.md +98 -0
  17. package/.agent/skills/backend-agent/resources/examples.md +85 -0
  18. package/.agent/skills/backend-agent/resources/execution-protocol.md +45 -0
  19. package/.agent/skills/backend-agent/resources/snippets.md +197 -0
  20. package/.agent/skills/backend-agent/resources/tech-stack.md +39 -0
  21. package/.agent/skills/commit/SKILL.md +121 -0
  22. package/.agent/skills/commit/config/commit-config.yaml +55 -0
  23. package/.agent/skills/commit/resources/conventional-commits.md +166 -0
  24. package/.agent/skills/debug-agent/SKILL.md +51 -0
  25. package/.agent/skills/debug-agent/resources/bug-report-template.md +332 -0
  26. package/.agent/skills/debug-agent/resources/checklist.md +30 -0
  27. package/.agent/skills/debug-agent/resources/common-patterns.md +734 -0
  28. package/.agent/skills/debug-agent/resources/debugging-checklist.md +362 -0
  29. package/.agent/skills/debug-agent/resources/error-playbook.md +94 -0
  30. package/.agent/skills/debug-agent/resources/examples.md +87 -0
  31. package/.agent/skills/debug-agent/resources/execution-protocol.md +51 -0
  32. package/.agent/skills/frontend-agent/SKILL.md +48 -0
  33. package/.agent/skills/frontend-agent/resources/checklist.md +38 -0
  34. package/.agent/skills/frontend-agent/resources/component-template.tsx +92 -0
  35. package/.agent/skills/frontend-agent/resources/error-playbook.md +108 -0
  36. package/.agent/skills/frontend-agent/resources/examples.md +77 -0
  37. package/.agent/skills/frontend-agent/resources/execution-protocol.md +49 -0
  38. package/.agent/skills/frontend-agent/resources/snippets.md +205 -0
  39. package/.agent/skills/frontend-agent/resources/tailwind-rules.md +343 -0
  40. package/.agent/skills/frontend-agent/resources/tech-stack.md +36 -0
  41. package/.agent/skills/mobile-agent/SKILL.md +46 -0
  42. package/.agent/skills/mobile-agent/resources/checklist.md +35 -0
  43. package/.agent/skills/mobile-agent/resources/error-playbook.md +106 -0
  44. package/.agent/skills/mobile-agent/resources/examples.md +79 -0
  45. package/.agent/skills/mobile-agent/resources/execution-protocol.md +49 -0
  46. package/.agent/skills/mobile-agent/resources/screen-template.dart +298 -0
  47. package/.agent/skills/mobile-agent/resources/snippets.md +235 -0
  48. package/.agent/skills/mobile-agent/resources/tech-stack.md +45 -0
  49. package/.agent/skills/orchestrator/SKILL.md +99 -0
  50. package/.agent/skills/orchestrator/config/cli-config.yaml +78 -0
  51. package/.agent/skills/orchestrator/resources/memory-schema.md +212 -0
  52. package/.agent/skills/orchestrator/resources/subagent-prompt-template.md +153 -0
  53. package/.agent/skills/orchestrator/scripts/parallel-run.sh +330 -0
  54. package/.agent/skills/orchestrator/scripts/spawn-agent.sh +263 -0
  55. package/.agent/skills/orchestrator/templates/backend-task.md +18 -0
  56. package/.agent/skills/orchestrator/templates/debug-task.md +16 -0
  57. package/.agent/skills/orchestrator/templates/frontend-task.md +17 -0
  58. package/.agent/skills/orchestrator/templates/mobile-task.md +17 -0
  59. package/.agent/skills/orchestrator/templates/qa-task.md +16 -0
  60. package/.agent/skills/orchestrator/templates/tasks-example.yaml +15 -0
  61. package/.agent/skills/pm-agent/SKILL.md +47 -0
  62. package/.agent/skills/pm-agent/resources/error-playbook.md +75 -0
  63. package/.agent/skills/pm-agent/resources/examples.md +121 -0
  64. package/.agent/skills/pm-agent/resources/execution-protocol.md +46 -0
  65. package/.agent/skills/pm-agent/resources/task-template.json +57 -0
  66. package/.agent/skills/qa-agent/SKILL.md +43 -0
  67. package/.agent/skills/qa-agent/resources/checklist.md +294 -0
  68. package/.agent/skills/qa-agent/resources/error-playbook.md +95 -0
  69. package/.agent/skills/qa-agent/resources/examples.md +100 -0
  70. package/.agent/skills/qa-agent/resources/execution-protocol.md +50 -0
  71. package/.agent/skills/qa-agent/resources/self-check.md +27 -0
  72. package/.agent/skills/workflow-guide/SKILL.md +57 -0
  73. package/.agent/skills/workflow-guide/resources/examples.md +68 -0
  74. package/README.ko.md +459 -0
  75. package/README.md +563 -0
  76. package/bin/cli.js +205 -0
  77. package/package.json +75 -0
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: backend-agent
3
+ description: Backend specialist for APIs, databases, authentication, and server-side logic using FastAPI, Node.js, or other frameworks
4
+ ---
5
+
6
+ # Backend Agent - API & Server Specialist
7
+
8
+ ## When to use
9
+ - Building REST APIs or GraphQL endpoints
10
+ - Database design and migrations
11
+ - Authentication and authorization
12
+ - Server-side business logic
13
+ - Background jobs and queues
14
+
15
+ ## When NOT to use
16
+ - Frontend UI -> use Frontend Agent
17
+ - Mobile-specific code -> use Mobile Agent
18
+
19
+ ## Core Rules
20
+ 1. Clean architecture: router -> service -> repository -> models
21
+ 2. No business logic in route handlers
22
+ 3. All inputs validated with Pydantic/Zod
23
+ 4. Parameterized queries only (never string interpolation)
24
+ 5. JWT + bcrypt for auth; rate limit auth endpoints
25
+ 6. Async/await consistently; type hints on all signatures
26
+
27
+ ## How to Execute
28
+ Follow `resources/execution-protocol.md` step by step.
29
+ See `resources/examples.md` for input/output examples.
30
+ Before submitting, run `resources/checklist.md`.
31
+
32
+ ## Serena Memory (CLI Mode)
33
+ See `../_shared/serena-memory-protocol.md`.
34
+
35
+ ## References
36
+ - Execution steps: `resources/execution-protocol.md`
37
+ - Code examples: `resources/examples.md`
38
+ - Code snippets: `resources/snippets.md`
39
+ - Checklist: `resources/checklist.md`
40
+ - Error recovery: `resources/error-playbook.md`
41
+ - Tech stack: `resources/tech-stack.md`
42
+ - API template: `resources/api-template.py`
43
+ - Context loading: `../_shared/context-loading.md`
44
+ - Reasoning templates: `../_shared/reasoning-templates.md`
45
+ - Clarification: `../_shared/clarification-protocol.md`
46
+ - Context budget: `../_shared/context-budget.md`
47
+ - Lessons learned: `../_shared/lessons-learned.md`
@@ -0,0 +1,326 @@
1
+ """
2
+ API Endpoint Template for Backend Agent
3
+
4
+ This template demonstrates best practices for FastAPI endpoints.
5
+ """
6
+
7
+ from fastapi import APIRouter, Depends, HTTPException, status, Query
8
+ from sqlalchemy.orm import Session
9
+ from typing import Annotated, List
10
+ from uuid import UUID
11
+
12
+ from app.database import get_db
13
+ from app.auth import get_current_user
14
+ from app.models import User, Resource
15
+ from app.schemas import ResourceCreate, ResourceUpdate, ResourceResponse
16
+ from app.services import ResourceService
17
+
18
+ # Type aliases for cleaner code
19
+ DatabaseDep = Annotated[Session, Depends(get_db)]
20
+ UserDep = Annotated[User, Depends(get_current_user)]
21
+
22
+ # Router setup
23
+ router = APIRouter(
24
+ prefix="/api/resources",
25
+ tags=["resources"],
26
+ responses={404: {"description": "Not found"}},
27
+ )
28
+
29
+
30
+ # List endpoint with pagination and filtering
31
+ @router.get(
32
+ "/",
33
+ response_model=List[ResourceResponse],
34
+ summary="List resources",
35
+ description="Retrieve a paginated list of resources with optional filtering"
36
+ )
37
+ async def list_resources(
38
+ db: DatabaseDep,
39
+ current_user: UserDep,
40
+ skip: int = Query(0, ge=0, description="Number of records to skip"),
41
+ limit: int = Query(100, ge=1, le=1000, description="Max records to return"),
42
+ search: str | None = Query(None, description="Search query"),
43
+ status: str | None = Query(None, description="Filter by status"),
44
+ ):
45
+ """
46
+ List resources with pagination.
47
+
48
+ - **skip**: Offset for pagination
49
+ - **limit**: Maximum number of records
50
+ - **search**: Optional search term
51
+ - **status**: Optional status filter
52
+ """
53
+ service = ResourceService(db)
54
+ resources = service.list_resources(
55
+ user_id=current_user.id,
56
+ skip=skip,
57
+ limit=limit,
58
+ search=search,
59
+ status=status,
60
+ )
61
+ return resources
62
+
63
+
64
+ # Get single resource
65
+ @router.get(
66
+ "/{resource_id}",
67
+ response_model=ResourceResponse,
68
+ summary="Get resource",
69
+ responses={
70
+ 200: {"description": "Resource found"},
71
+ 404: {"description": "Resource not found"},
72
+ 403: {"description": "Access denied"}
73
+ }
74
+ )
75
+ async def get_resource(
76
+ resource_id: UUID,
77
+ db: DatabaseDep,
78
+ current_user: UserDep,
79
+ ):
80
+ """
81
+ Get a specific resource by ID.
82
+
83
+ Raises:
84
+ 404: Resource not found
85
+ 403: User doesn't own this resource
86
+ """
87
+ service = ResourceService(db)
88
+ resource = service.get_resource(resource_id)
89
+
90
+ if not resource:
91
+ raise HTTPException(
92
+ status_code=status.HTTP_404_NOT_FOUND,
93
+ detail=f"Resource {resource_id} not found"
94
+ )
95
+
96
+ # Authorization check
97
+ if resource.user_id != current_user.id:
98
+ raise HTTPException(
99
+ status_code=status.HTTP_403_FORBIDDEN,
100
+ detail="Access denied"
101
+ )
102
+
103
+ return resource
104
+
105
+
106
+ # Create resource
107
+ @router.post(
108
+ "/",
109
+ response_model=ResourceResponse,
110
+ status_code=status.HTTP_201_CREATED,
111
+ summary="Create resource",
112
+ )
113
+ async def create_resource(
114
+ resource_data: ResourceCreate,
115
+ db: DatabaseDep,
116
+ current_user: UserDep,
117
+ ):
118
+ """
119
+ Create a new resource.
120
+
121
+ - **name**: Resource name (required)
122
+ - **description**: Optional description
123
+ - **status**: Initial status (default: active)
124
+ """
125
+ service = ResourceService(db)
126
+
127
+ try:
128
+ resource = service.create_resource(
129
+ user_id=current_user.id,
130
+ data=resource_data
131
+ )
132
+ return resource
133
+ except ValueError as e:
134
+ raise HTTPException(
135
+ status_code=status.HTTP_400_BAD_REQUEST,
136
+ detail=str(e)
137
+ )
138
+
139
+
140
+ # Update resource
141
+ @router.patch(
142
+ "/{resource_id}",
143
+ response_model=ResourceResponse,
144
+ summary="Update resource",
145
+ )
146
+ async def update_resource(
147
+ resource_id: UUID,
148
+ resource_data: ResourceUpdate,
149
+ db: DatabaseDep,
150
+ current_user: UserDep,
151
+ ):
152
+ """
153
+ Update an existing resource (partial update).
154
+
155
+ Only provided fields will be updated.
156
+ """
157
+ service = ResourceService(db)
158
+ resource = service.get_resource(resource_id)
159
+
160
+ if not resource:
161
+ raise HTTPException(
162
+ status_code=status.HTTP_404_NOT_FOUND,
163
+ detail=f"Resource {resource_id} not found"
164
+ )
165
+
166
+ if resource.user_id != current_user.id:
167
+ raise HTTPException(
168
+ status_code=status.HTTP_403_FORBIDDEN,
169
+ detail="Access denied"
170
+ )
171
+
172
+ try:
173
+ updated_resource = service.update_resource(resource, resource_data)
174
+ return updated_resource
175
+ except ValueError as e:
176
+ raise HTTPException(
177
+ status_code=status.HTTP_400_BAD_REQUEST,
178
+ detail=str(e)
179
+ )
180
+
181
+
182
+ # Delete resource
183
+ @router.delete(
184
+ "/{resource_id}",
185
+ status_code=status.HTTP_204_NO_CONTENT,
186
+ summary="Delete resource",
187
+ )
188
+ async def delete_resource(
189
+ resource_id: UUID,
190
+ db: DatabaseDep,
191
+ current_user: UserDep,
192
+ hard: bool = Query(False, description="Perform hard delete instead of soft delete"),
193
+ ):
194
+ """
195
+ Delete a resource.
196
+
197
+ - **hard=false**: Soft delete (default) - sets deleted_at timestamp
198
+ - **hard=true**: Hard delete - permanently removes from database
199
+ """
200
+ service = ResourceService(db)
201
+ resource = service.get_resource(resource_id)
202
+
203
+ if not resource:
204
+ raise HTTPException(
205
+ status_code=status.HTTP_404_NOT_FOUND,
206
+ detail=f"Resource {resource_id} not found"
207
+ )
208
+
209
+ if resource.user_id != current_user.id:
210
+ raise HTTPException(
211
+ status_code=status.HTTP_403_FORBIDDEN,
212
+ detail="Access denied"
213
+ )
214
+
215
+ service.delete_resource(resource, hard=hard)
216
+ # 204 No Content - no response body
217
+
218
+
219
+ # Bulk operations example
220
+ @router.post(
221
+ "/bulk",
222
+ response_model=List[ResourceResponse],
223
+ status_code=status.HTTP_201_CREATED,
224
+ summary="Bulk create resources",
225
+ )
226
+ async def bulk_create_resources(
227
+ resources_data: List[ResourceCreate],
228
+ db: DatabaseDep,
229
+ current_user: UserDep,
230
+ ):
231
+ """
232
+ Create multiple resources in one request.
233
+
234
+ Useful for batch imports.
235
+ """
236
+ if len(resources_data) > 100:
237
+ raise HTTPException(
238
+ status_code=status.HTTP_400_BAD_REQUEST,
239
+ detail="Maximum 100 resources per bulk operation"
240
+ )
241
+
242
+ service = ResourceService(db)
243
+ created_resources = []
244
+
245
+ try:
246
+ for data in resources_data:
247
+ resource = service.create_resource(
248
+ user_id=current_user.id,
249
+ data=data
250
+ )
251
+ created_resources.append(resource)
252
+
253
+ return created_resources
254
+ except ValueError as e:
255
+ db.rollback() # Rollback on error
256
+ raise HTTPException(
257
+ status_code=status.HTTP_400_BAD_REQUEST,
258
+ detail=str(e)
259
+ )
260
+
261
+
262
+ # Service class template (separate file: app/services/resource_service.py)
263
+ """
264
+ from sqlalchemy.orm import Session
265
+ from app.models import Resource
266
+ from app.schemas import ResourceCreate, ResourceUpdate
267
+ from datetime import datetime
268
+ from uuid import UUID
269
+
270
+ class ResourceService:
271
+ def __init__(self, db: Session):
272
+ self.db = db
273
+
274
+ def list_resources(
275
+ self,
276
+ user_id: UUID,
277
+ skip: int = 0,
278
+ limit: int = 100,
279
+ search: str | None = None,
280
+ status: str | None = None,
281
+ ):
282
+ query = self.db.query(Resource).filter(
283
+ Resource.user_id == user_id,
284
+ Resource.deleted_at.is_(None)
285
+ )
286
+
287
+ if search:
288
+ query = query.filter(Resource.name.ilike(f"%{search}%"))
289
+
290
+ if status:
291
+ query = query.filter(Resource.status == status)
292
+
293
+ return query.offset(skip).limit(limit).all()
294
+
295
+ def get_resource(self, resource_id: UUID) -> Resource | None:
296
+ return self.db.query(Resource).filter(
297
+ Resource.id == resource_id,
298
+ Resource.deleted_at.is_(None)
299
+ ).first()
300
+
301
+ def create_resource(self, user_id: UUID, data: ResourceCreate) -> Resource:
302
+ resource = Resource(
303
+ **data.model_dump(),
304
+ user_id=user_id
305
+ )
306
+ self.db.add(resource)
307
+ self.db.commit()
308
+ self.db.refresh(resource)
309
+ return resource
310
+
311
+ def update_resource(self, resource: Resource, data: ResourceUpdate) -> Resource:
312
+ for field, value in data.model_dump(exclude_unset=True).items():
313
+ setattr(resource, field, value)
314
+
315
+ self.db.commit()
316
+ self.db.refresh(resource)
317
+ return resource
318
+
319
+ def delete_resource(self, resource: Resource, hard: bool = False):
320
+ if hard:
321
+ self.db.delete(resource)
322
+ else:
323
+ resource.deleted_at = datetime.utcnow()
324
+
325
+ self.db.commit()
326
+ """
@@ -0,0 +1,36 @@
1
+ # Backend Agent - Self-Verification Checklist
2
+
3
+ Run through every item before submitting your work.
4
+
5
+ ## API Design
6
+ - [ ] RESTful conventions followed (proper HTTP methods, status codes)
7
+ - [ ] OpenAPI documentation complete (all endpoints documented)
8
+ - [ ] Request/response schemas defined with Pydantic
9
+ - [ ] Pagination for list endpoints returning > 20 items
10
+ - [ ] Consistent error response format
11
+
12
+ ## Database
13
+ - [ ] Migrations created (Alembic) and tested
14
+ - [ ] Indexes on foreign keys and frequently queried columns
15
+ - [ ] No N+1 queries (use joinedload/selectinload)
16
+ - [ ] Transactions used for multi-step operations
17
+
18
+ ## Security
19
+ - [ ] JWT authentication on protected endpoints
20
+ - [ ] Password hashing with bcrypt (cost 10-12)
21
+ - [ ] Rate limiting on auth endpoints
22
+ - [ ] Input validation with Pydantic (no raw user input in queries)
23
+ - [ ] SQL injection protected (ORM or parameterized queries)
24
+ - [ ] No secrets in code or logs
25
+
26
+ ## Testing
27
+ - [ ] Unit tests for service layer logic
28
+ - [ ] Integration tests for all endpoints (happy + error paths)
29
+ - [ ] Auth scenarios tested (missing token, expired, wrong role)
30
+ - [ ] Test coverage > 80%
31
+
32
+ ## Code Quality
33
+ - [ ] Clean architecture layers: router -> service -> repository
34
+ - [ ] No business logic in route handlers
35
+ - [ ] Async/await used consistently
36
+ - [ ] Type hints on all function signatures
@@ -0,0 +1,98 @@
1
+ # Backend Agent - Error Recovery Playbook
2
+
3
+ When you encounter a failure, find the matching scenario and follow the recovery steps.
4
+ Do NOT stop or ask for help until you have exhausted the playbook.
5
+
6
+ ---
7
+
8
+ ## Import / Module Not Found
9
+
10
+ **Symptoms**: `ModuleNotFoundError`, `ImportError`, `No module named X`
11
+
12
+ 1. Check the import path — typo? wrong package name?
13
+ 2. Verify the dependency exists in `pyproject.toml` or `requirements.txt`
14
+ 3. If missing: note it in your result as "requires `pip install X`" — do NOT install yourself
15
+ 4. If it's a local module: check the directory structure with `get_symbols_overview`
16
+ 5. If the path changed: use `search_for_pattern("class ClassName")` to find the new location
17
+
18
+ ---
19
+
20
+ ## Test Failure
21
+
22
+ **Symptoms**: `pytest` returns FAILED, assertion errors
23
+
24
+ 1. Read the full error output — which test, which assertion, expected vs actual
25
+ 2. `find_symbol("test_function_name")` to read the test code
26
+ 3. Determine: is the test wrong or is the implementation wrong?
27
+ - Test expects old behavior → update test
28
+ - Implementation has a bug → fix implementation
29
+ 4. Re-run the specific test: `pytest path/to/test.py::test_name -v`
30
+ 5. After fix, run full test suite to check for regressions
31
+ 6. **3회 실패 시**: 다른 접근 방식 시도. 현재 시도를 progress에 기록하고 대안 구현
32
+
33
+ ---
34
+
35
+ ## Database Migration Error
36
+
37
+ **Symptoms**: `alembic upgrade head` fails, `IntegrityError`, duplicate column
38
+
39
+ 1. Read the error — is it a conflict with existing migration?
40
+ 2. Check current DB state: `alembic current`
41
+ 3. If migration conflicts: `alembic downgrade -1` then fix migration script
42
+ 4. If schema mismatch: compare model with actual DB schema
43
+ 5. **절대 하지 말 것**: `alembic stamp head` (데이터 손실 위험)
44
+
45
+ ---
46
+
47
+ ## Authentication / JWT Error
48
+
49
+ **Symptoms**: 401/403 responses, `InvalidTokenError`, `ExpiredSignatureError`
50
+
51
+ 1. Check: is the secret key consistent between encode and decode?
52
+ 2. Check: is the algorithm specified (`HS256` vs `RS256`)?
53
+ 3. Check: is the token being sent in the correct header format? (`Bearer {token}`)
54
+ 4. Check: is token expiry set correctly? (access: 15min, refresh: 7day)
55
+ 5. Test with a manually created token to isolate the issue
56
+
57
+ ---
58
+
59
+ ## N+1 Query / Slow Response
60
+
61
+ **Symptoms**: API response > 500ms, many similar SQL queries in logs
62
+
63
+ 1. Enable SQL logging: `echo=True` on engine
64
+ 2. Count queries for a single request
65
+ 3. If N+1: add `joinedload()` or `selectinload()` to the query
66
+ 4. If slow single query: check indexes with `EXPLAIN ANALYZE`
67
+ 5. If still slow: consider caching with Redis
68
+
69
+ ---
70
+
71
+ ## Rate Limit / Quota Error (Gemini API)
72
+
73
+ **Symptoms**: `429`, `RESOURCE_EXHAUSTED`, `rate limit exceeded`
74
+
75
+ 1. **즉시 멈춤** — 추가 API 호출 하지 말 것
76
+ 2. 현재까지 작업을 `progress-{agent-id}.md`에 저장
77
+ 3. `result-{agent-id}.md`에 Status: `quota_exceeded` 기록
78
+ 4. 남은 작업 목록을 명시하여 orchestrator가 나중에 재시도할 수 있게 함
79
+
80
+ ---
81
+
82
+ ## Serena Memory 접근 불가
83
+
84
+ **Symptoms**: `write_memory` / `read_memory` 실패, timeout
85
+
86
+ 1. 1회 재시도 (일시적 오류일 수 있음)
87
+ 2. 2회 연속 실패 시: 로컬 파일로 대체
88
+ - progress → `/tmp/progress-{agent-id}.md`로 작성
89
+ - result → `/tmp/result-{agent-id}.md`로 작성
90
+ 3. result에 `memory_fallback: true` 플래그 추가
91
+
92
+ ---
93
+
94
+ ## 일반 원칙
95
+
96
+ - **3회 실패**: 같은 접근 3번 실패하면 반드시 다른 방법 시도
97
+ - **막힘**: 5턴 이상 진전 없으면 현재 상태 저장하고 result에 `Status: blocked` 기록
98
+ - **범위 초과**: 다른 에이전트 영역의 문제 발견 시, result에 기록만 하고 직접 수정하지 말 것
@@ -0,0 +1,85 @@
1
+ # Backend Agent - Examples
2
+
3
+ ## Example 1: CRUD API Endpoint
4
+
5
+ **Input**: "Create a TODO CRUD API with user ownership"
6
+
7
+ **Output**:
8
+ ```
9
+ ## Task: TODO CRUD API
10
+
11
+ ### Endpoints Implemented
12
+ - POST /api/todos (create)
13
+ - GET /api/todos (list, user-scoped)
14
+ - GET /api/todos/{id} (detail)
15
+ - PATCH /api/todos/{id} (update)
16
+ - DELETE /api/todos/{id} (delete)
17
+
18
+ ### Database Schema
19
+ - todos table: id (UUID), title (VARCHAR), completed (BOOL), user_id (FK), created_at
20
+ - Index on user_id
21
+
22
+ ### Security
23
+ - [x] All endpoints require JWT auth
24
+ - [x] User can only access own todos (user_id filter)
25
+ - [x] Input validated with Pydantic
26
+
27
+ ### Files Created
28
+ - app/models/todo.py
29
+ - app/schemas/todo.py
30
+ - app/services/todo_service.py
31
+ - app/api/todos.py
32
+ - tests/test_todos.py
33
+ - alembic/versions/xxx_add_todos.py
34
+ ```
35
+
36
+ ## Example 2: Authentication System
37
+
38
+ **Input**: "Add JWT authentication with register and login"
39
+
40
+ **Output**:
41
+ ```
42
+ ## Task: JWT Authentication
43
+
44
+ ### Endpoints Implemented
45
+ - POST /api/auth/register (email + password)
46
+ - POST /api/auth/login (returns access + refresh tokens)
47
+ - POST /api/auth/refresh (refresh token rotation)
48
+
49
+ ### Security
50
+ - [x] Password hashed with bcrypt (cost 12)
51
+ - [x] Access token: 15min expiry
52
+ - [x] Refresh token: 7 day expiry, single-use rotation
53
+ - [x] Rate limiting: 5 attempts/min on login
54
+ - [x] Email validation with Pydantic EmailStr
55
+
56
+ ### Files Created
57
+ - app/models/user.py
58
+ - app/schemas/auth.py
59
+ - app/services/auth_service.py
60
+ - app/api/auth.py
61
+ - app/core/security.py (JWT helpers, password hashing)
62
+ - tests/test_auth.py
63
+ ```
64
+
65
+ ## Example 3: Fixing N+1 Query
66
+
67
+ **Input**: "The /api/posts endpoint is slow, taking 2s for 50 posts"
68
+
69
+ **Output**:
70
+ ```
71
+ ## Task: Fix N+1 Query in Posts API
72
+
73
+ ### Root Cause
74
+ Each post triggers a separate query for its author (N+1 problem).
75
+
76
+ ### Fix
77
+ Added joinedload(Post.author) to the query.
78
+
79
+ ### Before: 51 queries (1 + 50)
80
+ ### After: 1 query with JOIN
81
+
82
+ ### Files Modified
83
+ - app/api/posts.py (added eager loading)
84
+ - tests/test_posts.py (added performance assertion)
85
+ ```
@@ -0,0 +1,45 @@
1
+ # Backend Agent - Execution Protocol
2
+
3
+ ## Step 0: Prepare
4
+ 1. **Assess difficulty** — see `../_shared/difficulty-guide.md`
5
+ - **Simple**: Skip to Step 3 | **Medium**: All 4 steps | **Complex**: All steps + checkpoints
6
+ 2. **Check lessons** — read your domain section in `../_shared/lessons-learned.md`
7
+ 3. **Clarify requirements** — follow `../_shared/clarification-protocol.md`
8
+ - Check **Uncertainty Triggers**: 비즈니스 로직, 보안/인증, 기존 코드 충돌?
9
+ - Determine level: LOW → proceed | MEDIUM → present options | HIGH → ask immediately
10
+ 4. **Budget context** — follow `../_shared/context-budget.md` (read symbols, not whole files)
11
+
12
+ **⚠️ Intelligent Escalation**: When uncertain, escalate early. Don't blindly proceed.
13
+
14
+ Follow these steps in order (adjust depth by difficulty).
15
+
16
+ ## Step 1: Analyze
17
+ - Read the task requirements carefully
18
+ - Identify which endpoints, models, and services are needed
19
+ - Check existing code with Serena: `get_symbols_overview("app/api")`, `find_symbol("existing_function")`
20
+ - List assumptions; ask if unclear
21
+
22
+ ## Step 2: Plan
23
+ - Decide on file structure: models, schemas, routes, services
24
+ - Define API contracts (method, path, request/response types)
25
+ - Plan database schema changes (tables, columns, indexes, migrations)
26
+ - Identify security requirements (auth, validation, rate limiting)
27
+
28
+ ## Step 3: Implement
29
+ - Create/modify files in this order:
30
+ 1. Database models + migrations
31
+ 2. Pydantic schemas (request/response)
32
+ 3. Service layer (business logic)
33
+ 4. API routes (thin, delegate to services)
34
+ 5. Tests (unit + integration)
35
+ - Use `resources/api-template.py` as reference
36
+ - Follow clean architecture: router -> service -> repository -> models
37
+
38
+ ## Step 4: Verify
39
+ - Run `resources/checklist.md` items
40
+ - Run `../_shared/common-checklist.md` items
41
+ - Ensure all tests pass
42
+ - Confirm OpenAPI docs are complete
43
+
44
+ ## On Error
45
+ See `resources/error-playbook.md` for recovery steps.