# Phase 10: Extract remaining kollabor/llm/ business logic

status: COMPLETE
created: 2026-02-17
completed: 2026-02-17

## Context

After phases 0-9, kollabor/llm/ still has ~1,770 lines of reusable
business logic that should live in packages. The worst offender is
permissions/models.py -- kollabor_tui/render_layout.py imports from
it, creating a backwards dependency (package importing from app layer).

## What moves where

```
  file                          dest package          lines
  ----------------------------  -----------------     -----
  permissions/models.py         kollabor-events         253
  permissions/config.py         kollabor-events          46
  permissions/risk_assessor.py  kollabor-agent          110
  permissions/response_handler  kollabor-agent          106
  permissions/manager.py        kollabor-agent          672
  plugin_sdk.py                 kollabor-plugins        423
  background_task_manager.py    kollabor-agent          498
                                                      -----
                                                      2,108
```

## What stays in kollabor/llm/

```
  file                          reason               lines
  ----------------------------  -------------------  -----
  llm_service.py                orchestration facade  1,075
  hook_system.py                event bus wiring        426
  message_handler.py            event glue              369
  message_display_service.py    renderer adapter        379
  session_manager.py            5-object orchestrator   228
  status_service.py             task_mgr internals      236
  streaming_handler.py          bridges 3 app objects   177
  permissions/hook.py           event bus wiring        100
  permissions/__init__.py       re-exports (update)      51
  __init__.py                   re-exports (update)      11
                                                      -----
                                                      3,052
```

## Execution order

### 10A: permissions/ -> split across kollabor-events + kollabor-agent (1,187 lines)

the split:
  - models.py + config.py -> kollabor-events (shared data types, 299 lines)
  - risk_assessor.py + response_handler.py + manager.py -> kollabor-agent (888 lines)

this keeps kollabor-tui lightweight (new dep on kollabor-events, not kollabor-agent)

step 1: models.py + config.py -> kollabor-events

  create packages/kollabor-events/src/kollabor_events/permissions_models.py
    - copy models.py content (no changes, stdlib only)
  create packages/kollabor-events/src/kollabor_events/permissions_config.py
    - copy config.py content (no changes)
  update kollabor_events/__init__.py to export permission types
  add kollabor-events as dep of kollabor-tui in pyproject.toml

step 2: business logic -> kollabor-agent

  create packages/kollabor-agent/src/kollabor_agent/permissions/
  copy into it:
    - risk_assessor.py (fix import: from .models -> from kollabor_events.permissions_models)
    - response_handler.py (fix imports: .models -> kollabor_events.permissions_models, .manager stays relative)
    - manager.py (fix imports: .models -> kollabor_events.permissions_models,
                   `from ...utils.config_utils` -> `from kollabor_config.config_utils`)
  create permissions/__init__.py re-exporting public API
  add kollabor-config as dep of kollabor-agent in pyproject.toml

step 3: fix render_layout.py backwards import

  packages/kollabor-tui/src/kollabor_tui/render_layout.py lines 755, 812:
    from kollabor.llm.permissions.models import ConfirmationResponse
    -> from kollabor_events.permissions_models import ConfirmationResponse

step 4: update app-layer importers

  kollabor/application.py (lines 307-313, 355):
    - PermissionManager, RiskAssessor -> from kollabor_agent.permissions import ...
    - RiskAssessmentRules -> from kollabor_events.permissions_models import ...
    - PERMISSION_CONFIG_DEFAULTS -> from kollabor_events.permissions_config import ...
    - handle_confirmation_response -> from kollabor_agent.permissions import ...
  kollabor/commands/system_commands/handlers/system.py (3 lazy imports):
    from ....llm.permissions.models import ApprovalMode
    -> from kollabor_events.permissions_models import ApprovalMode
  kollabor/llm/permissions/hook.py (stays, update manager import):
    from .manager import PermissionManager
    -> from kollabor_agent.permissions import PermissionManager
  kollabor/llm/permissions/__init__.py: slim down to re-export from both packages

step 5: delete old files

  - kollabor/llm/permissions/models.py
  - kollabor/llm/permissions/config.py
  - kollabor/llm/permissions/risk_assessor.py
  - kollabor/llm/permissions/response_handler.py
  - kollabor/llm/permissions/manager.py

add dep: kollabor-agent pyproject.toml needs "kollabor-config" in dependencies
add dep: kollabor-tui pyproject.toml needs "kollabor-events" in dependencies

### 10B: plugin_sdk.py -> kollabor-plugins (423 lines)

moves:
  1. copy kollabor/llm/plugin_sdk.py -> packages/kollabor-plugins/src/kollabor_plugins/plugin_sdk.py
  2. no import changes needed inside the file (stdlib only)
  3. add KollaborPluginSDK to kollabor_plugins/__init__.py exports

update importers:
  - kollabor/llm/__init__.py: remove KollaborPluginSDK re-export
  - kollabor/application.py: from kollabor_plugins import KollaborPluginSDK
  - plugins/hook_monitoring_plugin.py: from kollabor_plugins import KollaborPluginSDK

delete: kollabor/llm/plugin_sdk.py

### 10C: background_task_manager.py -> kollabor-agent (498 lines)

moves:
  1. copy kollabor/llm/background_task_manager.py -> packages/kollabor-agent/src/kollabor_agent/background_task_manager.py
  2. no import changes needed inside the file (only dep is kollabor_config.LLMTaskConfig, already clean)
  3. add BackgroundTaskManager to kollabor_agent/__init__.py exports

update importers:
  - kollabor/llm/llm_service.py: from kollabor_agent import BackgroundTaskManager
  - tests/unit/llm/test_background_task_manager.py: from kollabor_agent import BackgroundTaskManager
  - tests/unit/llm/test_task_management.py: from kollabor_agent import BackgroundTaskManager

delete: kollabor/llm/background_task_manager.py

### 10D: cleanup

  - delete kollabor/llm/providers/ if it still exists (stale __pycache__ + coverage artifact)
  - verify: grep for any remaining "from kollabor.llm.permissions" (except hook.py + __init__.py)
  - verify: grep for any remaining "from kollabor.llm.plugin_sdk"
  - verify: grep for any remaining "from kollabor.llm.background_task"
  - uv sync
  - run tests

## After phase 10

```
  kollabor/llm/:     ~3,052 lines (was 5,160, -41%)
  kollabor-agent:    ~9,197 lines (was 7,089, +2,108)
  kollabor-plugins:  ~1,916 lines (was 1,493, +423)
  kollabor-events:   ~2,779 lines (was 2,480, +299)
```

## Verification

  1. uv sync succeeds
  2. uv run python -c "from kollabor_agent.permissions import PermissionManager, RiskAssessor"
  3. uv run python -c "from kollabor_events.permissions_models import ConfirmationResponse, ApprovalMode"
  4. uv run python -c "from kollabor_agent import BackgroundTaskManager"
  5. uv run python -c "from kollabor_plugins import KollaborPluginSDK"
  6. uv run python -m pytest tests/ (full suite)
  7. grep confirms zero remaining old-path imports
  8. uv run kollab --version works
