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.
- hive_corp-0.1.0/.github/workflows/ci.yml +42 -0
- hive_corp-0.1.0/.github/workflows/publish.yml +32 -0
- hive_corp-0.1.0/.gitignore +36 -0
- hive_corp-0.1.0/CLAUDE.md +355 -0
- hive_corp-0.1.0/LICENSE +21 -0
- hive_corp-0.1.0/PKG-INFO +234 -0
- hive_corp-0.1.0/README.md +193 -0
- hive_corp-0.1.0/benchmarks/.gitignore +1 -0
- hive_corp-0.1.0/benchmarks/validation-suite.json +48 -0
- hive_corp-0.1.0/docs/ARCHITECTURE.md +1072 -0
- hive_corp-0.1.0/docs/BENCHMARKS.md +48 -0
- hive_corp-0.1.0/docs/OPEN_QUESTIONS.md +99 -0
- hive_corp-0.1.0/docs/PATTERNS.md +273 -0
- hive_corp-0.1.0/docs/ROADMAP.md +128 -0
- hive_corp-0.1.0/lefthook.yml +17 -0
- hive_corp-0.1.0/pyproject.toml +153 -0
- hive_corp-0.1.0/src/hive/__init__.py +3 -0
- hive_corp-0.1.0/src/hive/__main__.py +30 -0
- hive_corp-0.1.0/src/hive/api/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/api/apikey.py +16 -0
- hive_corp-0.1.0/src/hive/api/app.py +72 -0
- hive_corp-0.1.0/src/hive/api/auth.py +34 -0
- hive_corp-0.1.0/src/hive/api/deps.py +61 -0
- hive_corp-0.1.0/src/hive/api/routes/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/api/routes/approvals.py +50 -0
- hive_corp-0.1.0/src/hive/api/routes/budget.py +39 -0
- hive_corp-0.1.0/src/hive/api/routes/dashboard.py +40 -0
- hive_corp-0.1.0/src/hive/api/routes/finance.py +29 -0
- hive_corp-0.1.0/src/hive/api/routes/memory.py +87 -0
- hive_corp-0.1.0/src/hive/api/routes/org.py +30 -0
- hive_corp-0.1.0/src/hive/api/routes/projects.py +81 -0
- hive_corp-0.1.0/src/hive/api/routes/tasks.py +37 -0
- hive_corp-0.1.0/src/hive/api/templates.py +47 -0
- hive_corp-0.1.0/src/hive/api/views/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/api/views/approvals.py +25 -0
- hive_corp-0.1.0/src/hive/api/views/budget.py +47 -0
- hive_corp-0.1.0/src/hive/api/views/finance.py +48 -0
- hive_corp-0.1.0/src/hive/api/views/memory.py +33 -0
- hive_corp-0.1.0/src/hive/api/views/org.py +23 -0
- hive_corp-0.1.0/src/hive/api/views/overview.py +56 -0
- hive_corp-0.1.0/src/hive/budget/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/budget/benchmark.py +378 -0
- hive_corp-0.1.0/src/hive/budget/compiler.py +293 -0
- hive_corp-0.1.0/src/hive/budget/controller.py +121 -0
- hive_corp-0.1.0/src/hive/budget/escalation.py +181 -0
- hive_corp-0.1.0/src/hive/budget/finance.py +119 -0
- hive_corp-0.1.0/src/hive/budget/report.py +407 -0
- hive_corp-0.1.0/src/hive/budget/router.py +53 -0
- hive_corp-0.1.0/src/hive/budget/validation.py +375 -0
- hive_corp-0.1.0/src/hive/ceo/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/ceo/gateway.py +206 -0
- hive_corp-0.1.0/src/hive/cli/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/cli/main.py +1308 -0
- hive_corp-0.1.0/src/hive/core/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/core/config.py +162 -0
- hive_corp-0.1.0/src/hive/core/credentials.py +111 -0
- hive_corp-0.1.0/src/hive/core/models.py +232 -0
- hive_corp-0.1.0/src/hive/core/names.py +52 -0
- hive_corp-0.1.0/src/hive/founding/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/founding/engine.py +174 -0
- hive_corp-0.1.0/src/hive/growth/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/growth/engine.py +234 -0
- hive_corp-0.1.0/src/hive/growth/hiring.py +83 -0
- hive_corp-0.1.0/src/hive/growth/learning.py +114 -0
- hive_corp-0.1.0/src/hive/growth/optimizer.py +242 -0
- hive_corp-0.1.0/src/hive/growth/performance.py +89 -0
- hive_corp-0.1.0/src/hive/memory/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/memory/store.py +160 -0
- hive_corp-0.1.0/src/hive/office/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/office/cli.py +88 -0
- hive_corp-0.1.0/src/hive/office/factory.py +24 -0
- hive_corp-0.1.0/src/hive/office/matrix.py +559 -0
- hive_corp-0.1.0/src/hive/office/protocol.py +41 -0
- hive_corp-0.1.0/src/hive/py.typed +0 -0
- hive_corp-0.1.0/src/hive/revenue/__init__.py +1 -0
- hive_corp-0.1.0/src/hive/revenue/aggregate.py +58 -0
- hive_corp-0.1.0/src/hive/revenue/algora_scanner.py +119 -0
- hive_corp-0.1.0/src/hive/revenue/bidding.py +144 -0
- hive_corp-0.1.0/src/hive/revenue/devto_scanner.py +120 -0
- hive_corp-0.1.0/src/hive/revenue/portfolio.py +184 -0
- hive_corp-0.1.0/src/hive/revenue/scanner.py +255 -0
- hive_corp-0.1.0/src/hive/runtime/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/runtime/agent_dna.py +258 -0
- hive_corp-0.1.0/src/hive/runtime/code_worker.py +129 -0
- hive_corp-0.1.0/src/hive/runtime/context.py +86 -0
- hive_corp-0.1.0/src/hive/runtime/delta_retry.py +152 -0
- hive_corp-0.1.0/src/hive/runtime/events.py +48 -0
- hive_corp-0.1.0/src/hive/runtime/experimental.py +66 -0
- hive_corp-0.1.0/src/hive/runtime/lite_worker.py +151 -0
- hive_corp-0.1.0/src/hive/runtime/pool.py +135 -0
- hive_corp-0.1.0/src/hive/runtime/protocols.py +13 -0
- hive_corp-0.1.0/src/hive/runtime/registry.py +128 -0
- hive_corp-0.1.0/src/hive/runtime/scheduler.py +125 -0
- hive_corp-0.1.0/src/hive/runtime/sprint.py +114 -0
- hive_corp-0.1.0/src/hive/runtime/standup.py +111 -0
- hive_corp-0.1.0/src/hive/runtime/worktree.py +87 -0
- hive_corp-0.1.0/src/hive/static/css/custom.css +13 -0
- hive_corp-0.1.0/src/hive/static/js/charts.js +48 -0
- hive_corp-0.1.0/src/hive/storage/__init__.py +0 -0
- hive_corp-0.1.0/src/hive/storage/backup.py +93 -0
- hive_corp-0.1.0/src/hive/storage/database.py +59 -0
- hive_corp-0.1.0/src/hive/storage/rotation.py +152 -0
- hive_corp-0.1.0/src/hive/storage/schema.sql +143 -0
- hive_corp-0.1.0/src/hive/templates/base.html +33 -0
- hive_corp-0.1.0/src/hive/templates/pages/approvals.html +13 -0
- hive_corp-0.1.0/src/hive/templates/pages/budget.html +37 -0
- hive_corp-0.1.0/src/hive/templates/pages/finance.html +20 -0
- hive_corp-0.1.0/src/hive/templates/pages/memory.html +24 -0
- hive_corp-0.1.0/src/hive/templates/pages/org.html +12 -0
- hive_corp-0.1.0/src/hive/templates/pages/overview.html +26 -0
- hive_corp-0.1.0/src/hive/templates/partials/approvals_list.html +44 -0
- hive_corp-0.1.0/src/hive/templates/partials/budget_stats.html +23 -0
- hive_corp-0.1.0/src/hive/templates/partials/finance_breakdown.html +64 -0
- hive_corp-0.1.0/src/hive/templates/partials/finance_stats.html +27 -0
- hive_corp-0.1.0/src/hive/templates/partials/memory_list.html +23 -0
- hive_corp-0.1.0/src/hive/templates/partials/nav.html +48 -0
- hive_corp-0.1.0/src/hive/templates/partials/org_table.html +32 -0
- hive_corp-0.1.0/src/hive/templates/partials/overview_stats.html +27 -0
- hive_corp-0.1.0/tests/__init__.py +0 -0
- hive_corp-0.1.0/tests/conftest.py +104 -0
- hive_corp-0.1.0/tests/test_agent_dna.py +147 -0
- hive_corp-0.1.0/tests/test_aggregate_scanner.py +78 -0
- hive_corp-0.1.0/tests/test_algora_scanner.py +107 -0
- hive_corp-0.1.0/tests/test_api.py +223 -0
- hive_corp-0.1.0/tests/test_auth.py +41 -0
- hive_corp-0.1.0/tests/test_backup.py +97 -0
- hive_corp-0.1.0/tests/test_benchmark.py +227 -0
- hive_corp-0.1.0/tests/test_bidding.py +100 -0
- hive_corp-0.1.0/tests/test_budget.py +139 -0
- hive_corp-0.1.0/tests/test_cli_portfolio.py +122 -0
- hive_corp-0.1.0/tests/test_cli_runtime_policy.py +23 -0
- hive_corp-0.1.0/tests/test_code_worker.py +143 -0
- hive_corp-0.1.0/tests/test_compiler.py +313 -0
- hive_corp-0.1.0/tests/test_config.py +126 -0
- hive_corp-0.1.0/tests/test_context.py +65 -0
- hive_corp-0.1.0/tests/test_credentials.py +80 -0
- hive_corp-0.1.0/tests/test_database.py +236 -0
- hive_corp-0.1.0/tests/test_delta_retry.py +178 -0
- hive_corp-0.1.0/tests/test_devto_scanner.py +112 -0
- hive_corp-0.1.0/tests/test_e2e.py +265 -0
- hive_corp-0.1.0/tests/test_escalation.py +213 -0
- hive_corp-0.1.0/tests/test_experimental_runtime.py +145 -0
- hive_corp-0.1.0/tests/test_gateway.py +204 -0
- hive_corp-0.1.0/tests/test_growth.py +127 -0
- hive_corp-0.1.0/tests/test_hiring.py +140 -0
- hive_corp-0.1.0/tests/test_learning.py +129 -0
- hive_corp-0.1.0/tests/test_lite_worker.py +180 -0
- hive_corp-0.1.0/tests/test_matrix_office.py +320 -0
- hive_corp-0.1.0/tests/test_memory.py +188 -0
- hive_corp-0.1.0/tests/test_models.py +96 -0
- hive_corp-0.1.0/tests/test_optimizer.py +454 -0
- hive_corp-0.1.0/tests/test_pool.py +121 -0
- hive_corp-0.1.0/tests/test_portfolio.py +71 -0
- hive_corp-0.1.0/tests/test_registry.py +131 -0
- hive_corp-0.1.0/tests/test_report.py +237 -0
- hive_corp-0.1.0/tests/test_revenue_scanner.py +95 -0
- hive_corp-0.1.0/tests/test_rotation.py +111 -0
- hive_corp-0.1.0/tests/test_scheduler.py +190 -0
- hive_corp-0.1.0/tests/test_sprint.py +71 -0
- hive_corp-0.1.0/tests/test_standup.py +93 -0
- hive_corp-0.1.0/tests/test_validation.py +17 -0
- hive_corp-0.1.0/tests/test_views.py +167 -0
- 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` 가 전부 통과하는가?
|
hive_corp-0.1.0/LICENSE
ADDED
|
@@ -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.
|