# Zhihu Hotlist To Excel Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Make sgClaw reliably read Zhihu hotlist data through a Zhihu browser skill and export the collected structured result into a local `.xlsx` file through an independent Office skill.

**Architecture:** Keep zeroclaw as the core planner, but stop it from wandering across unrelated tools once a browser-attached skill is selected. The hotlist skill must produce a strict structured artifact, and the Office skill must consume that artifact through a dedicated `openxml_office` tool that wraps the sibling `openxml_cli` project. For the first delivery, reuse `openxml_cli template render` with a bundled `.xlsx` template instead of inventing a new workbook-construction API.

**Tech Stack:** Rust, vendored zeroclaw, sgClaw browser pipe, skill packages under `/home/zyl/projects/sgClaw/skill_lib`, sibling `openxml_cli`, JSON payload handoff, `.xlsx` template render, Python/Rust regression tests, real-provider smoke verification.

## Scope Guard

- In scope:
  - browser-attached skill execution discipline
  - `zhihu-hotlist` structured export artifact
  - new `office-export-xlsx` skill
  - new `openxml_office` runtime tool
  - end-to-end acceptance for "读取知乎热榜数据，并导出 excel 文件"
- Out of scope:
  - generic Office authoring platform
  - arbitrary shell-based export flows
  - browser-side file generation as the main export path
  - broad multi-site data export before Zhihu hotlist is stable

## Current Findings To Preserve

- Real-provider validation already proved that `zhihu-hotlist`, `zhihu-navigate`, and `zhihu-write` can be selected through `read_skill`.
- The current failure mode is not "skill missing" but "tool discipline collapse":
  - `file_read`, `glob_search`, and `shell` are attempted after `read_skill`
  - `zhihu-write` can fill title/body but still exceeds max tool iterations
  - `zhihu-navigate` succeeds for some intents but still detours through non-browser tools
- The sibling Office project already exists at `/home/zyl/projects/sgClaw/openxml_cli`.
- `openxml_cli` currently exposes `capabilities`, `template inspect`, `template validate`, and `template render`; it does not yet expose a direct "create workbook from scratch" command.

## Final Acceptance Contract

Input:

```text
读取知乎热榜数据，并导出 excel 文件
```

Required behavior:

1. sgClaw selects `zhihu-hotlist`.
2. sgClaw gathers hotlist rows through the SuperRPA browser interface only.
3. sgClaw converts the result into a structured JSON export payload.
4. sgClaw selects `office-export-xlsx`.
5. sgClaw calls `openxml_office`.
6. A local `.xlsx` file is produced and its path is returned.

Required logs:

- `read_skill zhihu-hotlist`
- browser actions only: `navigate`, `getText`, optionally `click`
- `read_skill office-export-xlsx`
- `call openxml_office`

Forbidden logs during the mainline path:

- `call shell`
- `call glob_search`
- `call file_read` on skill references or skill roots
- `docker run`

Required Excel content:

- one sheet named `知乎热榜`
- columns: `rank`, `title`, `heat`
- at least 10 hotlist rows
- exported values match the collected rows

## Task 1: Lock Browser-Attached Skill Runs To The Right Tools

**Files:**
- Modify: `/home/zyl/projects/sgClaw/claw/tests/compat_runtime_test.rs`
- Modify: `/home/zyl/projects/sgClaw/claw/src/runtime/engine.rs`
- Modify: `/home/zyl/projects/sgClaw/claw/src/runtime/tool_policy.rs`
- Modify: `/home/zyl/projects/sgClaw/claw/src/compat/runtime.rs`

**Intent:**
- Once the task is clearly in a browser-attached Zhihu skill flow, the runtime must stop offering unrelated tools such as `shell`, `glob_search`, and arbitrary `file_read`.

**Step 1: Write the failing regression tests**

Add focused tests in `tests/compat_runtime_test.rs` for:

```rust
#[test]
fn zhihu_hotlist_skill_flow_does_not_expose_shell_or_glob_tools() {}

#[test]
fn browser_attached_export_flow_exposes_browser_and_office_tools_only() {}
```

Assertions to include:

- request tool list contains `superrpa_browser`
- request tool list contains `read_skill`
- request tool list does not contain `shell`
- request tool list does not contain `glob_search`
- request tool list does not contain generic `file_read` during the constrained browser skill phase

**Step 2: Run the focused tests to verify failure**

Run:

```bash
cargo test --test compat_runtime_test zhihu_hotlist_skill_flow_does_not_expose_shell_or_glob_tools -- --nocapture
cargo test --test compat_runtime_test browser_attached_export_flow_exposes_browser_and_office_tools_only -- --nocapture
```

Expected:
- fail because current runtime still exposes too many tools in browser-attached mode

**Step 3: Implement minimal constrained-tool policy**

Implement a browser-skill execution mode that:

- keeps `superrpa_browser`
- keeps compatibility alias `browser_action`
- keeps `read_skill`
- optionally keeps the new `openxml_office` tool only for export tasks
- removes `shell`, `glob_search`, and free-form `file_read` from the allowed tool list for these phases

Do this in `src/runtime/engine.rs` by deriving a narrower `allowed_tools` set from:

- runtime profile
- browser surface present flag
- instruction intent
- whether export mode is active

**Step 4: Re-run the focused tests**

Run the same commands.

Expected:
- both pass

## Task 2: Convert Zhihu Hotlist Skill To Structured Output First

**Files:**
- Modify: `/home/zyl/projects/sgClaw/skill_lib/skills/zhihu-hotlist/SKILL.md`
- Modify: `/home/zyl/projects/sgClaw/claw/tests/skill_lib_validation_test.py`
- Modify: `/home/zyl/projects/sgClaw/claw/tests/compat_runtime_test.rs`

**Intent:**
- The hotlist skill should stop ending with prose-only summaries. Its primary output must be a stable export artifact the Office skill can consume.

**Step 1: Write the failing tests**

Add tests that enforce:

- `zhihu-hotlist` prompt body contains an explicit `Export Artifact` section
- the artifact schema includes `sheet_name`, `columns`, and `rows`
- runtime regression checks can find those fields in the skill content when `read_skill` is used

**Step 2: Run tests to verify failure**

Run:

```bash
python3 -m unittest tests.skill_lib_validation_test
cargo test --test compat_runtime_test handle_browser_message_executes_real_zhihu_hotlist_skill_flow -- --nocapture
```

Expected:
- validation fails because the artifact contract is not yet required

**Step 3: Update `zhihu-hotlist`**

Add an `Export Artifact` section that requires this shape:

```json
{
  "source": "https://www.zhihu.com/hot",
  "sheet_name": "知乎热榜",
  "columns": ["rank", "title", "heat"],
  "rows": [[1, "标题", "344万"]]
}
```

Also add hard rules:

- no extra exploratory tools after the browser data is collected
- prose summary is secondary, structured artifact is primary

**Step 4: Re-run tests**

Expected:
- validation passes

## Task 3: Create The Office Export Skill Package

**Files:**
- Create: `/home/zyl/projects/sgClaw/skill_lib/skills/office-export-xlsx/SKILL.md`
- Create: `/home/zyl/projects/sgClaw/skill_lib/skills/office-export-xlsx/references/export-flow.md`
- Create: `/home/zyl/projects/sgClaw/skill_lib/skills/office-export-xlsx/assets/zhihu_hotlist_template.xlsx`
- Modify: `/home/zyl/projects/sgClaw/claw/tests/skill_lib_validation_test.py`

**Intent:**
- Add a fully separate Office skill that knows nothing about browser scraping and only turns structured table data into a local Excel file.

**Step 1: Write the failing validation test**

Extend `tests/skill_lib_validation_test.py` so discovery expects:

```python
EXPECTED_SKILL_NAMES = [
    "office-export-xlsx",
    "zhihu-hotlist",
    "zhihu-navigate",
    "zhihu-write",
]
```

Also require the new skill to mention:

- `openxml_office`
- `.xlsx`
- `sheet_name`
- `columns`
- `rows`

**Step 2: Run the validation test to verify failure**

Run:

```bash
python3 -m unittest tests.skill_lib_validation_test
```

Expected:
- fail because the new skill package does not exist yet

**Step 3: Create the skill package**

`SKILL.md` must define:

- when to use: local Office export from structured rows
- required input schema
- output: exported file path
- tool rule: only call `openxml_office`, do not use browser tools

`export-flow.md` must define:

- validate payload shape
- choose output path
- invoke `openxml_office`
- return file path and row count

The first workbook template should be a fixed `zhihu_hotlist_template.xlsx` with:

- sheet `知乎热榜`
- row 1 headers already present
- table fill anchored to a stable name or placeholder expected by `openxml_cli`

**Step 4: Re-run validation**

Expected:
- new skill passes audit

## Task 4: Add The `openxml_office` Runtime Tool

**Files:**
- Create: `/home/zyl/projects/sgClaw/claw/src/compat/openxml_office_tool.rs`
- Modify: `/home/zyl/projects/sgClaw/claw/src/compat/mod.rs`
- Modify: `/home/zyl/projects/sgClaw/claw/src/compat/runtime.rs`
- Modify: `/home/zyl/projects/sgClaw/claw/src/runtime/tool_policy.rs`
- Test: `/home/zyl/projects/sgClaw/claw/tests/compat_openxml_office_tool_test.rs`

**Intent:**
- Wrap sibling `openxml_cli` as a first-class local tool instead of leaking Office export through shell prompting.

**Step 1: Write the failing tool test**

Create `tests/compat_openxml_office_tool_test.rs` with cases for:

- capability probe
- render request assembly for xlsx export
- rejection when rows/columns are missing
- stable JSON output containing `output_path`

**Step 2: Run the test to verify failure**

Run:

```bash
cargo test --test compat_openxml_office_tool_test -- --nocapture
```

Expected:
- fail because the tool does not exist

**Step 3: Implement minimal tool**

Tool contract:

```json
{
  "action": "export_hotlist_xlsx",
  "template_path": ".../zhihu_hotlist_template.xlsx",
  "output_path": "/tmp/zhihu_hotlist.xlsx",
  "sheet_name": "知乎热榜",
  "columns": ["rank", "title", "heat"],
  "rows": [[1, "标题", "344万"]]
}
```

Implementation rules:

- write the payload JSON to a temp file
- invoke sibling `openxml_cli template render --request <file> --json`
- return parsed JSON result and normalized `output_path`
- no free-form shell composition from model text

**Step 4: Re-run the focused tests**

Expected:
- pass

## Task 5: Wire Export Tasks To Use Two Skills In Sequence

**Files:**
- Modify: `/home/zyl/projects/sgClaw/claw/src/runtime/engine.rs`
- Modify: `/home/zyl/projects/sgClaw/claw/tests/compat_runtime_test.rs`

**Intent:**
- The single user instruction must naturally flow from hotlist capture into Office export, not end after the first skill.

**Step 1: Write the failing runtime test**

Add a focused regression test for:

```rust
#[test]
fn zhihu_hotlist_export_task_reads_hotlist_skill_then_office_skill() {}
```

Assertions:

- request stream includes `read_skill zhihu-hotlist`
- later includes `read_skill office-export-xlsx`
- office phase exposes `openxml_office`
- no `shell` is exposed in the constrained task path

**Step 2: Run the test to verify failure**

Run:

```bash
cargo test --test compat_runtime_test zhihu_hotlist_export_task_reads_hotlist_skill_then_office_skill -- --nocapture
```

Expected:
- fail because the task currently has no structured handoff to Office export

**Step 3: Implement minimal chaining support**

Do not add a hard-coded workflow engine.

Minimal implementation:

- strengthen prompt contract so export tasks require structured hotlist artifact
- include `openxml_office` in allowed tools for export intent
- keep browser-only tools for the collection phase and Office-only tool for the export phase

**Step 4: Re-run the test**

Expected:
- pass

## Task 6: Add Real Acceptance Harness And Scoring

**Files:**
- Create: `/home/zyl/projects/sgClaw/claw/tools/live_acceptance/run_zhihu_hotlist_excel_acceptance.py`
- Create: `/home/zyl/projects/sgClaw/claw/docs/acceptance/2026-03-29-zhihu-hotlist-excel.md`

**Intent:**
- Make the final acceptance repeatable with the real user config and a transparent score.

**Step 1: Write the script**

The script must:

- use `/home/zyl/.config/superrpa/Default/superrpa/sgclaw_config.json`
- boot local `target/debug/sgclaw`
- send one browser `submit_task`
- respond to browser commands with controlled fixture responses
- capture:
  - loaded skills
  - selected skills
  - forbidden tool calls
  - final summary
  - exported file path

**Step 2: Define score rubric**

Rubric:

- `skill selection`: 30
- `tool discipline`: 25
- `hotlist data correctness`: 20
- `xlsx export success`: 20
- `final response quality`: 5

Automatic deductions:

- `shell` called: `-15`
- `glob_search` called: `-10`
- `file_read` on skill references: `-10`
- wrong skill selected first: `-15`
- export missing output path: `-20`

**Step 3: Run acceptance**

Run:

```bash
python3 tools/live_acceptance/run_zhihu_hotlist_excel_acceptance.py
```

Expected:
- prints total score and per-dimension breakdown
- stores final evidence in `docs/acceptance/2026-03-29-zhihu-hotlist-excel.md`

## Delivery Sequence

Execute in this order:

1. Task 1: constrain tools
2. Task 2: structure hotlist output
3. Task 3: add office skill package
4. Task 4: add `openxml_office`
5. Task 5: chain the two skills
6. Task 6: run acceptance and score

## Definition Of Done

- browser-attached hotlist tasks no longer wander into `shell`, `glob_search`, or ad-hoc `file_read`
- `office-export-xlsx` exists as an independent skill
- `openxml_office` exists as an explicit tool
- a single user task can collect hotlist data and export `.xlsx`
- acceptance score is at least `85/100`
