hive-corp 0.1.0__tar.gz

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 (163) hide show
  1. hive_corp-0.1.0/.github/workflows/ci.yml +42 -0
  2. hive_corp-0.1.0/.github/workflows/publish.yml +32 -0
  3. hive_corp-0.1.0/.gitignore +36 -0
  4. hive_corp-0.1.0/CLAUDE.md +355 -0
  5. hive_corp-0.1.0/LICENSE +21 -0
  6. hive_corp-0.1.0/PKG-INFO +234 -0
  7. hive_corp-0.1.0/README.md +193 -0
  8. hive_corp-0.1.0/benchmarks/.gitignore +1 -0
  9. hive_corp-0.1.0/benchmarks/validation-suite.json +48 -0
  10. hive_corp-0.1.0/docs/ARCHITECTURE.md +1072 -0
  11. hive_corp-0.1.0/docs/BENCHMARKS.md +48 -0
  12. hive_corp-0.1.0/docs/OPEN_QUESTIONS.md +99 -0
  13. hive_corp-0.1.0/docs/PATTERNS.md +273 -0
  14. hive_corp-0.1.0/docs/ROADMAP.md +128 -0
  15. hive_corp-0.1.0/lefthook.yml +17 -0
  16. hive_corp-0.1.0/pyproject.toml +153 -0
  17. hive_corp-0.1.0/src/hive/__init__.py +3 -0
  18. hive_corp-0.1.0/src/hive/__main__.py +30 -0
  19. hive_corp-0.1.0/src/hive/api/__init__.py +0 -0
  20. hive_corp-0.1.0/src/hive/api/apikey.py +16 -0
  21. hive_corp-0.1.0/src/hive/api/app.py +72 -0
  22. hive_corp-0.1.0/src/hive/api/auth.py +34 -0
  23. hive_corp-0.1.0/src/hive/api/deps.py +61 -0
  24. hive_corp-0.1.0/src/hive/api/routes/__init__.py +0 -0
  25. hive_corp-0.1.0/src/hive/api/routes/approvals.py +50 -0
  26. hive_corp-0.1.0/src/hive/api/routes/budget.py +39 -0
  27. hive_corp-0.1.0/src/hive/api/routes/dashboard.py +40 -0
  28. hive_corp-0.1.0/src/hive/api/routes/finance.py +29 -0
  29. hive_corp-0.1.0/src/hive/api/routes/memory.py +87 -0
  30. hive_corp-0.1.0/src/hive/api/routes/org.py +30 -0
  31. hive_corp-0.1.0/src/hive/api/routes/projects.py +81 -0
  32. hive_corp-0.1.0/src/hive/api/routes/tasks.py +37 -0
  33. hive_corp-0.1.0/src/hive/api/templates.py +47 -0
  34. hive_corp-0.1.0/src/hive/api/views/__init__.py +0 -0
  35. hive_corp-0.1.0/src/hive/api/views/approvals.py +25 -0
  36. hive_corp-0.1.0/src/hive/api/views/budget.py +47 -0
  37. hive_corp-0.1.0/src/hive/api/views/finance.py +48 -0
  38. hive_corp-0.1.0/src/hive/api/views/memory.py +33 -0
  39. hive_corp-0.1.0/src/hive/api/views/org.py +23 -0
  40. hive_corp-0.1.0/src/hive/api/views/overview.py +56 -0
  41. hive_corp-0.1.0/src/hive/budget/__init__.py +0 -0
  42. hive_corp-0.1.0/src/hive/budget/benchmark.py +378 -0
  43. hive_corp-0.1.0/src/hive/budget/compiler.py +293 -0
  44. hive_corp-0.1.0/src/hive/budget/controller.py +121 -0
  45. hive_corp-0.1.0/src/hive/budget/escalation.py +181 -0
  46. hive_corp-0.1.0/src/hive/budget/finance.py +119 -0
  47. hive_corp-0.1.0/src/hive/budget/report.py +407 -0
  48. hive_corp-0.1.0/src/hive/budget/router.py +53 -0
  49. hive_corp-0.1.0/src/hive/budget/validation.py +375 -0
  50. hive_corp-0.1.0/src/hive/ceo/__init__.py +0 -0
  51. hive_corp-0.1.0/src/hive/ceo/gateway.py +206 -0
  52. hive_corp-0.1.0/src/hive/cli/__init__.py +0 -0
  53. hive_corp-0.1.0/src/hive/cli/main.py +1308 -0
  54. hive_corp-0.1.0/src/hive/core/__init__.py +0 -0
  55. hive_corp-0.1.0/src/hive/core/config.py +162 -0
  56. hive_corp-0.1.0/src/hive/core/credentials.py +111 -0
  57. hive_corp-0.1.0/src/hive/core/models.py +232 -0
  58. hive_corp-0.1.0/src/hive/core/names.py +52 -0
  59. hive_corp-0.1.0/src/hive/founding/__init__.py +0 -0
  60. hive_corp-0.1.0/src/hive/founding/engine.py +174 -0
  61. hive_corp-0.1.0/src/hive/growth/__init__.py +0 -0
  62. hive_corp-0.1.0/src/hive/growth/engine.py +234 -0
  63. hive_corp-0.1.0/src/hive/growth/hiring.py +83 -0
  64. hive_corp-0.1.0/src/hive/growth/learning.py +114 -0
  65. hive_corp-0.1.0/src/hive/growth/optimizer.py +242 -0
  66. hive_corp-0.1.0/src/hive/growth/performance.py +89 -0
  67. hive_corp-0.1.0/src/hive/memory/__init__.py +0 -0
  68. hive_corp-0.1.0/src/hive/memory/store.py +160 -0
  69. hive_corp-0.1.0/src/hive/office/__init__.py +0 -0
  70. hive_corp-0.1.0/src/hive/office/cli.py +88 -0
  71. hive_corp-0.1.0/src/hive/office/factory.py +24 -0
  72. hive_corp-0.1.0/src/hive/office/matrix.py +559 -0
  73. hive_corp-0.1.0/src/hive/office/protocol.py +41 -0
  74. hive_corp-0.1.0/src/hive/py.typed +0 -0
  75. hive_corp-0.1.0/src/hive/revenue/__init__.py +1 -0
  76. hive_corp-0.1.0/src/hive/revenue/aggregate.py +58 -0
  77. hive_corp-0.1.0/src/hive/revenue/algora_scanner.py +119 -0
  78. hive_corp-0.1.0/src/hive/revenue/bidding.py +144 -0
  79. hive_corp-0.1.0/src/hive/revenue/devto_scanner.py +120 -0
  80. hive_corp-0.1.0/src/hive/revenue/portfolio.py +184 -0
  81. hive_corp-0.1.0/src/hive/revenue/scanner.py +255 -0
  82. hive_corp-0.1.0/src/hive/runtime/__init__.py +0 -0
  83. hive_corp-0.1.0/src/hive/runtime/agent_dna.py +258 -0
  84. hive_corp-0.1.0/src/hive/runtime/code_worker.py +129 -0
  85. hive_corp-0.1.0/src/hive/runtime/context.py +86 -0
  86. hive_corp-0.1.0/src/hive/runtime/delta_retry.py +152 -0
  87. hive_corp-0.1.0/src/hive/runtime/events.py +48 -0
  88. hive_corp-0.1.0/src/hive/runtime/experimental.py +66 -0
  89. hive_corp-0.1.0/src/hive/runtime/lite_worker.py +151 -0
  90. hive_corp-0.1.0/src/hive/runtime/pool.py +135 -0
  91. hive_corp-0.1.0/src/hive/runtime/protocols.py +13 -0
  92. hive_corp-0.1.0/src/hive/runtime/registry.py +128 -0
  93. hive_corp-0.1.0/src/hive/runtime/scheduler.py +125 -0
  94. hive_corp-0.1.0/src/hive/runtime/sprint.py +114 -0
  95. hive_corp-0.1.0/src/hive/runtime/standup.py +111 -0
  96. hive_corp-0.1.0/src/hive/runtime/worktree.py +87 -0
  97. hive_corp-0.1.0/src/hive/static/css/custom.css +13 -0
  98. hive_corp-0.1.0/src/hive/static/js/charts.js +48 -0
  99. hive_corp-0.1.0/src/hive/storage/__init__.py +0 -0
  100. hive_corp-0.1.0/src/hive/storage/backup.py +93 -0
  101. hive_corp-0.1.0/src/hive/storage/database.py +59 -0
  102. hive_corp-0.1.0/src/hive/storage/rotation.py +152 -0
  103. hive_corp-0.1.0/src/hive/storage/schema.sql +143 -0
  104. hive_corp-0.1.0/src/hive/templates/base.html +33 -0
  105. hive_corp-0.1.0/src/hive/templates/pages/approvals.html +13 -0
  106. hive_corp-0.1.0/src/hive/templates/pages/budget.html +37 -0
  107. hive_corp-0.1.0/src/hive/templates/pages/finance.html +20 -0
  108. hive_corp-0.1.0/src/hive/templates/pages/memory.html +24 -0
  109. hive_corp-0.1.0/src/hive/templates/pages/org.html +12 -0
  110. hive_corp-0.1.0/src/hive/templates/pages/overview.html +26 -0
  111. hive_corp-0.1.0/src/hive/templates/partials/approvals_list.html +44 -0
  112. hive_corp-0.1.0/src/hive/templates/partials/budget_stats.html +23 -0
  113. hive_corp-0.1.0/src/hive/templates/partials/finance_breakdown.html +64 -0
  114. hive_corp-0.1.0/src/hive/templates/partials/finance_stats.html +27 -0
  115. hive_corp-0.1.0/src/hive/templates/partials/memory_list.html +23 -0
  116. hive_corp-0.1.0/src/hive/templates/partials/nav.html +48 -0
  117. hive_corp-0.1.0/src/hive/templates/partials/org_table.html +32 -0
  118. hive_corp-0.1.0/src/hive/templates/partials/overview_stats.html +27 -0
  119. hive_corp-0.1.0/tests/__init__.py +0 -0
  120. hive_corp-0.1.0/tests/conftest.py +104 -0
  121. hive_corp-0.1.0/tests/test_agent_dna.py +147 -0
  122. hive_corp-0.1.0/tests/test_aggregate_scanner.py +78 -0
  123. hive_corp-0.1.0/tests/test_algora_scanner.py +107 -0
  124. hive_corp-0.1.0/tests/test_api.py +223 -0
  125. hive_corp-0.1.0/tests/test_auth.py +41 -0
  126. hive_corp-0.1.0/tests/test_backup.py +97 -0
  127. hive_corp-0.1.0/tests/test_benchmark.py +227 -0
  128. hive_corp-0.1.0/tests/test_bidding.py +100 -0
  129. hive_corp-0.1.0/tests/test_budget.py +139 -0
  130. hive_corp-0.1.0/tests/test_cli_portfolio.py +122 -0
  131. hive_corp-0.1.0/tests/test_cli_runtime_policy.py +23 -0
  132. hive_corp-0.1.0/tests/test_code_worker.py +143 -0
  133. hive_corp-0.1.0/tests/test_compiler.py +313 -0
  134. hive_corp-0.1.0/tests/test_config.py +126 -0
  135. hive_corp-0.1.0/tests/test_context.py +65 -0
  136. hive_corp-0.1.0/tests/test_credentials.py +80 -0
  137. hive_corp-0.1.0/tests/test_database.py +236 -0
  138. hive_corp-0.1.0/tests/test_delta_retry.py +178 -0
  139. hive_corp-0.1.0/tests/test_devto_scanner.py +112 -0
  140. hive_corp-0.1.0/tests/test_e2e.py +265 -0
  141. hive_corp-0.1.0/tests/test_escalation.py +213 -0
  142. hive_corp-0.1.0/tests/test_experimental_runtime.py +145 -0
  143. hive_corp-0.1.0/tests/test_gateway.py +204 -0
  144. hive_corp-0.1.0/tests/test_growth.py +127 -0
  145. hive_corp-0.1.0/tests/test_hiring.py +140 -0
  146. hive_corp-0.1.0/tests/test_learning.py +129 -0
  147. hive_corp-0.1.0/tests/test_lite_worker.py +180 -0
  148. hive_corp-0.1.0/tests/test_matrix_office.py +320 -0
  149. hive_corp-0.1.0/tests/test_memory.py +188 -0
  150. hive_corp-0.1.0/tests/test_models.py +96 -0
  151. hive_corp-0.1.0/tests/test_optimizer.py +454 -0
  152. hive_corp-0.1.0/tests/test_pool.py +121 -0
  153. hive_corp-0.1.0/tests/test_portfolio.py +71 -0
  154. hive_corp-0.1.0/tests/test_registry.py +131 -0
  155. hive_corp-0.1.0/tests/test_report.py +237 -0
  156. hive_corp-0.1.0/tests/test_revenue_scanner.py +95 -0
  157. hive_corp-0.1.0/tests/test_rotation.py +111 -0
  158. hive_corp-0.1.0/tests/test_scheduler.py +190 -0
  159. hive_corp-0.1.0/tests/test_sprint.py +71 -0
  160. hive_corp-0.1.0/tests/test_standup.py +93 -0
  161. hive_corp-0.1.0/tests/test_validation.py +17 -0
  162. hive_corp-0.1.0/tests/test_views.py +167 -0
  163. hive_corp-0.1.0/uv.lock +1728 -0
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout
13
+ uses: actions/checkout@v4
14
+
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.14"
19
+
20
+ - name: Set up uv
21
+ uses: astral-sh/setup-uv@v6
22
+
23
+ - name: Install dependencies
24
+ run: uv sync --extra dev --extra dashboard --extra matrix
25
+
26
+ - name: Ruff
27
+ run: uv run --extra dev --extra dashboard --extra matrix ruff check .
28
+
29
+ - name: Pyright
30
+ run: uv run --extra dev --extra dashboard --extra matrix pyright
31
+
32
+ - name: Pytest
33
+ run: uv run --extra dev --extra dashboard --extra matrix pytest
34
+
35
+ - name: Benchmark smoke
36
+ run: uv run --extra dev --extra dashboard --extra matrix hive benchmark --validate-suite all --json --artifact benchmarks/latest/validation-suite.json
37
+
38
+ - name: Upload benchmark artifact
39
+ uses: actions/upload-artifact@v4
40
+ with:
41
+ name: benchmark-validation-suite
42
+ path: benchmarks/latest/validation-suite.json
@@ -0,0 +1,32 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ environment: pypi
14
+ permissions:
15
+ id-token: write
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.14"
24
+
25
+ - name: Set up uv
26
+ uses: astral-sh/setup-uv@v6
27
+
28
+ - name: Build
29
+ run: uv build
30
+
31
+ - name: Publish to PyPI
32
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,36 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ *.egg
9
+
10
+ # Node
11
+ node_modules/
12
+ .next/
13
+ out/
14
+
15
+ # IDE
16
+ .idea/
17
+ .vscode/
18
+ *.swp
19
+
20
+ # OS
21
+ .DS_Store
22
+ Thumbs.db
23
+
24
+ # Env
25
+ .env
26
+ .env.local
27
+
28
+ # SQLite
29
+ *.db
30
+ *.db-wal
31
+ *.db-shm
32
+
33
+ # Hive runtime
34
+ .hive/
35
+ worktrees/
36
+ company.yaml
@@ -0,0 +1,355 @@
1
+ # Hive Corp — Project Instructions
2
+
3
+ ## What This Is
4
+
5
+ Autonomous AI company platform. Users found a company through conversation,
6
+ hire AI agents as employees, and the company runs on its own.
7
+ The user is the CEO, not a developer using a tool.
8
+
9
+ ## Core Architecture Decisions
10
+
11
+ 1. **Agents are data, not processes.** Agent = config in DB (mem ~0).
12
+ Worker = execution slot (fixed-size pool). 100 agents share 3 workers.
13
+ 2. **Nothing is predefined.** No fixed departments, roles, or business models.
14
+ The company starts from a conversation and grows via Growth Engine triggers.
15
+ 3. **CLI-first.** Phase 1 is CLI-only. Matrix/Discord are Phase 3+.
16
+ 4. **Token efficiency is a core feature**, not an afterthought.
17
+ Proven techniques from Phase 1, experimental from Phase 4+.
18
+ All LLM calls logged to token_logs. No untracked LLM calls.
19
+
20
+ ## Key Documents
21
+
22
+ - `docs/ARCHITECTURE.md` — full system design
23
+ - `docs/ROADMAP.md` — phased development plan
24
+
25
+ ## Code Rules
26
+
27
+ - Python 3.14+, strict pyright, ruff for lint/format
28
+ - `@dataclass(slots=True)` for all data classes
29
+ - `Protocol` for interfaces (not ABC)
30
+ - `async/await` throughout (asyncio)
31
+ - Type hints on all function signatures
32
+ - `pathlib.Path` (not os.path)
33
+ - `match/case` for 3+ branches
34
+ - No `any` type, no `as` assertion, no `typing.Optional`
35
+
36
+ ## Common Mistakes — 반복하지 말 것
37
+
38
+ 실제 개발 중 ruff/pyright에 반복적으로 걸린 패턴들. 작성 시점에서 지킬 것.
39
+
40
+ ### 1. 함수 내 import 금지 (PLC0415)
41
+ ```python
42
+ # ❌
43
+ async def fire(self) -> bool:
44
+ from time import time # PLC0415
45
+ ...
46
+
47
+ # ✅ 파일 상단에서 import
48
+ from time import time
49
+ ```
50
+ 순환 import가 아닌 이상 함수 내 import를 쓰지 않는다.
51
+
52
+ ### 2. 테스트에서 호출할 메서드는 public으로 (reportPrivateUsage)
53
+ ```python
54
+ # ❌ 테스트에서 접근 불가
55
+ def _classify(self, approval): ...
56
+
57
+ # ✅ 테스트 가능성을 고려
58
+ def classify(self, approval): ...
59
+ ```
60
+ `_prefix`는 정말 외부에서 호출할 일이 없는 내부 구현에만 사용.
61
+
62
+ ### 3. `type: ignore` 복붙 금지 (reportUnnecessaryTypeIgnoreComment)
63
+ ```python
64
+ # ❌ 이전 파일에서 복사한 불필요한 주석
65
+ return float(row["total"]) # type: ignore[index]
66
+
67
+ # ✅ 먼저 pyright를 돌려보고 필요할 때만
68
+ return float(row["total"])
69
+ ```
70
+ `type: ignore`는 pyright가 실제로 에러를 내는 경우에만 추가.
71
+
72
+ ### 4. async 함수에서 blocking I/O 금지 (ASYNC240)
73
+ ```python
74
+ # ❌ async 함수에서 Path.exists() 직접 호출
75
+ async def check() -> None:
76
+ if not Path(DB_PATH).exists(): ...
77
+
78
+ # ✅ sync 헬퍼로 분리
79
+ def _db_exists() -> bool:
80
+ return Path(DB_PATH).exists()
81
+ ```
82
+
83
+ ### 5. 테스트에서 하드코딩 시크릿 주의 (S105)
84
+ ```python
85
+ # ❌
86
+ assert token == "secret123" # S105 경고
87
+
88
+ # ✅ noqa 명시 또는 변수로 분리
89
+ assert token == "secret123" # noqa: S105
90
+ ```
91
+
92
+ ### 6. `datetime.UTC` alias 사용 (UP017)
93
+ ```python
94
+ # ❌ Python 3.11 이전 스타일
95
+ from datetime import timezone
96
+ now = datetime.now(tz=timezone.utc)
97
+
98
+ # ✅ Python 3.11+ alias
99
+ from datetime import UTC
100
+ now = datetime.now(tz=UTC)
101
+ ```
102
+ `datetime.timezone.utc` 대신 `datetime.UTC`를 사용한다.
103
+
104
+ ### 7. FastAPI `Depends()` 기본값 (B008)
105
+ ```python
106
+ # ❌ ruff B008 경고
107
+ async def handler(db: Database = Depends(get_db)) -> None: ...
108
+
109
+ # ✅ noqa 명시 (FastAPI 공식 패턴)
110
+ async def handler(db: Database = Depends(get_db)) -> None: # noqa: B008
111
+ ...
112
+ ```
113
+ FastAPI의 `Depends()`는 함수 기본값에 쓰는 것이 공식 패턴이므로 `noqa: B008`로 허용.
114
+
115
+ ## Project Structure
116
+
117
+ ```
118
+ src/hive/
119
+ cli/ — CEO CLI (click + rich)
120
+ core/ — Domain models (Company, Agent, Task, Project)
121
+ founding/ — Conversational founding engine
122
+ growth/ — Growth triggers
123
+ ceo/ — CEO Gateway (escalation logic)
124
+ memory/ — Company Memory (SQLite FTS5)
125
+ budget/ — Token budget controller + model router
126
+ runtime/ — Worker Pool + Agent Registry + Scheduler
127
+ office/ — Office Protocol (cli, matrix, discord)
128
+ storage/ — SQLite database + migrations
129
+ api/ — FastAPI dashboard API
130
+ ```
131
+
132
+ ## Build & Run
133
+
134
+ ```bash
135
+ uv sync --extra dev # Install deps (with dev tools)
136
+ uv run hive found # Found a company
137
+ uv run hive status # Company status
138
+ uv run pytest # Run tests
139
+ uv run pytest --memray # Run tests with memory profiling
140
+ ruff check --fix && ruff format # Lint
141
+ pyright # Type check
142
+ ```
143
+
144
+ ## Pre-commit Hooks (lefthook)
145
+
146
+ commit 시 자동 실행 (병렬, ~2초):
147
+ - `ruff check` — lint
148
+ - `ruff format --check` — format 검증
149
+ - `pyright` — 타입 체크
150
+
151
+ push 시 자동 실행:
152
+ - `pytest` — 전체 테스트
153
+
154
+ ## Token Efficiency — Must Follow
155
+
156
+ - Never call LLM for something code can do (standups, status, routing, git ops)
157
+ - Agent-to-agent communication uses structured messages (token 0), not natural language
158
+ - Only CEO-facing messages use natural language
159
+ - Use `cache_control` on system prompts (Anthropic prompt caching)
160
+ - Log every LLM call to `token_logs` with `optimization_flags`
161
+ - Task-based model routing: Haiku for simple, Sonnet for code, Opus for architecture only
162
+
163
+ ## Memory Management — Must Follow
164
+
165
+ 메모리 누수는 장시간 실행되는 Agent Runtime에서 치명적이다.
166
+ 코드 작성 시 아래 규칙을 반드시 따른다.
167
+
168
+ ### 리소스 정리 원칙
169
+
170
+ ```python
171
+ # ✅ async 리소스는 반드시 async with (DB, HTTP, file)
172
+ async with aiosqlite.connect(path) as conn:
173
+ ...
174
+
175
+ async with httpx.AsyncClient() as client:
176
+ response = await client.post(...)
177
+
178
+ # ✅ subprocess는 finally에서 kill 보장
179
+ try:
180
+ proc = await asyncio.create_subprocess_exec(...)
181
+ await proc.communicate()
182
+ finally:
183
+ if proc.returncode is None:
184
+ proc.kill()
185
+ await proc.wait()
186
+
187
+ # ✅ 캐시는 반드시 크기 제한
188
+ from functools import lru_cache
189
+ @lru_cache(maxsize=128) # 무제한(maxsize=None) 금지
190
+
191
+ # ✅ 객체 참조가 약해야 하면 WeakRef
192
+ from weakref import WeakValueDictionary
193
+ agent_cache: WeakValueDictionary[str, AgentConfig] = WeakValueDictionary()
194
+ ```
195
+
196
+ ### 금지 패턴
197
+
198
+ ```python
199
+ # ❌ context manager 없이 리소스 열기
200
+ conn = await aiosqlite.connect(path) # close 누락 위험
201
+
202
+ # ❌ 무한 증가 컬렉션
203
+ results: list[Result] = []
204
+ async for item in stream:
205
+ results.append(item) # OOM 위험 → generator로 yield
206
+
207
+ # ❌ 전역 변수에 큰 객체 캐싱
208
+ _cache: dict[str, bytes] = {} # GC 불가, 무한 증가
209
+
210
+ # ❌ 이벤트 리스너 등록 후 미해제
211
+ ```
212
+
213
+ ### 모듈별 위험 지점
214
+
215
+ | 모듈 | 위험 | 대응 |
216
+ |------|------|------|
217
+ | runtime/pool | Worker subprocess 좀비 | finally에서 kill + wait |
218
+ | runtime/scheduler | Task queue 무한 증가 | 완료 태스크 주기적 정리 |
219
+ | storage/database | Connection 미반환 | context manager 강제 |
220
+ | memory/store | FTS 인덱스 무한 증가 | 오래된 memory 아카이브 정책 |
221
+ | budget/controller | token_logs 무한 증가 | 월별 집계 후 상세 로그 정리 |
222
+ | LLM 호출 | httpx client 미반환 | async with 강제 |
223
+
224
+ ### 메모리 프로파일링
225
+
226
+ ```bash
227
+ # CI/테스트: pytest-memray로 메모리 회귀 탐지
228
+ uv run pytest --memray
229
+
230
+ # 특정 테스트에 메모리 한도 설정
231
+ @pytest.mark.limit_memory("50 MB")
232
+ async def test_worker_pool() -> None:
233
+ ...
234
+
235
+ # 개발: memray로 상세 분석
236
+ memray run -o output.bin python script.py
237
+ memray flamegraph output.bin
238
+
239
+ # 프로덕션: tracemalloc (낮은 오버헤드)
240
+ # 3.14: python -m asyncio ps <PID> 로 async 태스크 실시간 조회
241
+ # 3.14: python -m pdb -p <PID> 로 실행 중 프로세스 원격 디버깅
242
+ ```
243
+
244
+ ### 대량 데이터 처리
245
+
246
+ ```python
247
+ # ✅ generator로 한 건씩 처리
248
+ async def stream_logs(db: Database) -> AsyncGenerator[TokenLog]:
249
+ async for row in await db.execute("SELECT * FROM token_logs"):
250
+ yield TokenLog(**row)
251
+
252
+ # ✅ 대량 INSERT는 executemany + 배치
253
+ await db.executemany(
254
+ "INSERT INTO token_logs VALUES (?, ?, ?)",
255
+ batch, # list[tuple], 1000건 단위
256
+ )
257
+ ```
258
+
259
+ ## Testing — Must Follow
260
+
261
+ 코드를 작성하면 반드시 테스트도 함께 작성한다. PR 없는 코드는 있어도, 테스트 없는 코드는 없다.
262
+
263
+ ### 원칙
264
+
265
+ - **새 모듈 = 새 테스트 파일.** `src/hive/foo/bar.py` → `tests/test_bar.py`
266
+ - **모든 public 함수에 최소 1개 테스트.** happy path + edge case
267
+ - **테스트 먼저 실행 가능한 상태 유지.** `uv run pytest` 가 항상 통과해야 함
268
+ - **LLM 호출은 mock.** 단위 테스트에서 실제 API를 호출하지 않는다
269
+
270
+ ### 테스트 구조
271
+
272
+ ```
273
+ tests/
274
+ test_models.py ← core/models.py
275
+ test_database.py ← storage/database.py
276
+ test_config.py ← core/config.py
277
+ test_founding.py ← founding/engine.py (LLM mock)
278
+ test_gateway.py ← ceo/gateway.py
279
+ test_memory.py ← memory/store.py
280
+ test_budget.py ← budget/controller.py
281
+ test_pool.py ← runtime/pool.py
282
+ test_scheduler.py ← runtime/scheduler.py
283
+ test_cli_office.py ← office/cli.py
284
+ ...
285
+ ```
286
+
287
+ ### 패턴
288
+
289
+ ```python
290
+ # 1. async 테스트는 그냥 async def로 작성 (asyncio_mode=auto)
291
+ class TestSomething:
292
+ async def test_example(self) -> None:
293
+ ...
294
+
295
+ # 2. DB fixture — in-memory SQLite (매 테스트 격리)
296
+ @pytest.fixture
297
+ async def db() -> AsyncGenerator[Database]:
298
+ database = Database(":memory:")
299
+ await database.connect()
300
+ yield database
301
+ await database.close()
302
+
303
+ # 3. LLM mock — anthropic client를 mock
304
+ @pytest.fixture
305
+ def mock_llm() -> MockLLMClient:
306
+ return MockLLMClient(responses=[
307
+ {"content": "분석 결과입니다.", "input_tokens": 100, "output_tokens": 50},
308
+ ])
309
+
310
+ # 4. Office mock — CLI 입력을 자동화
311
+ @pytest.fixture
312
+ def mock_office() -> MockOffice:
313
+ return MockOffice(ceo_responses=["yes", "TestCorp", "50"])
314
+
315
+ # 5. integration 테스트는 마커로 분리
316
+ @pytest.mark.integration
317
+ async def test_real_llm_call() -> None:
318
+ """실제 LLM API 호출. CI에서는 스킵."""
319
+ ...
320
+ ```
321
+
322
+ ### 무엇을 테스트하는가
323
+
324
+ | 모듈 | 테스트 대상 | mock 대상 |
325
+ |------|-----------|----------|
326
+ | models | 기본값, 유효성, ID 유니크 | 없음 |
327
+ | database | CRUD, FTS, 집계 쿼리 | 없음 (in-memory DB) |
328
+ | config | load/save, env var, 기본값 | 없음 |
329
+ | founding | 대화 흐름, company.yaml 생성 | Office (CEO 입력), LLM |
330
+ | gateway | escalation 판단, 승인/거절 | Office |
331
+ | memory | CRUD, 검색, 중복 감지 | 없음 (in-memory DB) |
332
+ | budget | 예산 추적, auto-downgrade, 알림 | Office (알림) |
333
+ | pool | Worker 동시성 제한, semaphore | LLM |
334
+ | scheduler | DAG 정렬, 병렬 실행, 큐 | Worker Pool |
335
+ | office/cli | 메시지 표시, 승인 프롬프트 | stdin/stdout |
336
+
337
+ ### 테스트 실행
338
+
339
+ ```bash
340
+ uv run pytest # 전체
341
+ uv run pytest tests/test_foo.py # 단일 파일
342
+ uv run pytest -k "test_hire" # 이름으로 필터
343
+ uv run pytest -v # 상세 출력
344
+ uv run pytest -m integration # integration만
345
+ uv run pytest -m "not integration" # integration 제외
346
+ ```
347
+
348
+ ### 체크리스트 (새 기능 작성 시)
349
+
350
+ - [ ] 새 모듈에 대응하는 test 파일 생성했는가?
351
+ - [ ] happy path 테스트가 있는가?
352
+ - [ ] edge case (빈 값, None, 잘못된 입력) 테스트가 있는가?
353
+ - [ ] async 함수는 async 테스트로 작성했는가?
354
+ - [ ] LLM 호출을 mock 했는가?
355
+ - [ ] `uv run pytest` 가 전부 통과하는가?
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Son Seongjun (SonAIengine)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.