# Work P0 Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add the P0 `loushang.work` shell around the existing coding fast path.

**Architecture:** Add a small `loushang.work` package with stable dataclass models, an in-memory event log backend, and projection helpers from current `AgentEvent`/coding session events to `WorkEvent`. Keep `AgentSession` unchanged for P0; the work shell wraps and observes it rather than moving prompt/tool/session responsibilities.

**Tech Stack:** Python 3.11+, dataclasses, `TypedDict`-style JSON-compatible payloads, pytest, existing `loushang.agent` and `loushang.coding.event` types.

---

### Task 1: Core Work Types

**Files:**
- Create: `src/loushang/work/__init__.py`
- Create: `src/loushang/work/types.py`
- Test: `tests/work/test_work_types.py`

- [x] **Step 1: Write failing tests for P0 dataclass defaults**

Test `WorkOperation`, `WorkRun`, `WorkEvent`, and delivery hints with JSON-compatible payloads.

- [x] **Step 2: Run tests to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_work_types.py -q`

Expected: import failure for `loushang.work`.

- [x] **Step 3: Implement minimal types**

Create frozen dataclasses and literal aliases. Do not add multi-agent public APIs.

- [x] **Step 4: Run tests to verify GREEN**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_work_types.py -q`

- [x] **Step 5: Commit**

Commit message: `feat: add work p0 core types`

### Task 2: EventLogBackend

**Files:**
- Create: `src/loushang/work/event_log.py`
- Modify: `src/loushang/work/__init__.py`
- Test: `tests/work/test_event_log.py`

- [x] **Step 1: Write failing tests for append/query/subscribe**

Cover append position ordering, query by run/session, and async subscribe receiving later entries.

- [x] **Step 2: Run tests to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_event_log.py -q`

- [x] **Step 3: Implement in-memory backend**

Create `EventLogEntry`, `EventPosition`, `EventLogBackend` protocol, and `InMemoryEventLogBackend`.

- [x] **Step 4: Run tests to verify GREEN**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_event_log.py -q`

- [x] **Step 5: Commit**

Commit message: `feat: add work event log backend`

### Task 3: AgentEvent To WorkEvent Projection

**Files:**
- Create: `src/loushang/work/projection.py`
- Modify: `src/loushang/work/__init__.py`
- Test: `tests/work/test_agent_event_projection.py`

- [x] **Step 1: Write failing projection tests**

Cover `agent_start`, `agent_end`, `message_update`, `tool_execution_start`, `tool_execution_end`, and `queue_update`.

- [x] **Step 2: Run tests to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_agent_event_projection.py -q`

- [x] **Step 3: Implement projection helpers**

Add pure functions that accept metadata plus `AgentEvent`/coding session event and return one or more `WorkEvent` values.

- [x] **Step 4: Run tests to verify GREEN**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_agent_event_projection.py -q`

- [x] **Step 5: Commit**

Commit message: `feat: project agent events to work events`

### Task 4: Coding Work Shell

**Files:**
- Create: `src/loushang/work/coding.py`
- Modify: `src/loushang/work/__init__.py`
- Test: `tests/work/test_coding_work_shell.py`

- [x] **Step 1: Write failing wrapper tests**

Use a fake promptable session with `prompt()` and `subscribe()` to verify `SubmitCodingTurn` creates a `WorkRun`, appends operation/run/events, calls prompt once, and projects emitted events.

- [x] **Step 2: Run tests to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_coding_work_shell.py -q`

- [x] **Step 3: Implement minimal `CodingWorkShell`**

Keep it independent from concrete `AgentSession` construction. Accept a promptable/subscribable session object and an `EventLogBackend`.

- [x] **Step 4: Run tests to verify GREEN**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_coding_work_shell.py -q`

- [x] **Step 5: Commit**

Commit message: `feat: add coding work shell`

### Task 5: Public Surface And Focused Regression

**Files:**
- Modify: `src/loushang/work/__init__.py`
- Create: `tests/work/test_public_api.py`

- [x] **Step 1: Write failing public API test**

Assert the P0 public exports are available and do not include `AgentLane`, `TaskLedger`, or `CollaborationBus`.

- [x] **Step 2: Run test to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_public_api.py -q`

- [x] **Step 3: Update exports**

Export only the P0 surface.

- [x] **Step 4: Run focused suite**

Run:

```bash
uv --cache-dir .uv-cache run --extra dev pytest tests/work tests/agent/test_public_api.py tests/coding/test_session_events.py tests/coding/test_session_event_bus.py tests/coding/test_workflow_events.py -q
uv --cache-dir .uv-cache run ruff check src/loushang/work tests/work
```

- [x] **Step 5: Commit**

Commit message: `test: cover work p0 public surface`

### Task 6: Optional Print Mode Work Logging

**Files:**
- Modify: `src/loushang/coding/mode/print_mode.py`
- Modify: `src/loushang/work/coding.py`
- Test: `tests/coding/test_print_mode.py`

- [x] **Step 1: Write failing print-mode integration test**

Verify `PrintMode` can optionally route prompts through `CodingWorkShell`, append `WorkEvent` entries to a caller-provided event log, preserve existing stdout behavior, and keep image arguments intact.

- [x] **Step 2: Run test to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_print_mode.py -k work_event_log -q`

- [x] **Step 3: Implement optional work logging path**

Add an optional event log parameter to print mode and route prompt execution through `CodingWorkShell` only when provided. Keep the default path unchanged.

- [x] **Step 4: Run focused suite**

Run:

```bash
uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_print_mode.py tests/work -q
uv --cache-dir .uv-cache run ruff check src/loushang/work src/loushang/coding/mode/print_mode.py tests/work tests/coding/test_print_mode.py
```

- [x] **Step 5: Commit**

Commit message: `feat: wire print mode to work shell`

### Task 7: JSONL Event Log Persistence And Replay Smoke

**Files:**
- Modify: `src/loushang/work/event_log.py`
- Modify: `src/loushang/work/__init__.py`
- Test: `tests/work/test_event_log.py`
- Test: `tests/work/test_coding_work_shell.py`

- [x] **Step 1: Write failing JSONL backend tests**

Cover append positions, query by run/session, `after` replay, reopening from disk, and subscribe replay/stream behavior.

- [x] **Step 2: Run tests to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/work/test_event_log.py -k jsonl -q`

Expected: import failure for `JsonlEventLogBackend`.

- [x] **Step 3: Implement minimal JSONL backend**

Add `JsonlEventLogBackend` with one JSON object per line. Normalize payload values into JSON-safe data at append time. Keep `EventLogBackend` unchanged.

- [x] **Step 4: Add work-shell replay smoke test**

Use `CodingWorkShell` with `JsonlEventLogBackend`, run a fake coding turn, reopen the log, and assert the persisted WorkOperation/WorkEvent sequence is replayable.

- [x] **Step 5: Run focused suite**

Run:

```bash
uv --cache-dir .uv-cache run --extra dev pytest tests/work tests/coding/test_print_mode.py -q
uv --cache-dir .uv-cache run ruff check src/loushang/work tests/work
```

- [x] **Step 6: Manual verification commands**

From the branch worktree:

```bash
cd /home/dev/workspace/loushang/.worktrees/work-p0-28
uv --cache-dir .uv-cache run loushang --help
uv --cache-dir .uv-cache run --extra dev pytest tests/work tests/coding/test_print_mode.py -q
```

No-provider smoke for the work log path:

```bash
uv --cache-dir .uv-cache run --extra dev python - <<'PY'
import asyncio
from datetime import UTC, datetime
from pathlib import Path
from tempfile import TemporaryDirectory

from loushang.work import CodingWorkShell, JsonlEventLogBackend

class FakeSession:
    def __init__(self):
        self.listeners = []

    def subscribe(self, listener):
        self.listeners.append(listener)
        return lambda: self.listeners.remove(listener)

    async def prompt(self, text):
        for listener in list(self.listeners):
            result = listener({
                "type": "message_update",
                "message": {"role": "assistant"},
                "assistant_message_event": {"type": "text_delta", "text": "ok"},
            })
            if result is not None:
                await result

async def main():
    with TemporaryDirectory() as tmp:
        path = Path(tmp) / "events.jsonl"
        shell = CodingWorkShell(
            session=FakeSession(),
            event_log=JsonlEventLogBackend(path),
            clock=lambda: datetime(2026, 6, 1, tzinfo=UTC),
        )
        run = await shell.submit_coding_turn("hello", session_id="manual", run_id="run-manual")
        entries = JsonlEventLogBackend(path).query(run_id=run.run_id)
        print(run.status)
        print([entry.payload["kind"] for entry in entries])

asyncio.run(main())
PY
```

Expected output includes `completed` and the persisted event kinds.

- [x] **Step 7: Commit**

Commit message: `feat: add jsonl work event log`

### Task 8: CLI Work Log Switch

**Files:**
- Modify: `src/loushang/coding/cli/args.py`
- Modify: `src/loushang/coding/cli/__main__.py`
- Modify: `src/loushang/coding/mode/base.py`
- Modify: `src/loushang/coding/prompt_command.py`
- Test: `tests/coding/test_cli.py`
- Test: `tests/coding/test_print_mode.py`
- Test: `tests/coding/test_prompt_command.py`

- [x] **Step 1: Write failing CLI tests**

Cover `--work-log PATH` parsing, prompt-command injection, print runner injection, default unified mode runner injection, and unsupported TUI/RPC/workflow paths.

- [x] **Step 2: Run tests to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_cli.py -k work_log -q`

Expected: parse failure or missing `work_log` attribute.

- [x] **Step 3: Implement CLI argument and backend wiring**

Add `CliArgs.work_log`, parser support, builtin flag registration, and a helper that resolves relative paths under the project root into `JsonlEventLogBackend`.

- [x] **Step 4: Pass work log through mode adapter**

Add optional `work_event_log` plumbing through `run_mode()` / `create_mode_adapter()` into `PrintMode`.

- [x] **Step 5: Add mode-level regression**

Verify `run_mode(..., work_event_log=InMemoryEventLogBackend())` routes through `PrintMode` and records work events.

- [x] **Step 6: Run focused suite**

Run:

```bash
uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_cli.py -k "work_log or default_path_uses_unified_mode_runner or mode_print_dispatches_print_adapter" -q
uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_print_mode.py tests/work -q
uv --cache-dir .uv-cache run ruff check src/loushang/coding/cli src/loushang/coding/mode src/loushang/work tests/coding/test_cli.py tests/coding/test_print_mode.py tests/work
```

- [x] **Step 7: Manual verification**

From the branch worktree:

```bash
cd /home/dev/workspace/loushang/.worktrees/work-p0-28
uv --cache-dir .uv-cache run loushang --help | rg -- --work-log
uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_cli.py -k work_log -q
```

With a configured provider/model, run:

```bash
uv --cache-dir .uv-cache run loushang --mode text --work-log .loushang/work/events.jsonl --prompt "hello"
```

Then inspect:

```bash
python - <<'PY'
from pathlib import Path
from loushang.work import JsonlEventLogBackend

entries = JsonlEventLogBackend(Path(".loushang/work/events.jsonl")).query(limit=20)
print([entry.payload["kind"] for entry in entries])
PY
```

- [x] **Step 8: Commit**

Commit message: `feat: add cli work log switch`

### Task 9: CLI Work Log Inspect Command

**Files:**
- Modify: `src/loushang/coding/cli/args.py`
- Modify: `src/loushang/coding/cli/__main__.py`
- Test: `tests/coding/test_cli.py`

- [x] **Step 1: Write failing CLI inspect tests**

Cover `--work-log-inspect PATH` parsing, text summary output, JSON summary output, run filtering, and no runtime/session startup.

- [x] **Step 2: Run tests to verify RED**

Run: `uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_cli.py -k work_log_inspect -q`

Expected: parse failure or missing `work_log_inspect` attribute.

- [x] **Step 3: Implement inspect arguments and read-only command**

Add `CliArgs.work_log_inspect`, `CliArgs.work_log_run`, and `CliArgs.work_log_inspect_format`. Implement a read-only command that opens `JsonlEventLogBackend`, queries recent entries, and renders `sequence`, `kind`, `run_id`, `session_id`, and `delivery_hint` in text or JSON.

- [x] **Step 4: Run focused suite**

Run:

```bash
uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_cli.py -k "work_log_inspect or work_log" -q
uv --cache-dir .uv-cache run --extra dev pytest tests/coding/test_cli.py tests/coding/test_prompt_command.py tests/coding/test_print_mode.py tests/work -q
uv --cache-dir .uv-cache run ruff check src/loushang/coding/cli/args.py src/loushang/coding/cli/__main__.py tests/coding/test_cli.py
```

- [x] **Step 5: Manual verification**

From the branch worktree:

```bash
uv --cache-dir .uv-cache run loushang --help | rg -- --work-log-inspect
uv --cache-dir .uv-cache run loushang --work-log-inspect .loushang/work/events.jsonl
uv --cache-dir .uv-cache run loushang --work-log-inspect .loushang/work/events.jsonl --work-log-inspect-format json
```

- [x] **Step 6: Commit**

Commit message: `feat: add work log inspect command`
