ak5 1.0.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 (54) hide show
  1. ak5-1.0.0/.gitignore +64 -0
  2. ak5-1.0.0/Dockerfile +14 -0
  3. ak5-1.0.0/PKG-INFO +163 -0
  4. ak5-1.0.0/README.md +133 -0
  5. ak5-1.0.0/pyproject.toml +46 -0
  6. ak5-1.0.0/src/ak5/__init__.py +3 -0
  7. ak5-1.0.0/src/ak5/cli/__init__.py +3 -0
  8. ak5-1.0.0/src/ak5/cli/commands/agents.py +55 -0
  9. ak5-1.0.0/src/ak5/cli/commands/board.py +122 -0
  10. ak5-1.0.0/src/ak5/cli/commands/delegate.py +66 -0
  11. ak5-1.0.0/src/ak5/cli/commands/demo.py +230 -0
  12. ak5-1.0.0/src/ak5/cli/commands/login.py +47 -0
  13. ak5-1.0.0/src/ak5/cli/commands/mcp.py +8 -0
  14. ak5-1.0.0/src/ak5/cli/commands/serve.py +18 -0
  15. ak5-1.0.0/src/ak5/cli/config.py +35 -0
  16. ak5-1.0.0/src/ak5/cli/main.py +31 -0
  17. ak5-1.0.0/src/ak5/config.py +29 -0
  18. ak5-1.0.0/src/ak5/database.py +52 -0
  19. ak5-1.0.0/src/ak5/main.py +148 -0
  20. ak5-1.0.0/src/ak5/mcp/__init__.py +17 -0
  21. ak5-1.0.0/src/ak5/mcp/client.py +164 -0
  22. ak5-1.0.0/src/ak5/mcp/server.py +10 -0
  23. ak5-1.0.0/src/ak5/mcp/tools.py +149 -0
  24. ak5-1.0.0/src/ak5/models/__init__.py +16 -0
  25. ak5-1.0.0/src/ak5/models/actor.py +50 -0
  26. ak5-1.0.0/src/ak5/models/audit.py +38 -0
  27. ak5-1.0.0/src/ak5/models/base.py +24 -0
  28. ak5-1.0.0/src/ak5/models/board.py +40 -0
  29. ak5-1.0.0/src/ak5/models/column.py +46 -0
  30. ak5-1.0.0/src/ak5/models/ticket.py +157 -0
  31. ak5-1.0.0/src/ak5/routers/__init__.py +13 -0
  32. ak5-1.0.0/src/ak5/routers/actors.py +101 -0
  33. ak5-1.0.0/src/ak5/routers/auth.py +137 -0
  34. ak5-1.0.0/src/ak5/routers/boards.py +211 -0
  35. ak5-1.0.0/src/ak5/routers/events.py +37 -0
  36. ak5-1.0.0/src/ak5/routers/tickets.py +488 -0
  37. ak5-1.0.0/src/ak5/schemas/__init__.py +57 -0
  38. ak5-1.0.0/src/ak5/schemas/actor.py +47 -0
  39. ak5-1.0.0/src/ak5/schemas/audit.py +16 -0
  40. ak5-1.0.0/src/ak5/schemas/board.py +31 -0
  41. ak5-1.0.0/src/ak5/schemas/column.py +23 -0
  42. ak5-1.0.0/src/ak5/schemas/event.py +10 -0
  43. ak5-1.0.0/src/ak5/schemas/ticket.py +93 -0
  44. ak5-1.0.0/src/ak5/services/__init__.py +12 -0
  45. ak5-1.0.0/src/ak5/services/discovery.py +79 -0
  46. ak5-1.0.0/src/ak5/services/event_bus.py +72 -0
  47. ak5-1.0.0/src/ak5/services/lexorank.py +149 -0
  48. ak5-1.0.0/tests/conftest.py +109 -0
  49. ak5-1.0.0/tests/test_boards_api.py +94 -0
  50. ak5-1.0.0/tests/test_cli.py +31 -0
  51. ak5-1.0.0/tests/test_discovery.py +43 -0
  52. ak5-1.0.0/tests/test_lexorank.py +57 -0
  53. ak5-1.0.0/tests/test_mcp_tools.py +73 -0
  54. ak5-1.0.0/tests/test_tickets_api.py +199 -0
ak5-1.0.0/.gitignore ADDED
@@ -0,0 +1,64 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ /lib/
14
+ /lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ share/python-wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+ MANIFEST
24
+
25
+ # Virtual environments
26
+ .venv/
27
+ env/
28
+ venv/
29
+ ENV/
30
+
31
+ # Database
32
+ *.db
33
+ *.db-wal
34
+ *.db-shm
35
+ *.sqlite
36
+ *.sqlite3
37
+
38
+ # Node / Frontend
39
+ node_modules/
40
+ .next/
41
+ out/
42
+ build/
43
+ dist/
44
+ .npm
45
+ *.tsbuildinfo
46
+
47
+ # Testing & Coverage
48
+ .pytest_cache/
49
+ .coverage
50
+ htmlcov/
51
+
52
+ # OS / IDE
53
+ .DS_Store
54
+ .idea/
55
+ .vscode/
56
+ *.swp
57
+ *.swo
58
+
59
+ # Session
60
+ .ak5_session.json
61
+
62
+ # Local agent / scratch
63
+ .libragent/
64
+ tmp/
ak5-1.0.0/Dockerfile ADDED
@@ -0,0 +1,14 @@
1
+ FROM python:3.13-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN pip install uv
6
+
7
+ COPY pyproject.toml README.md ./
8
+ COPY backend ./backend
9
+
10
+ RUN uv pip install --system -e backend
11
+
12
+ EXPOSE 8000
13
+
14
+ CMD ["uvicorn", "ak5.main:app", "--host", "0.0.0.0", "--port", "8000"]
ak5-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.5
2
+ Name: ak5
3
+ Version: 1.0.0
4
+ Summary: AK5: Agent-Orchestrated Kanban System Gateway, MCP Server & CLI
5
+ Author: AK5 Team
6
+ License: MIT
7
+ Keywords: ai-agents,fastapi,kanban,mcp,multi-agent,orchestration
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: aiosqlite>=0.20.0
18
+ Requires-Dist: click>=8.1.0
19
+ Requires-Dist: fastapi>=0.115.0
20
+ Requires-Dist: httpx>=0.27.0
21
+ Requires-Dist: mcp>=1.0.0
22
+ Requires-Dist: pydantic-settings>=2.4.0
23
+ Requires-Dist: pydantic>=2.8.0
24
+ Requires-Dist: pyjwt>=2.9.0
25
+ Requires-Dist: rich>=13.7.0
26
+ Requires-Dist: sqlalchemy>=2.0.30
27
+ Requires-Dist: sse-starlette>=2.1.0
28
+ Requires-Dist: uvicorn[standard]>=0.30.0
29
+ Description-Content-Type: text/markdown
30
+
31
+ # AK5 (Agent K5) — Agent-Orchestrated Kanban System
32
+
33
+ AK5는 인간 사용자(PM, 개발자)와 자율 AI 에이전트(LLM Agents)가 단일 칸반(K5) 인터페이스 위에서 실시간으로 협업하고 작업을 위임(Delegation) 및 추적하는 **Agent-Orchestrated Kanban 시스템**입니다.
34
+
35
+ ---
36
+
37
+ ## 1. 주요 특징
38
+
39
+ * **Actor 추상화 일원화 (Unified Actor Model):** 인간과 AI 에이전트를 동일한 `Actor` 인터페이스로 취급 (`user_pm`, `agent_image_worker` 등).
40
+ * **역량 기반 발견 및 위임 (Capability-driven Discovery & Delegation):** 에이전트 역량 태그(`image-resize`, `code-review`, `security` 등) 및 자연어 검색 기반으로 작업 위임.
41
+ * **듀얼 프로토콜 (REST + SSE + MCP):**
42
+ * **Web UI (Next.js 15):** 드래그 앤 드롭(`@dnd-kit`), SSE 실시간 보드 자동 동기화, 계층형 서브태스크 진행률 바 및 아코디언 토글, 에이전트 활동 펄스(Activity Glow).
43
+ * **AI Agents (MCP):** Model Context Protocol 표준 툴셋(`ak5_list_available_agents`, `ak5_delegate_subtask`, `ak5_get_ticket_context`, `ak5_update_ticket_status`, `ak5_report_block`).
44
+ * **CLI (`ak5`):** 터미널 환경에서 액터 로그인, 에이전트 검색, 서브태스크 위임, 실시간 터미널 칸반 뷰(`ak5 board --watch`), 협업 시뮬레이션 데모(`ak5 demo`).
45
+ * **동시성 및 순서 정렬 보장:** Lexorank 알고리즘(Base36)을 통한 충돌 없는 임의 순서 삽입, SQLite WAL 모드 + Busy Timeout 설정.
46
+
47
+ ---
48
+
49
+ ## 2. 프로젝트 디렉토리 레이아웃
50
+
51
+ ```
52
+ ak5/
53
+ ├── backend/ # FastAPI + MCP Server
54
+ │ ├── src/ak5/
55
+ │ │ ├── main.py # FastAPI 진입점 & Lifespan & MCP 마운트
56
+ │ │ ├── config.py # Pydantic Settings
57
+ │ │ ├── database.py # SQLite WAL 비동기 세션
58
+ │ │ ├── models/ # SQLAlchemy 2.0 모델 (Actor, Board, Column, Ticket, Audit)
59
+ │ │ ├── schemas/ # Pydantic v2 DTO 스키마
60
+ │ │ ├── services/ # Lexorank, Discovery, EventBus (SSE)
61
+ │ │ ├── routers/ # REST API (auth, actors, boards, tickets, events)
62
+ │ │ └── mcp/ # MCP Server (MCPServer, tools, client)
63
+ │ └── tests/ # Pytest 종합 단위/통합 테스트 (19개)
64
+ │
65
+ ├── frontend/ # Next.js 15 Web UI (React 18, Tailwind, @dnd-kit)
66
+ │ ├── src/
67
+ │ │ ├── app/ # App Router (layout.tsx, page.tsx, globals.css)
68
+ │ │ ├── components/
69
+ │ │ │ ├── board/ # KanbanBoard, KanbanColumn, TicketCard
70
+ │ │ │ └── actor/ # ActorBadge
71
+ │ │ └── lib/ # SSE 구독 및 API 클라이언트
72
+ │ └── package.json
73
+ │
74
+ ├── cli/ # ak5 터미널 도구
75
+ │ └── src/ak5_cli/
76
+ │ ├── main.py # Click CLI 엔트리포인트
77
+ │ ├── config.py # 세션 및 API URL 관리
78
+ │ └── commands/ # login, agents, delegate, board, demo
79
+ │
80
+ ├── docker-compose.yml # 컨테이너 오케스트레이션
81
+ └── pyproject.toml # uv 기반 워크스페이스 설정
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 3. 실행 방법
87
+
88
+ ### 3.1 사전 요구사항
89
+ * Python 3.11+
90
+ * [uv](https://github.com/astral-sh/uv)
91
+ * Node.js 18+ 및 npm
92
+
93
+ ### 3.2 백엔드 (FastAPI & MCP Gateway) 실행
94
+ ```bash
95
+ # 가상환경 생성 및 의존성 설치
96
+ uv sync
97
+ uv pip install -e backend -e cli
98
+
99
+ # 백엔드 서버 기동 (기본 포트 8000)
100
+ uv run uvicorn ak5.main:app --host 127.0.0.1 --port 8000 --reload
101
+ ```
102
+ * **Swagger API 문서:** `http://127.0.0.1:8000/docs`
103
+ * **MCP SSE 엔드포인트:** `http://127.0.0.1:8000/mcp/sse`
104
+
105
+ ### 3.3 프론트엔드 (Next.js 15 Web Dashboard) 실행
106
+ ```bash
107
+ cd frontend
108
+ npm install
109
+ npm run dev
110
+ ```
111
+ * **웹 대시보드:** `http://localhost:3000`
112
+
113
+ ### 3.4 CLI (`ak5`) 도구 사용법
114
+ ```bash
115
+ # 1. 액터 등록 및 로그인
116
+ uv run ak5 login --id "agent_code_reviewer" --role "Senior Reviewer" --caps "python,rust,security"
117
+
118
+ # 2. 역량 기반 에이전트 검색
119
+ uv run ak5 agents --cap "image-resize"
120
+
121
+ # 3. 작업 위임 실행
122
+ uv run ak5 delegate TK-001 \
123
+ --to agent_image_worker \
124
+ --title "WebP 썸네일 변환기 구현" \
125
+ --desc "150x150 WebP 포맷 변환 함수 작성"
126
+
127
+ # 4. 실시간 터미널 칸반 뷰
128
+ uv run ak5 board --watch
129
+
130
+ # 5. 자율 멀티 에이전트 협업 데모 시뮬레이션 실행
131
+ uv run ak5 demo
132
+ ```
133
+
134
+ ---
135
+
136
+ ## 4. MCP (Model Context Protocol) 툴셋
137
+
138
+ 외부 에이전트(Claude Desktop, Cursor, LibrAgent 등)에서 다음 5가지 표준 툴을 호출하여 AK5 칸반을 직접 조작할 수 있습니다:
139
+
140
+ 1. `ak5_list_available_agents(capability, search_query)`: 가용 에이전트 역량 검색
141
+ 2. `ak5_delegate_subtask(parent_ticket_id, target_agent_id, title, description, priority)`: 하위 티켓 발급 및 에이전트 위임
142
+ 3. `ak5_get_ticket_context(ticket_id)`: 티켓 세부사항, 서브태스크 진척도, 최근 코멘트, 실행 맥락 조회
143
+ 4. `ak5_update_ticket_status(ticket_id, column_name, status_note, execution_context)`: 티켓 상태 전이 및 산출물 기록
144
+ 5. `ak5_report_block(ticket_id, blocking_reason, required_actor_id)`: 티켓 블록 처리 및 PM/담당자 멘션
145
+
146
+ ---
147
+
148
+ ## 5. 테스트 검증
149
+
150
+ ```bash
151
+ # 백엔드 및 CLI 전체 단위/통합 테스트 실행
152
+ uv run pytest backend/tests
153
+ ```
154
+ 19개의 모든 테스트 케이스(Lexorank 보간/리밸런싱, Actor 식별 및 검색, 티켓 수명주기, 계층형 서브태스크 위임, SSE 이벤트 버스, MCP 툴셋, CLI 명령어)가 통과합니다.
155
+
156
+ ---
157
+
158
+ ## 6. 사용방법 매뉴얼 & Agent Skill 안내
159
+
160
+ * **상세 사용자 및 운영 매뉴얼:** [MANUAL.md](../MANUAL.md) (또는 [docs/MANUAL.md](../docs/MANUAL.md))
161
+ * **에이전트 하네스용 Skill 정의:** [skills/ak5/SKILL.md](../skills/ak5/SKILL.md)
162
+ * Antigravity, Claude, Cursor 등의 자율 에이전트 하네스에서 `ak5` CLI 및 MCP 툴을 직접 호출하여 자율 분업을 수행할 수 있도록 절차와 러너 스크립트([harness_setup.sh](../skills/ak5/scripts/harness_setup.sh))가 포함되어 있습니다.
163
+
ak5-1.0.0/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # AK5 (Agent K5) — Agent-Orchestrated Kanban System
2
+
3
+ AK5는 인간 사용자(PM, 개발자)와 자율 AI 에이전트(LLM Agents)가 단일 칸반(K5) 인터페이스 위에서 실시간으로 협업하고 작업을 위임(Delegation) 및 추적하는 **Agent-Orchestrated Kanban 시스템**입니다.
4
+
5
+ ---
6
+
7
+ ## 1. 주요 특징
8
+
9
+ * **Actor 추상화 일원화 (Unified Actor Model):** 인간과 AI 에이전트를 동일한 `Actor` 인터페이스로 취급 (`user_pm`, `agent_image_worker` 등).
10
+ * **역량 기반 발견 및 위임 (Capability-driven Discovery & Delegation):** 에이전트 역량 태그(`image-resize`, `code-review`, `security` 등) 및 자연어 검색 기반으로 작업 위임.
11
+ * **듀얼 프로토콜 (REST + SSE + MCP):**
12
+ * **Web UI (Next.js 15):** 드래그 앤 드롭(`@dnd-kit`), SSE 실시간 보드 자동 동기화, 계층형 서브태스크 진행률 바 및 아코디언 토글, 에이전트 활동 펄스(Activity Glow).
13
+ * **AI Agents (MCP):** Model Context Protocol 표준 툴셋(`ak5_list_available_agents`, `ak5_delegate_subtask`, `ak5_get_ticket_context`, `ak5_update_ticket_status`, `ak5_report_block`).
14
+ * **CLI (`ak5`):** 터미널 환경에서 액터 로그인, 에이전트 검색, 서브태스크 위임, 실시간 터미널 칸반 뷰(`ak5 board --watch`), 협업 시뮬레이션 데모(`ak5 demo`).
15
+ * **동시성 및 순서 정렬 보장:** Lexorank 알고리즘(Base36)을 통한 충돌 없는 임의 순서 삽입, SQLite WAL 모드 + Busy Timeout 설정.
16
+
17
+ ---
18
+
19
+ ## 2. 프로젝트 디렉토리 레이아웃
20
+
21
+ ```
22
+ ak5/
23
+ ├── backend/ # FastAPI + MCP Server
24
+ │ ├── src/ak5/
25
+ │ │ ├── main.py # FastAPI 진입점 & Lifespan & MCP 마운트
26
+ │ │ ├── config.py # Pydantic Settings
27
+ │ │ ├── database.py # SQLite WAL 비동기 세션
28
+ │ │ ├── models/ # SQLAlchemy 2.0 모델 (Actor, Board, Column, Ticket, Audit)
29
+ │ │ ├── schemas/ # Pydantic v2 DTO 스키마
30
+ │ │ ├── services/ # Lexorank, Discovery, EventBus (SSE)
31
+ │ │ ├── routers/ # REST API (auth, actors, boards, tickets, events)
32
+ │ │ └── mcp/ # MCP Server (MCPServer, tools, client)
33
+ │ └── tests/ # Pytest 종합 단위/통합 테스트 (19개)
34
+ │
35
+ ├── frontend/ # Next.js 15 Web UI (React 18, Tailwind, @dnd-kit)
36
+ │ ├── src/
37
+ │ │ ├── app/ # App Router (layout.tsx, page.tsx, globals.css)
38
+ │ │ ├── components/
39
+ │ │ │ ├── board/ # KanbanBoard, KanbanColumn, TicketCard
40
+ │ │ │ └── actor/ # ActorBadge
41
+ │ │ └── lib/ # SSE 구독 및 API 클라이언트
42
+ │ └── package.json
43
+ │
44
+ ├── cli/ # ak5 터미널 도구
45
+ │ └── src/ak5_cli/
46
+ │ ├── main.py # Click CLI 엔트리포인트
47
+ │ ├── config.py # 세션 및 API URL 관리
48
+ │ └── commands/ # login, agents, delegate, board, demo
49
+ │
50
+ ├── docker-compose.yml # 컨테이너 오케스트레이션
51
+ └── pyproject.toml # uv 기반 워크스페이스 설정
52
+ ```
53
+
54
+ ---
55
+
56
+ ## 3. 실행 방법
57
+
58
+ ### 3.1 사전 요구사항
59
+ * Python 3.11+
60
+ * [uv](https://github.com/astral-sh/uv)
61
+ * Node.js 18+ 및 npm
62
+
63
+ ### 3.2 백엔드 (FastAPI & MCP Gateway) 실행
64
+ ```bash
65
+ # 가상환경 생성 및 의존성 설치
66
+ uv sync
67
+ uv pip install -e backend -e cli
68
+
69
+ # 백엔드 서버 기동 (기본 포트 8000)
70
+ uv run uvicorn ak5.main:app --host 127.0.0.1 --port 8000 --reload
71
+ ```
72
+ * **Swagger API 문서:** `http://127.0.0.1:8000/docs`
73
+ * **MCP SSE 엔드포인트:** `http://127.0.0.1:8000/mcp/sse`
74
+
75
+ ### 3.3 프론트엔드 (Next.js 15 Web Dashboard) 실행
76
+ ```bash
77
+ cd frontend
78
+ npm install
79
+ npm run dev
80
+ ```
81
+ * **웹 대시보드:** `http://localhost:3000`
82
+
83
+ ### 3.4 CLI (`ak5`) 도구 사용법
84
+ ```bash
85
+ # 1. 액터 등록 및 로그인
86
+ uv run ak5 login --id "agent_code_reviewer" --role "Senior Reviewer" --caps "python,rust,security"
87
+
88
+ # 2. 역량 기반 에이전트 검색
89
+ uv run ak5 agents --cap "image-resize"
90
+
91
+ # 3. 작업 위임 실행
92
+ uv run ak5 delegate TK-001 \
93
+ --to agent_image_worker \
94
+ --title "WebP 썸네일 변환기 구현" \
95
+ --desc "150x150 WebP 포맷 변환 함수 작성"
96
+
97
+ # 4. 실시간 터미널 칸반 뷰
98
+ uv run ak5 board --watch
99
+
100
+ # 5. 자율 멀티 에이전트 협업 데모 시뮬레이션 실행
101
+ uv run ak5 demo
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 4. MCP (Model Context Protocol) 툴셋
107
+
108
+ 외부 에이전트(Claude Desktop, Cursor, LibrAgent 등)에서 다음 5가지 표준 툴을 호출하여 AK5 칸반을 직접 조작할 수 있습니다:
109
+
110
+ 1. `ak5_list_available_agents(capability, search_query)`: 가용 에이전트 역량 검색
111
+ 2. `ak5_delegate_subtask(parent_ticket_id, target_agent_id, title, description, priority)`: 하위 티켓 발급 및 에이전트 위임
112
+ 3. `ak5_get_ticket_context(ticket_id)`: 티켓 세부사항, 서브태스크 진척도, 최근 코멘트, 실행 맥락 조회
113
+ 4. `ak5_update_ticket_status(ticket_id, column_name, status_note, execution_context)`: 티켓 상태 전이 및 산출물 기록
114
+ 5. `ak5_report_block(ticket_id, blocking_reason, required_actor_id)`: 티켓 블록 처리 및 PM/담당자 멘션
115
+
116
+ ---
117
+
118
+ ## 5. 테스트 검증
119
+
120
+ ```bash
121
+ # 백엔드 및 CLI 전체 단위/통합 테스트 실행
122
+ uv run pytest backend/tests
123
+ ```
124
+ 19개의 모든 테스트 케이스(Lexorank 보간/리밸런싱, Actor 식별 및 검색, 티켓 수명주기, 계층형 서브태스크 위임, SSE 이벤트 버스, MCP 툴셋, CLI 명령어)가 통과합니다.
125
+
126
+ ---
127
+
128
+ ## 6. 사용방법 매뉴얼 & Agent Skill 안내
129
+
130
+ * **상세 사용자 및 운영 매뉴얼:** [MANUAL.md](../MANUAL.md) (또는 [docs/MANUAL.md](../docs/MANUAL.md))
131
+ * **에이전트 하네스용 Skill 정의:** [skills/ak5/SKILL.md](../skills/ak5/SKILL.md)
132
+ * Antigravity, Claude, Cursor 등의 자율 에이전트 하네스에서 `ak5` CLI 및 MCP 툴을 직접 호출하여 자율 분업을 수행할 수 있도록 절차와 러너 스크립트([harness_setup.sh](../skills/ak5/scripts/harness_setup.sh))가 포함되어 있습니다.
133
+
@@ -0,0 +1,46 @@
1
+ [project]
2
+ name = "ak5"
3
+ version = "1.0.0"
4
+ description = "AK5: Agent-Orchestrated Kanban System Gateway, MCP Server & CLI"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.11"
8
+ authors = [
9
+ { name = "AK5 Team" }
10
+ ]
11
+ keywords = ["kanban", "ai-agents", "mcp", "orchestration", "multi-agent", "fastapi"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
21
+ ]
22
+ dependencies = [
23
+ "fastapi>=0.115.0",
24
+ "uvicorn[standard]>=0.30.0",
25
+ "sqlalchemy>=2.0.30",
26
+ "aiosqlite>=0.20.0",
27
+ "pydantic>=2.8.0",
28
+ "pydantic-settings>=2.4.0",
29
+ "pyjwt>=2.9.0",
30
+ "httpx>=0.27.0",
31
+ "sse-starlette>=2.1.0",
32
+ "mcp>=1.0.0",
33
+ "click>=8.1.0",
34
+ "rich>=13.7.0",
35
+ ]
36
+
37
+ [project.scripts]
38
+ ak5 = "ak5.cli.main:cli"
39
+ ak5-mcp = "ak5.mcp.server:main"
40
+
41
+ [build-system]
42
+ requires = ["hatchling"]
43
+ build-backend = "hatchling.build"
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = ["src/ak5"]
@@ -0,0 +1,3 @@
1
+ """AK5 (Agent K5) - Agent-Orchestrated Kanban System."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,3 @@
1
+ """AK5 CLI - Terminal tool for Agent-Orchestrated Kanban."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,55 @@
1
+ import click
2
+ import httpx
3
+ from ak5.cli.config import get_api_url
4
+ from rich.console import Console
5
+ from rich.table import Table
6
+
7
+ console = Console()
8
+
9
+
10
+ @click.command("agents")
11
+ @click.option("--cap", default=None, help="Filter by capability tag (e.g. 'image-resize')")
12
+ @click.option("--status", default=None, help="Filter by status ('idle', 'busy', 'offline')")
13
+ @click.option("--query", default=None, help="Semantic search query")
14
+ def agents_command(cap: str | None, status: str | None, query: str | None) -> None:
15
+ """Discover agents matching capability tags or search queries."""
16
+ api_url = get_api_url()
17
+ params = {}
18
+ if cap:
19
+ params["capability"] = cap
20
+ if status:
21
+ params["status"] = status
22
+ if query:
23
+ params["query"] = query
24
+
25
+ try:
26
+ with httpx.Client(timeout=10.0) as client:
27
+ resp = client.get(f"{api_url}/actors/discovery", params=params)
28
+ resp.raise_for_status()
29
+ agents = resp.json()
30
+
31
+ if not agents:
32
+ console.print("[yellow]No matching agents found.[/yellow]")
33
+ return
34
+
35
+ table = Table(title="Available Autonomous AI Agents", show_lines=True)
36
+ table.add_column("Agent ID", style="cyan", no_wrap=True)
37
+ table.add_column("Role", style="magenta")
38
+ table.add_column("Status", style="green")
39
+ table.add_column("Capabilities", style="yellow")
40
+
41
+ for a in agents:
42
+ caps_str = ", ".join(a.get("capabilities", []))
43
+ status_color = "green" if a["status"] == "idle" else ("yellow" if a["status"] == "busy" else "red")
44
+ table.add_row(
45
+ f"@{a['actor_id']}",
46
+ a["role"],
47
+ f"[{status_color}]{a['status']}[/{status_color}]",
48
+ caps_str,
49
+ )
50
+
51
+ console.print(table)
52
+ except httpx.ConnectError:
53
+ console.print(f"[bold red]✗ Failed to connect to AK5 Gateway at {api_url}[/bold red]")
54
+ except Exception as e:
55
+ console.print(f"[bold red]✗ Error querying agents:[/bold red] {e}")
@@ -0,0 +1,122 @@
1
+ import asyncio
2
+
3
+ import click
4
+ import httpx
5
+ from ak5.cli.config import get_api_url
6
+ from rich.console import Console
7
+ from rich.live import Live
8
+ from rich.panel import Panel
9
+ from rich.table import Table
10
+ from rich.text import Text
11
+
12
+ console = Console()
13
+
14
+
15
+ def render_board_view(board_data: dict) -> Table:
16
+ """Render 4-column Kanban board as a Rich Table."""
17
+ main_table = Table(
18
+ title=f"📋 Kanban Board: {board_data['name']} ({board_data['board_id']})",
19
+ show_header=True,
20
+ header_style="bold cyan",
21
+ expand=True,
22
+ )
23
+
24
+ stage_colors = {
25
+ "open": "blue",
26
+ "in_progress": "yellow",
27
+ "review": "magenta",
28
+ "done": "green",
29
+ }
30
+
31
+ # Add column headers
32
+ for col in board_data.get("columns", []):
33
+ color = stage_colors.get(col.get("stage"), "white")
34
+ count = len(col.get("tickets", []))
35
+ wip_info = f" [WIP: {count}/{col['wip_limit']}]" if col.get("wip_limit", 0) > 0 else f" ({count})"
36
+ main_table.add_column(f"[{color}]{col['name']}{wip_info}[/{color}]")
37
+
38
+ # Find maximum number of rows among columns
39
+ max_tickets = max(len(col.get("tickets", [])) for col in board_data.get("columns", [])) if board_data.get("columns") else 0
40
+
41
+ if max_tickets == 0:
42
+ empty_row = [Panel("[dim](Empty)[/dim]", expand=True) for _ in board_data.get("columns", [])]
43
+ main_table.add_row(*empty_row)
44
+ return main_table
45
+
46
+ for row_idx in range(max_tickets):
47
+ row_cells = []
48
+ for col in board_data.get("columns", []):
49
+ tickets = col.get("tickets", [])
50
+ if row_idx < len(tickets):
51
+ t = tickets[row_idx]
52
+ p_color = "red" if t["priority"] in ("urgent", "high") else ("yellow" if t["priority"] == "medium" else "dim")
53
+ status_badge = f"[{p_color}][{t['priority'].upper()}][/{p_color}]"
54
+
55
+ assignee = f"@{t['assigned_to']}" if t.get("assigned_to") else "[dim]Unassigned[/dim]"
56
+
57
+ subtask_badge = ""
58
+ if t.get("subtask_count", 0) > 0:
59
+ subtask_badge = f"\n[bold cyan]Subtasks: {t['subtask_done_count']}/{t['subtask_count']} Done[/bold cyan]"
60
+
61
+ content = (
62
+ f"[bold white]{t['title']}[/bold white]\n"
63
+ f"{status_badge} [dim]{t['ticket_id']}[/dim] | {assignee}"
64
+ f"{subtask_badge}"
65
+ )
66
+
67
+ border_color = "yellow" if col.get("stage") == "in_progress" else "white"
68
+ row_cells.append(Panel(content, border_style=border_color, expand=True))
69
+ else:
70
+ row_cells.append(Text(""))
71
+ main_table.add_row(*row_cells)
72
+
73
+ return main_table
74
+
75
+
76
+ def fetch_board(api_url: str, board_id: str) -> dict:
77
+ with httpx.Client(timeout=10.0) as client:
78
+ resp = client.get(f"{api_url}/boards/{board_id}")
79
+ resp.raise_for_status()
80
+ return resp.json()
81
+
82
+
83
+ async def watch_board_live(api_url: str, board_id: str) -> None:
84
+ """Stream SSE events and re-render board on changes."""
85
+ console.print(f"[bold cyan]Connecting to real-time event stream for board '{board_id}'...[/bold cyan]")
86
+ board_data = fetch_board(api_url, board_id)
87
+
88
+ with Live(render_board_view(board_data), console=console, refresh_per_second=4) as live:
89
+ async with (
90
+ httpx.AsyncClient(timeout=None) as client,
91
+ client.stream("GET", f"{api_url}/events/stream") as stream,
92
+ ):
93
+ async for line in stream.aiter_lines():
94
+ if line.startswith("event:"):
95
+ event_type = line.split(":", 1)[1].strip()
96
+ if event_type in ("TICKET_CREATED", "TICKET_MOVED", "TICKET_DELEGATED", "TICKET_UPDATED", "COMMENT_ADDED"):
97
+ # Refresh board
98
+ try:
99
+ board_data = fetch_board(api_url, board_id)
100
+ live.update(render_board_view(board_data))
101
+ except (httpx.HTTPError, OSError):
102
+ pass
103
+
104
+
105
+ @click.command("board")
106
+ @click.option("--board-id", default="proj-core-engine", help="Target Board ID")
107
+ @click.option("--watch", is_flag=True, help="Watch board with live real-time SSE updates")
108
+ def board_command(board_id: str, watch: bool) -> None:
109
+ """View Kanban board in terminal."""
110
+ api_url = get_api_url()
111
+ try:
112
+ if watch:
113
+ asyncio.run(watch_board_live(api_url, board_id))
114
+ else:
115
+ board_data = fetch_board(api_url, board_id)
116
+ console.print(render_board_view(board_data))
117
+ except httpx.ConnectError:
118
+ console.print(f"[bold red]✗ Failed to connect to AK5 Gateway at {api_url}[/bold red]")
119
+ except httpx.HTTPStatusError as e:
120
+ console.print(f"[bold red]✗ Board query failed ({e.response.status_code}):[/bold red] {e.response.text}")
121
+ except KeyboardInterrupt:
122
+ console.print("\n[yellow]Watch stopped.[/yellow]")
@@ -0,0 +1,66 @@
1
+ import click
2
+ import httpx
3
+ from ak5.cli.config import get_api_url, get_token
4
+ from rich.console import Console
5
+
6
+ console = Console()
7
+
8
+
9
+ @click.command("delegate")
10
+ @click.argument("ticket_id")
11
+ @click.option("--to", "target_actor_id", required=True, help="Target Agent ID to delegate task to")
12
+ @click.option("--title", required=True, help="Subtask title")
13
+ @click.option("--desc", "description", default="", help="Subtask detailed description")
14
+ @click.option("--priority", type=click.Choice(["low", "medium", "high", "urgent"]), default="medium")
15
+ def delegate_command(
16
+ ticket_id: str,
17
+ target_actor_id: str,
18
+ title: str,
19
+ description: str,
20
+ priority: str,
21
+ ) -> None:
22
+ """Delegate a subtask to an agent under an existing parent ticket."""
23
+ api_url = get_api_url()
24
+ token = get_token()
25
+
26
+ headers = {}
27
+ if token:
28
+ headers["Authorization"] = f"Bearer {token}"
29
+ else:
30
+ # Auto-login as orchestrator if not logged in
31
+ with httpx.Client(timeout=5.0) as client:
32
+ resp = client.post(
33
+ f"{api_url}/auth/identify",
34
+ json={"actor_id": "cli_user", "actor_type": "human", "name": "CLI User", "role": "PM"},
35
+ )
36
+ if resp.is_success:
37
+ headers["Authorization"] = f"Bearer {resp.json()['access_token']}"
38
+
39
+ payload = {
40
+ "target_actor_id": target_actor_id,
41
+ "subtask_title": title,
42
+ "subtask_description": description,
43
+ "priority": priority,
44
+ "labels": ["delegated", "cli"],
45
+ }
46
+
47
+ try:
48
+ with httpx.Client(timeout=10.0) as client:
49
+ resp = client.post(
50
+ f"{api_url}/tickets/{ticket_id}/delegate",
51
+ json=payload,
52
+ headers=headers,
53
+ )
54
+ resp.raise_for_status()
55
+ subtask = resp.json()
56
+
57
+ console.print(
58
+ f"[bold green]✓[/bold green] Subtask [cyan]{subtask['ticket_id']}[/cyan] created and assigned to "
59
+ f"[magenta]@{target_actor_id}[/magenta] (Parent: [yellow]{ticket_id}[/yellow])"
60
+ )
61
+ except httpx.ConnectError:
62
+ console.print(f"[bold red]✗ Failed to connect to AK5 Gateway at {api_url}[/bold red]")
63
+ except httpx.HTTPStatusError as e:
64
+ console.print(f"[bold red]✗ Delegation failed ({e.response.status_code}):[/bold red] {e.response.text}")
65
+ except Exception as e:
66
+ console.print(f"[bold red]✗ Error:[/bold red] {e}")