From 173d84ea27998b4a616809af97a1fc397ef9582f Mon Sep 17 00:00:00 2001
From: liuche <1257067825@qq.com>
Date: Tue, 17 Mar 2026 16:58:19 +0800
Subject: [PATCH 1/4] feat: add notebooklm agent harness scaffold
---
.gitignore | 6 +-
.../2026-03-17-notebooklm-harness-scaffold.md | 192 ++++++++++++
docs/plans/2026-03-17-notebooklm-pr-polish.md | 116 +++++++
notebooklm/agent-harness/ATTRIBUTION.md | 29 ++
notebooklm/agent-harness/NOTEBOOKLM.md | 44 +++
.../agent-harness/THIRD_PARTY_NOTICES.md | 26 ++
.../cli_anything/notebooklm/README.md | 112 +++++++
.../cli_anything/notebooklm/__init__.py | 3 +
.../cli_anything/notebooklm/__main__.py | 7 +
.../cli_anything/notebooklm/core/__init__.py | 1 +
.../cli_anything/notebooklm/core/session.py | 42 +++
.../cli_anything/notebooklm/notebooklm_cli.py | 282 ++++++++++++++++++
.../cli_anything/notebooklm/skills/SKILL.md | 78 +++++
.../cli_anything/notebooklm/tests/TEST.md | 64 ++++
.../cli_anything/notebooklm/tests/__init__.py | 1 +
.../notebooklm/tests/test_cli_smoke.py | 86 ++++++
.../notebooklm/tests/test_core.py | 96 ++++++
.../notebooklm/tests/test_manual_e2e.md | 11 +
.../cli_anything/notebooklm/utils/__init__.py | 1 +
.../notebooklm/utils/notebooklm_backend.py | 91 ++++++
notebooklm/agent-harness/setup.py | 54 ++++
21 files changed, 1341 insertions(+), 1 deletion(-)
create mode 100644 docs/plans/2026-03-17-notebooklm-harness-scaffold.md
create mode 100644 docs/plans/2026-03-17-notebooklm-pr-polish.md
create mode 100644 notebooklm/agent-harness/ATTRIBUTION.md
create mode 100644 notebooklm/agent-harness/NOTEBOOKLM.md
create mode 100644 notebooklm/agent-harness/THIRD_PARTY_NOTICES.md
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/README.md
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/__init__.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/__main__.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/core/__init__.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/core/session.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/tests/__init__.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/tests/test_manual_e2e.md
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/utils/__init__.py
create mode 100644 notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py
create mode 100644 notebooklm/agent-harness/setup.py
diff --git a/.gitignore b/.gitignore
index 8a8e23618..5dc592593 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@
!/README.md
!/assets/
!/.claude-plugin/
+!/docs/
# Step 3: Allow cli-anything-plugin, codex-skill, and skill_generation tests
!/cli-anything-plugin/
@@ -99,4 +100,7 @@ assets/gen_typing_gif.py
!README_CN.md
!opencode-commands/
!/qoder-plugin/
-
+!/notebooklm/
+/notebooklm/*
+/notebooklm/.*
+!/notebooklm/agent-harness/
diff --git a/docs/plans/2026-03-17-notebooklm-harness-scaffold.md b/docs/plans/2026-03-17-notebooklm-harness-scaffold.md
new file mode 100644
index 000000000..5d38a7faa
--- /dev/null
+++ b/docs/plans/2026-03-17-notebooklm-harness-scaffold.md
@@ -0,0 +1,192 @@
+# NotebookLM Harness Scaffold Implementation Plan
+
+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
+
+**Goal:** Add an experimental `cli-anything-notebooklm` scaffold that wraps an installed `notebooklm` CLI, includes attribution files, and establishes the first round of tests and docs.
+
+**Architecture:** Create a service-style harness under `notebooklm/agent-harness/` that mirrors the existing CLI-Anything package layout. The backend adapter will shell out to the installed `notebooklm` command, sanitize sensitive errors, and keep notebook context in a lightweight session file for REPL use.
+
+**Tech Stack:** Python 3.10+, Click, prompt-toolkit, pytest, subprocess-based backend wrapper
+
+### Task 1: Establish the tracked scaffold area
+
+**Files:**
+- Modify: `.gitignore`
+- Create: `docs/plans/2026-03-17-notebooklm-harness-scaffold.md`
+
+**Step 1: Write the failing test**
+
+No behavior test for this task. It is repository plumbing needed to track the new harness path and plan document.
+
+**Step 2: Run test to verify it fails**
+
+Not applicable.
+
+**Step 3: Write minimal implementation**
+
+- Allow `docs/`
+- Allow `notebooklm/`
+- Allow `notebooklm/agent-harness/`
+
+**Step 4: Run test to verify it passes**
+
+Run: `git status --short`
+Expected: new scaffold files are visible to git
+
+**Step 5: Commit**
+
+```bash
+git add .gitignore docs/plans/2026-03-17-notebooklm-harness-scaffold.md
+git commit -m "chore: prepare notebooklm harness scaffold"
+```
+
+### Task 2: Write the first failing backend tests
+
+**Files:**
+- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py`
+- Test: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py`
+
+**Step 1: Write the failing test**
+
+Cover:
+- backend finds `notebooklm` on PATH
+- backend raises clear install guidance if missing
+- backend builds explicit commands with `-n `
+- backend sanitizes secret-bearing auth path output
+- session file stores current notebook context
+
+**Step 2: Run test to verify it fails**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q`
+Expected: FAIL with import errors because the package does not exist yet
+
+**Step 3: Write minimal implementation**
+
+Create:
+- `cli_anything/notebooklm/utils/notebooklm_backend.py`
+- `cli_anything/notebooklm/core/session.py`
+
+**Step 4: Run test to verify it passes**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q`
+Expected: PASS
+
+**Step 5: Commit**
+
+```bash
+git add notebooklm/agent-harness/cli_anything/notebooklm
+git commit -m "feat: add notebooklm backend scaffold"
+```
+
+### Task 3: Write the first failing CLI tests
+
+**Files:**
+- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py`
+- Test: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py`
+
+**Step 1: Write the failing test**
+
+Cover:
+- root `--help` shows experimental NotebookLM wording
+- root `--help` exposes command groups
+- `auth status --help` and `notebook list --help` execute
+
+**Step 2: Run test to verify it fails**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_cli_smoke.py -q`
+Expected: FAIL because `notebooklm_cli.py` is missing
+
+**Step 3: Write minimal implementation**
+
+Create:
+- `cli_anything/notebooklm/notebooklm_cli.py`
+- `cli_anything/notebooklm/__init__.py`
+- `cli_anything/notebooklm/__main__.py`
+
+Use placeholder command handlers that route through the backend wrapper.
+
+**Step 4: Run test to verify it passes**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_cli_smoke.py -q`
+Expected: PASS
+
+**Step 5: Commit**
+
+```bash
+git add notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
+git commit -m "feat: add notebooklm cli skeleton"
+```
+
+### Task 4: Add packaging and attribution docs
+
+**Files:**
+- Create: `notebooklm/agent-harness/setup.py`
+- Create: `notebooklm/agent-harness/NOTEBOOKLM.md`
+- Create: `notebooklm/agent-harness/ATTRIBUTION.md`
+- Create: `notebooklm/agent-harness/THIRD_PARTY_NOTICES.md`
+- Create: `notebooklm/agent-harness/cli_anything/notebooklm/README.md`
+- Create: `notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md`
+- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md`
+- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_manual_e2e.md`
+
+**Step 1: Write the failing test**
+
+Add assertions that:
+- `setup.py` exposes `cli-anything-notebooklm`
+- skill file exists
+- README includes acknowledgement text
+
+**Step 2: Run test to verify it fails**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q`
+Expected: FAIL on missing files and packaging metadata
+
+**Step 3: Write minimal implementation**
+
+Create all packaging and documentation files with explicit attribution and experimental disclaimers.
+
+**Step 4: Run test to verify it passes**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
+Expected: PASS
+
+**Step 5: Commit**
+
+```bash
+git add notebooklm/agent-harness
+git commit -m "docs: add notebooklm harness attribution and packaging"
+```
+
+### Task 5: Verify the scaffold end to end
+
+**Files:**
+- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md`
+
+**Step 1: Write the failing test**
+
+No new behavior. This task is verification and documentation.
+
+**Step 2: Run test to verify it fails**
+
+Not applicable.
+
+**Step 3: Write minimal implementation**
+
+Run:
+- `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
+- `cd notebooklm/agent-harness && python3 -m cli_anything.notebooklm.notebooklm_cli --help`
+
+Append the verification notes to `TEST.md`.
+
+**Step 4: Run test to verify it passes**
+
+Expected:
+- targeted tests PASS
+- CLI help exits 0
+
+**Step 5: Commit**
+
+```bash
+git add notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
+git commit -m "test: verify notebooklm harness scaffold"
+```
diff --git a/docs/plans/2026-03-17-notebooklm-pr-polish.md b/docs/plans/2026-03-17-notebooklm-pr-polish.md
new file mode 100644
index 000000000..3b2f0d536
--- /dev/null
+++ b/docs/plans/2026-03-17-notebooklm-pr-polish.md
@@ -0,0 +1,116 @@
+# NotebookLM PR Polish Implementation Plan
+
+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
+
+**Goal:** Tighten the experimental NotebookLM harness into a more upstream-ready contribution with stronger docs, explicit attribution, and subprocess-level CLI smoke coverage.
+
+**Architecture:** Keep the current service-style wrapper architecture intact. Improve PR readiness by expanding package-facing documentation and adding lightweight subprocess tests that verify the packaged CLI interface without requiring a live authenticated NotebookLM session.
+
+**Tech Stack:** Python 3, Click, pytest, subprocess, Markdown docs
+
+### Task 1: Add failing tests for PR-facing expectations
+
+**Files:**
+- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py`
+- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py`
+
+**Step 1: Write the failing test**
+
+Add tests that require:
+- README to document installation, test execution, safety boundaries, and references
+- SKILL.md to include installation, usage, and explicit unofficial guidance
+- subprocess CLI help to render through a resolved `cli-anything-notebooklm` entry path
+
+**Step 2: Run test to verify it fails**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
+
+Expected: FAIL on missing README/SKILL sections or missing subprocess helper behavior
+
+**Step 3: Write minimal implementation**
+
+Expand documentation and add the smallest test helper needed for subprocess smoke coverage.
+
+**Step 4: Run test to verify it passes**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
+
+Expected: PASS
+
+**Step 5: Commit**
+
+```bash
+git add notebooklm/agent-harness/cli_anything/notebooklm/tests notebooklm/agent-harness/cli_anything/notebooklm/README.md notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
+git commit -m "test: harden notebooklm harness smoke coverage"
+```
+
+### Task 2: Improve docs for upstream review
+
+**Files:**
+- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/README.md`
+- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md`
+- Modify: `notebooklm/agent-harness/NOTEBOOKLM.md`
+
+**Step 1: Write the failing test**
+
+Covered by Task 1 doc assertions.
+
+**Step 2: Run test to verify it fails**
+
+Covered by Task 1.
+
+**Step 3: Write minimal implementation**
+
+Document:
+- installation and local prerequisites
+- run and test commands
+- command group overview
+- agent guidance and safe-by-default behavior
+- explicit references and unofficial attribution boundary
+
+**Step 4: Run test to verify it passes**
+
+Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
+
+Expected: PASS
+
+**Step 5: Commit**
+
+```bash
+git add notebooklm/agent-harness/NOTEBOOKLM.md notebooklm/agent-harness/cli_anything/notebooklm/README.md notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
+git commit -m "docs: polish notebooklm harness contribution docs"
+```
+
+### Task 3: Verify and record final state
+
+**Files:**
+- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md`
+
+**Step 1: Write the failing test**
+
+No new behavior test. This task records verification evidence.
+
+**Step 2: Run test to verify it fails**
+
+Not applicable.
+
+**Step 3: Write minimal implementation**
+
+Run:
+- `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests -q`
+- `cd notebooklm/agent-harness && python3 -m cli_anything.notebooklm.notebooklm_cli --help`
+
+Append fresh results to `TEST.md`.
+
+**Step 4: Run test to verify it passes**
+
+Expected:
+- all NotebookLM scaffold tests PASS
+- module help exits 0 and prints command groups
+
+**Step 5: Commit**
+
+```bash
+git add notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
+git commit -m "test: record notebooklm harness verification"
+```
diff --git a/notebooklm/agent-harness/ATTRIBUTION.md b/notebooklm/agent-harness/ATTRIBUTION.md
new file mode 100644
index 000000000..bb27d4bcb
--- /dev/null
+++ b/notebooklm/agent-harness/ATTRIBUTION.md
@@ -0,0 +1,29 @@
+# Attribution
+
+This harness adapts the CLI-Anything methodology for NotebookLM.
+
+## Acknowledgements
+
+- **CLI-Anything**
+ - Project: https://github.com/HKUDS/CLI-Anything
+ - Methodology: https://github.com/HKUDS/CLI-Anything/blob/main/cli-anything-plugin/HARNESS.md
+ - We follow its agent-native CLI conventions, including REPL-first design, JSON output, package layout, and test documentation patterns.
+
+- **notebooklm-py**
+ - Project: https://github.com/teng-lin/notebooklm-py
+ - PyPI: https://pypi.org/project/notebooklm-py/
+ - This harness is designed to interoperate with the installed `notebooklm` CLI distributed by notebooklm-py.
+
+- **Google NotebookLM**
+ - Product help: https://support.google.com/notebooklm/answer/16206563
+ - NotebookLM is a Google product. This harness is unofficial and not affiliated with or endorsed by Google.
+
+## Design Boundary
+
+This project prefers composition over copying:
+
+- wrap the installed `notebooklm` CLI
+- document upstream dependencies and policies
+- avoid vendoring third-party NotebookLM implementation code into this repository
+
+If you extend this harness, preserve these acknowledgements and keep the unofficial / experimental disclaimer intact.
diff --git a/notebooklm/agent-harness/NOTEBOOKLM.md b/notebooklm/agent-harness/NOTEBOOKLM.md
new file mode 100644
index 000000000..c53731dab
--- /dev/null
+++ b/notebooklm/agent-harness/NOTEBOOKLM.md
@@ -0,0 +1,44 @@
+# NotebookLM: Project-Specific Analysis & SOP
+
+## Architecture Summary
+
+NotebookLM is a hosted Google research and content-generation product. Unlike the
+local GUI applications that CLI-Anything usually targets, this harness wraps an
+installed `notebooklm` command-line client that already manages authentication,
+source ingestion, chat, artifact generation, and downloads.
+
+This harness therefore behaves as a **service-style CLI wrapper**:
+
+1. Resolve the local `notebooklm` executable.
+2. Build explicit commands with notebook context where needed.
+3. Sanitize sensitive auth-related error output.
+4. Persist lightweight local session state for REPL convenience.
+
+## Backend Strategy
+
+- Prefer the installed `notebooklm` CLI over reimplementing NotebookLM internals.
+- Keep credentials outside the repository and outside test fixtures.
+- Treat this integration as experimental and unofficial.
+- Require explicit confirmation for destructive or high-impact operations.
+- Preserve clear attribution to CLI-Anything, notebooklm-py, and Google NotebookLM documentation.
+
+## Contribution Boundary
+
+This harness is designed to be safe for an upstream contribution review:
+
+- it wraps an installed community CLI instead of vendoring third-party NotebookLM code
+- it documents copyright and service-boundary concerns instead of implying official support
+- it limits automated verification to non-destructive smoke coverage unless a local authenticated session is intentionally used
+- it keeps end-to-end authenticated testing manual so secrets and account state stay out of CI and fixtures
+
+## Constraints
+
+- Depends on a valid local Google-authenticated NotebookLM session.
+- Depends on behavior provided by the installed `notebooklm` CLI.
+- Full authenticated end-to-end tests are manual by design.
+
+## References
+
+- CLI-Anything methodology: https://github.com/HKUDS/CLI-Anything
+- notebooklm-py project: https://github.com/teng-lin/notebooklm-py
+- Google NotebookLM help: https://support.google.com/notebooklm/answer/16206563
diff --git a/notebooklm/agent-harness/THIRD_PARTY_NOTICES.md b/notebooklm/agent-harness/THIRD_PARTY_NOTICES.md
new file mode 100644
index 000000000..dea35669f
--- /dev/null
+++ b/notebooklm/agent-harness/THIRD_PARTY_NOTICES.md
@@ -0,0 +1,26 @@
+# Third-Party Notices
+
+## notebooklm-py
+
+- Homepage: https://github.com/teng-lin/notebooklm-py
+- PyPI: https://pypi.org/project/notebooklm-py/
+- License: MIT
+
+This harness is intended to work with the `notebooklm` CLI provided by notebooklm-py.
+
+## Click
+
+Used for CLI command structure.
+
+## prompt-toolkit
+
+Used for REPL interaction helpers.
+
+## Important Boundary
+
+Google NotebookLM is a third-party online service. This harness is an unofficial
+integration layer and is not affiliated with Google. Users are responsible for:
+
+- complying with Google terms and product restrictions
+- protecting their own credentials and local auth state
+- respecting copyright for imported sources
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/README.md b/notebooklm/agent-harness/cli_anything/notebooklm/README.md
new file mode 100644
index 000000000..2751f83d8
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/README.md
@@ -0,0 +1,112 @@
+# CLI-Anything NotebookLM Harness
+
+Experimental NotebookLM harness for CLI-Anything.
+
+This package wraps an installed `notebooklm` CLI and exposes a CLI-Anything-style
+interface for authentication checks, notebook selection, source management, chat,
+artifact generation, downloads, and sharing.
+
+## Status
+
+- Experimental
+- Community-maintained
+- Unofficial and not affiliated with Google
+
+## Requirements
+
+- Python 3.10+
+- An installed `notebooklm` command
+- A valid local NotebookLM login session
+
+## Install
+
+```bash
+cd notebooklm/agent-harness
+python3 -m pip install -e .
+```
+
+If the upstream NotebookLM CLI is not installed yet:
+
+```bash
+python3 -m pip install --user 'notebooklm-py[browser]'
+python3 -m playwright install chromium
+```
+
+## Run
+
+```bash
+# Show help
+cli-anything-notebooklm --help
+
+# Check auth state
+cli-anything-notebooklm auth status
+
+# List notebooks
+cli-anything-notebooklm notebook list
+```
+
+## Run Tests
+
+```bash
+cd notebooklm/agent-harness
+python3 -m pytest cli_anything/notebooklm/tests -q
+python3 -m cli_anything.notebooklm.notebooklm_cli --help
+```
+
+## Command Groups
+
+| Group | Purpose |
+| --- | --- |
+| `auth` | login, auth status, and lightweight auth checks |
+| `notebook` | list, create, and summarize notebooks |
+| `source` | inspect sources and add URL sources |
+| `chat` | ask questions and inspect history |
+| `artifact` | list artifacts and generate reports |
+| `download` | download generated artifacts |
+| `share` | inspect sharing status |
+
+## Common Workflows
+
+```bash
+cli-anything-notebooklm auth status
+cli-anything-notebooklm notebook list
+cli-anything-notebooklm source list --notebook nb_123
+cli-anything-notebooklm chat ask "Summarize the current notebook"
+cli-anything-notebooklm artifact generate-report --notebook nb_123
+```
+
+## For AI Agents
+
+- Prefer explicit notebook IDs with `--notebook` instead of relying on ambient state.
+- Use `--json` whenever the command supports machine-readable output.
+- Treat NotebookLM auth state as sensitive local data and never print cookie or storage files.
+- Treat this harness as a thin wrapper around `notebooklm`, not a reimplementation of NotebookLM.
+
+## Acknowledgements
+
+This harness is inspired by the CLI-Anything methodology:
+https://github.com/HKUDS/CLI-Anything
+
+It is designed to work with the community-maintained `notebooklm` CLI from `notebooklm-py`:
+https://github.com/teng-lin/notebooklm-py
+
+NotebookLM is a Google product:
+https://support.google.com/notebooklm/answer/16206563
+
+This project is unofficial and not affiliated with Google.
+
+## Safety Notes
+
+- Do not commit local auth state into the repository.
+- Do not upload sensitive content without permission.
+- Respect copyright and service terms for imported sources.
+- Prefer review-oriented or read-only commands first when working inside a live notebook.
+- Treat sharing and artifact generation as user-impacting operations that deserve explicit intent.
+
+## References
+
+- CLI-Anything: https://github.com/HKUDS/CLI-Anything
+- CLI-Anything HARNESS.md: https://github.com/HKUDS/CLI-Anything/blob/main/cli-anything-plugin/HARNESS.md
+- notebooklm-py: https://github.com/teng-lin/notebooklm-py
+- notebooklm-py on PyPI: https://pypi.org/project/notebooklm-py/
+- Google NotebookLM help: https://support.google.com/notebooklm/answer/16206563
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/__init__.py b/notebooklm/agent-harness/cli_anything/notebooklm/__init__.py
new file mode 100644
index 000000000..c8601e771
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/__init__.py
@@ -0,0 +1,3 @@
+"""NotebookLM harness package."""
+
+__version__ = "0.1.0"
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/__main__.py b/notebooklm/agent-harness/cli_anything/notebooklm/__main__.py
new file mode 100644
index 000000000..fd1753810
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/__main__.py
@@ -0,0 +1,7 @@
+"""Module entry point for cli-anything-notebooklm."""
+
+from cli_anything.notebooklm.notebooklm_cli import main
+
+
+if __name__ == "__main__":
+ main()
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/core/__init__.py b/notebooklm/agent-harness/cli_anything/notebooklm/core/__init__.py
new file mode 100644
index 000000000..2c7cef76d
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/core/__init__.py
@@ -0,0 +1 @@
+"""Core modules for the NotebookLM harness."""
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/core/session.py b/notebooklm/agent-harness/cli_anything/notebooklm/core/session.py
new file mode 100644
index 000000000..995e6b01c
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/core/session.py
@@ -0,0 +1,42 @@
+"""Session persistence helpers for NotebookLM CLI context."""
+
+from __future__ import annotations
+
+import json
+from pathlib import Path
+
+
+class Session:
+ """Persist the active notebook for REPL and one-shot commands."""
+
+ def __init__(self, session_file: str | Path | None = None):
+ if session_file is None:
+ session_file = Path.home() / ".cli-anything-notebooklm" / "session.json"
+ self.session_file = Path(session_file)
+ self.session_file.parent.mkdir(parents=True, exist_ok=True)
+ self._data = self._load()
+
+ def _load(self) -> dict:
+ if not self.session_file.exists():
+ return {"active_notebook": None}
+ try:
+ return json.loads(self.session_file.read_text(encoding="utf-8"))
+ except json.JSONDecodeError:
+ return {"active_notebook": None}
+
+ def _save(self):
+ self.session_file.write_text(
+ json.dumps(self._data, indent=2, ensure_ascii=True),
+ encoding="utf-8",
+ )
+
+ def get_active_notebook(self) -> str | None:
+ return self._data.get("active_notebook")
+
+ def set_active_notebook(self, notebook_id: str):
+ self._data["active_notebook"] = notebook_id
+ self._save()
+
+ def clear_active_notebook(self):
+ self._data["active_notebook"] = None
+ self._save()
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py b/notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
new file mode 100644
index 000000000..53640752b
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python3
+"""NotebookLM CLI — Experimental NotebookLM wrapper for AI agents."""
+
+from __future__ import annotations
+
+import json
+import sys
+
+import click
+
+from cli_anything.notebooklm import __version__
+from cli_anything.notebooklm.core.session import Session
+from cli_anything.notebooklm.utils.notebooklm_backend import run_notebooklm
+
+_json_output = False
+_session: Session | None = None
+
+
+def get_session() -> Session:
+ global _session
+ if _session is None:
+ _session = Session()
+ return _session
+
+
+def emit(data, message: str = ""):
+ if _json_output:
+ click.echo(json.dumps(data, indent=2, default=str))
+ elif message:
+ click.echo(message)
+ elif isinstance(data, str):
+ click.echo(data)
+ else:
+ click.echo(json.dumps(data, indent=2, default=str))
+
+
+def handle_error(func):
+ def wrapper(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except Exception as exc: # pragma: no cover - scaffold behavior
+ if _json_output:
+ click.echo(json.dumps({"error": str(exc), "type": type(exc).__name__}))
+ else:
+ click.echo(f"Error: {exc}", err=True)
+ sys.exit(1)
+
+ wrapper.__name__ = func.__name__
+ wrapper.__doc__ = func.__doc__
+ return wrapper
+
+
+def resolve_notebook_id(notebook_id: str | None) -> str | None:
+ return notebook_id or get_session().get_active_notebook()
+
+
+@click.group(invoke_without_command=True)
+@click.option("--json", "use_json", is_flag=True, help="Output as JSON")
+@click.option("--notebook", "notebook_id", default=None, help="Active notebook ID")
+@click.pass_context
+def cli(ctx, use_json, notebook_id):
+ """NotebookLM CLI — Experimental NotebookLM wrapper for AI agents."""
+ global _json_output
+ _json_output = use_json
+ if notebook_id:
+ get_session().set_active_notebook(notebook_id)
+ if ctx.invoked_subcommand is None:
+ ctx.invoke(repl)
+
+
+@cli.command()
+def repl():
+ """Start a minimal REPL placeholder."""
+ click.echo(f"cli-anything-notebooklm v{__version__}")
+ click.echo("Experimental harness scaffold. Use --help to inspect command groups.")
+
+
+@cli.group()
+def auth():
+ """Authentication and login helpers."""
+
+
+@auth.command("status")
+@handle_error
+def auth_status():
+ """Check authentication status."""
+ emit(run_notebooklm(["status"], json_output=_json_output))
+
+
+@auth.command("login")
+@handle_error
+def auth_login():
+ """Open the browser login flow."""
+ emit(run_notebooklm(["login"], json_output=_json_output))
+
+
+@auth.command("check")
+@handle_error
+def auth_check():
+ """Run a lightweight authentication check."""
+ emit(run_notebooklm(["auth", "check"], json_output=_json_output))
+
+
+@cli.group()
+def notebook():
+ """Notebook management commands."""
+
+
+@notebook.command("list")
+@handle_error
+def notebook_list():
+ """List notebooks."""
+ emit(run_notebooklm(["list"], json_output=_json_output))
+
+
+@notebook.command("create")
+@click.argument("name")
+@handle_error
+def notebook_create(name):
+ """Create a notebook."""
+ emit(run_notebooklm(["create", name], json_output=_json_output))
+
+
+@notebook.command("summary")
+@handle_error
+def notebook_summary():
+ """Summarize the active notebook."""
+ emit(
+ run_notebooklm(
+ ["summary"],
+ notebook_id=resolve_notebook_id(None),
+ json_output=_json_output,
+ )
+ )
+
+
+@cli.group()
+def source():
+ """Source ingestion and inspection commands."""
+
+
+@source.command("list")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def source_list(notebook_id):
+ """List sources for a notebook."""
+ emit(
+ run_notebooklm(
+ ["source", "list"],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+@source.command("add-url")
+@click.argument("url")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def source_add_url(url, notebook_id):
+ """Add a URL source."""
+ emit(
+ run_notebooklm(
+ ["source", "add", url],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+@cli.group()
+def chat():
+ """Chat and history commands."""
+
+
+@chat.command("ask")
+@click.argument("prompt")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def chat_ask(prompt, notebook_id):
+ """Ask a question against a notebook."""
+ emit(
+ run_notebooklm(
+ ["ask", prompt],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+@chat.command("history")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def chat_history(notebook_id):
+ """Show chat history."""
+ emit(
+ run_notebooklm(
+ ["history"],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+@cli.group()
+def artifact():
+ """Artifact generation and inspection commands."""
+
+
+@artifact.command("list")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def artifact_list(notebook_id):
+ """List notebook artifacts."""
+ emit(
+ run_notebooklm(
+ ["artifact", "list"],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+@artifact.command("generate-report")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def artifact_generate_report(notebook_id):
+ """Generate a report artifact."""
+ emit(
+ run_notebooklm(
+ ["generate", "report", "--wait"],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+@cli.group()
+def download():
+ """Artifact download helpers."""
+
+
+@download.command("report")
+@click.argument("output_path")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def download_report(output_path, notebook_id):
+ """Download the latest report artifact."""
+ emit(
+ run_notebooklm(
+ ["download", "report", output_path],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+@cli.group()
+def share():
+ """Sharing and access control commands."""
+
+
+@share.command("status")
+@click.option("--notebook", "notebook_id", default=None, help="Notebook ID")
+@handle_error
+def share_status(notebook_id):
+ """Inspect notebook sharing state."""
+ emit(
+ run_notebooklm(
+ ["share", "status"],
+ notebook_id=resolve_notebook_id(notebook_id),
+ json_output=_json_output,
+ )
+ )
+
+
+def main():
+ cli()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md b/notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
new file mode 100644
index 000000000..9a8c6b514
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
@@ -0,0 +1,78 @@
+---
+name: cli-anything-notebooklm
+description: Experimental NotebookLM harness for listing notebooks, managing sources, asking questions, generating artifacts, and downloading outputs through an installed notebooklm CLI.
+---
+
+# cli-anything-notebooklm
+
+Experimental NotebookLM harness for CLI-Anything.
+
+## Installation
+
+This package is intended to be installed from the harness directory:
+
+```bash
+cd notebooklm/agent-harness
+python3 -m pip install -e .
+```
+
+Install the upstream NotebookLM CLI if needed:
+
+```bash
+python3 -m pip install --user 'notebooklm-py[browser]'
+python3 -m playwright install chromium
+```
+
+## Requirements
+
+- `notebooklm` command installed locally
+- Valid local NotebookLM login session
+
+## Usage
+
+### Basic Commands
+
+```bash
+# Show help
+cli-anything-notebooklm --help
+
+# Start with a notebook context
+cli-anything-notebooklm --notebook nb_123 source list
+
+# Prefer JSON for agent use
+cli-anything-notebooklm --json notebook list
+```
+
+## Command Groups
+
+| Group | Purpose |
+| --- | --- |
+| `auth` | login and auth status |
+| `notebook` | notebook list, create, summary |
+| `source` | source listing and URL add |
+| `chat` | ask questions and inspect history |
+| `artifact` | list and generate artifacts |
+| `download` | fetch generated outputs |
+| `share` | inspect sharing state |
+
+## Agent Workflow
+
+1. Check auth with `cli-anything-notebooklm auth status`
+2. Discover notebook IDs with `cli-anything-notebooklm --json notebook list`
+3. Use explicit `--notebook` for follow-up commands
+4. Prefer `--json` for list and inspection commands
+
+## Agent Guidance
+
+- Prefer explicit notebook IDs with `--notebook`.
+- Use `--json` for machine-readable output.
+- Treat this harness as experimental and unofficial.
+- Do not expose auth files or cookies in logs.
+- NotebookLM is a Google product; this harness is unofficial and not affiliated with Google.
+
+## References
+
+- CLI-Anything: https://github.com/HKUDS/CLI-Anything
+- CLI-Anything HARNESS.md: https://github.com/HKUDS/CLI-Anything/blob/main/cli-anything-plugin/HARNESS.md
+- notebooklm-py: https://github.com/teng-lin/notebooklm-py
+- Google NotebookLM help: https://support.google.com/notebooklm/answer/16206563
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md b/notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
new file mode 100644
index 000000000..26a3afe23
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
@@ -0,0 +1,64 @@
+# NotebookLM Harness - Test Documentation
+
+## Test Inventory
+
+| File | Focus |
+| --- | --- |
+| `test_core.py` | backend discovery, command building, session persistence, packaging fixtures |
+| `test_cli_smoke.py` | help output and command group exposure |
+| `test_manual_e2e.md` | authenticated local smoke-test checklist |
+
+## Coverage Notes
+
+This harness has three validation layers:
+
+- unit tests for backend helpers and session state
+- smoke tests for CLI help and command registration
+- manual authenticated end-to-end verification
+
+Because NotebookLM depends on a live Google account session and an installed
+community CLI, full authenticated E2E coverage is not run in public CI.
+
+## Local Verification
+
+Verified on 2026-03-17 in the notebooklm harness worktree.
+
+### Commands Run
+
+```bash
+python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q
+python3 -m pytest cli_anything/notebooklm/tests/test_cli_smoke.py -q
+python3 -m cli_anything.notebooklm.notebooklm_cli --help
+```
+
+### Results
+
+- `test_core.py`: 9 passed
+- `test_cli_smoke.py`: 5 passed
+- `python3 -m cli_anything.notebooklm.notebooklm_cli --help`: exit code 0, help text rendered correctly
+
+### Notes
+
+- Added a regression test for module execution so `python -m cli_anything.notebooklm.notebooklm_cli --help` is covered, not just Click's in-process `CliRunner`.
+- The authenticated `notebooklm` backend remains intentionally manual for end-to-end verification because it depends on a local Google session.
+
+## PR Polish Verification
+
+Verified on 2026-03-17 after README, SKILL, and subprocess smoke coverage upgrades.
+
+### Commands Run
+
+```bash
+python3 -m pytest cli_anything/notebooklm/tests -q
+python3 -m cli_anything.notebooklm.notebooklm_cli --help
+```
+
+### Results
+
+- Full NotebookLM harness suite: 17 passed
+- Module help command: exit code 0, rendered command groups correctly
+
+### Notes
+
+- Added doc-level assertions so the package README and skill file now explicitly cover installation, tests, safety boundaries, and unofficial Google attribution.
+- Added `_resolve_cli`-style subprocess smoke coverage so the CLI can be exercised through a resolved command path, not only through Click's in-process test runner.
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/__init__.py b/notebooklm/agent-harness/cli_anything/notebooklm/tests/__init__.py
new file mode 100644
index 000000000..9eb399dd0
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/__init__.py
@@ -0,0 +1 @@
+"""Tests for the NotebookLM harness."""
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py
new file mode 100644
index 000000000..e9c440f64
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py
@@ -0,0 +1,86 @@
+"""CLI smoke tests for the NotebookLM harness scaffold."""
+
+import os
+from pathlib import Path
+import shutil
+import subprocess
+import sys
+
+from click.testing import CliRunner
+
+from cli_anything.notebooklm.notebooklm_cli import cli
+
+
+def _resolve_cli(name):
+ """Resolve installed CLI command; fall back to python -m for local dev."""
+ force = os.environ.get("CLI_ANYTHING_FORCE_INSTALLED", "").strip() == "1"
+ path = shutil.which(name)
+ if path:
+ return [path], None
+ if force:
+ raise RuntimeError(f"{name} not found in PATH. Install with: pip install -e .")
+
+ module = "cli_anything.notebooklm.notebooklm_cli"
+ package_root = Path(__file__).resolve().parents[3]
+ env = os.environ.copy()
+ current = env.get("PYTHONPATH", "")
+ env["PYTHONPATH"] = (
+ f"{package_root}{os.pathsep}{current}" if current else str(package_root)
+ )
+ return [sys.executable, "-m", module], env
+
+
+class TestRootHelp:
+ def test_root_help_shows_experimental_notebooklm(self):
+ result = CliRunner().invoke(cli, ["--help"])
+ assert result.exit_code == 0
+ assert "NotebookLM CLI" in result.output
+ assert "Experimental" in result.output
+
+ def test_root_help_lists_command_groups(self):
+ result = CliRunner().invoke(cli, ["--help"])
+ assert result.exit_code == 0
+ for group in ["auth", "notebook", "source", "chat", "artifact", "download", "share"]:
+ assert group in result.output
+
+
+class TestSubcommandHelp:
+ def test_auth_status_help(self):
+ result = CliRunner().invoke(cli, ["auth", "status", "--help"])
+ assert result.exit_code == 0
+ assert "Check authentication status" in result.output
+
+ def test_notebook_list_help(self):
+ result = CliRunner().invoke(cli, ["notebook", "list", "--help"])
+ assert result.exit_code == 0
+ assert "List notebooks" in result.output
+
+
+class TestModuleExecution:
+ def test_python_m_module_help_emits_output(self):
+ result = subprocess.run(
+ [
+ sys.executable,
+ "-m",
+ "cli_anything.notebooklm.notebooklm_cli",
+ "--help",
+ ],
+ capture_output=True,
+ text=True,
+ check=False,
+ )
+ assert result.returncode == 0
+ assert "NotebookLM CLI" in result.stdout
+
+ def test_resolved_cli_help_emits_output(self):
+ command, env = _resolve_cli("cli-anything-notebooklm")
+ result = subprocess.run(
+ command + ["--help"],
+ capture_output=True,
+ text=True,
+ check=False,
+ env=env,
+ )
+ assert result.returncode == 0
+ assert "NotebookLM CLI" in result.stdout
+ assert "auth" in result.stdout
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py
new file mode 100644
index 000000000..7ef1a4889
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py
@@ -0,0 +1,96 @@
+"""Unit tests for NotebookLM harness scaffold."""
+
+import json
+from pathlib import Path
+from unittest.mock import patch
+
+import pytest
+
+from cli_anything.notebooklm.core.session import Session
+from cli_anything.notebooklm.utils.notebooklm_backend import (
+ build_command,
+ require_notebooklm,
+ sanitize_error,
+)
+
+
+class TestBackendDiscovery:
+ def test_require_notebooklm_returns_path(self):
+ with patch("cli_anything.notebooklm.utils.notebooklm_backend.shutil.which", return_value="/usr/local/bin/notebooklm"):
+ assert require_notebooklm() == "/usr/local/bin/notebooklm"
+
+ def test_require_notebooklm_raises_with_install_guidance(self):
+ with patch("cli_anything.notebooklm.utils.notebooklm_backend.shutil.which", return_value=None):
+ with pytest.raises(RuntimeError, match="notebooklm command not found"):
+ require_notebooklm()
+
+
+class TestCommandBuilder:
+ def test_build_command_with_notebook_id_and_json(self):
+ command = build_command(
+ ["source", "list"],
+ notebook_id="nb_123",
+ json_output=True,
+ )
+ assert command == [
+ "notebooklm",
+ "source",
+ "list",
+ "-n",
+ "nb_123",
+ "--json",
+ ]
+
+ def test_build_command_without_notebook_id(self):
+ command = build_command(["list"])
+ assert command == ["notebooklm", "list"]
+
+
+class TestErrorSanitization:
+ def test_sanitize_error_redacts_storage_state_path(self):
+ raw = "Failed to open /Users/tester/.notebooklm/storage_state.json because auth expired"
+ assert "storage_state.json" not in sanitize_error(raw)
+ assert "[redacted-auth-path]" in sanitize_error(raw)
+
+
+class TestSession:
+ def test_session_persists_active_notebook(self, tmp_path):
+ session_file = tmp_path / "session.json"
+ session = Session(session_file=session_file)
+ session.set_active_notebook("nb_abc")
+
+ reloaded = Session(session_file=session_file)
+ assert reloaded.get_active_notebook() == "nb_abc"
+
+ def test_session_clear_active_notebook(self, tmp_path):
+ session_file = tmp_path / "session.json"
+ session = Session(session_file=session_file)
+ session.set_active_notebook("nb_abc")
+ session.clear_active_notebook()
+
+ data = json.loads(Path(session_file).read_text())
+ assert data["active_notebook"] is None
+
+
+class TestPackagingFixtures:
+ def test_acknowledgements_reference_external_projects(self):
+ readme = Path("cli_anything/notebooklm/README.md").read_text(encoding="utf-8")
+ assert "CLI-Anything" in readme
+ assert "notebooklm-py" in readme
+
+ def test_readme_documents_install_test_and_safety_sections(self):
+ readme = Path("cli_anything/notebooklm/README.md").read_text(encoding="utf-8")
+ assert "## Install" in readme
+ assert "## Run Tests" in readme
+ assert "## Safety Notes" in readme
+ assert "Google NotebookLM" in readme
+
+ def test_skill_file_contains_usage_and_boundary_guidance(self):
+ skill = Path("cli_anything/notebooklm/skills/SKILL.md").read_text(encoding="utf-8")
+ assert "## Installation" in skill
+ assert "## Usage" in skill
+ assert "unofficial" in skill.lower()
+ assert "not affiliated with Google" in skill
+
+ def test_skill_file_exists(self):
+ assert Path("cli_anything/notebooklm/skills/SKILL.md").is_file()
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_manual_e2e.md b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_manual_e2e.md
new file mode 100644
index 000000000..c0b943dd9
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_manual_e2e.md
@@ -0,0 +1,11 @@
+# Manual E2E Checklist
+
+1. Run `notebooklm login`.
+2. Run `cli-anything-notebooklm auth status`.
+3. Run `cli-anything-notebooklm notebook list`.
+4. Create a temporary notebook with `cli-anything-notebooklm notebook create "CLI Anything Smoke Test"`.
+5. Add a simple text or URL source.
+6. Run `cli-anything-notebooklm chat ask "Summarize the notebook."`.
+7. Generate one artifact, such as a report.
+8. Download the artifact to a temporary local path.
+9. Delete the temporary notebook manually after verification.
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/utils/__init__.py b/notebooklm/agent-harness/cli_anything/notebooklm/utils/__init__.py
new file mode 100644
index 000000000..2f7adc5be
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/utils/__init__.py
@@ -0,0 +1 @@
+"""Utility modules for the NotebookLM harness."""
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py b/notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py
new file mode 100644
index 000000000..4ff424097
--- /dev/null
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py
@@ -0,0 +1,91 @@
+"""NotebookLM backend adapter.
+
+This module wraps an installed `notebooklm` CLI for use inside a CLI-Anything
+harness. It does not implement a Google official API client.
+
+References:
+- CLI-Anything methodology: https://github.com/HKUDS/CLI-Anything
+- notebooklm-py project: https://github.com/teng-lin/notebooklm-py
+
+Security rules:
+- never print credential files or cookies
+- never commit auth state into the repository
+- prefer explicit notebook IDs
+"""
+
+from __future__ import annotations
+
+import json
+import re
+import shutil
+import subprocess
+
+
+def require_notebooklm() -> str:
+ """Resolve the notebooklm command from PATH."""
+ path = shutil.which("notebooklm")
+ if path:
+ return path
+ raise RuntimeError(
+ "notebooklm command not found. Install it with:\n"
+ " python3 -m pip install --user 'notebooklm-py[browser]'\n"
+ " python3 -m playwright install chromium"
+ )
+
+
+def build_command(
+ args: list[str],
+ *,
+ notebook_id: str | None = None,
+ json_output: bool = False,
+) -> list[str]:
+ """Build a notebooklm command with explicit notebook context."""
+ command = ["notebooklm", *args]
+ if notebook_id:
+ command.extend(["-n", notebook_id])
+ if json_output:
+ command.append("--json")
+ return command
+
+
+def sanitize_error(text: str) -> str:
+ """Redact local auth file paths from stderr/stdout."""
+ patterns = [
+ r"/Users/[^/\s]+/\.notebooklm/storage_state\.json",
+ r"/home/[^/\s]+/\.notebooklm/storage_state\.json",
+ r"[A-Za-z]:\\\\Users\\\\[^\\\s]+\\\\\.notebooklm\\\\storage_state\.json",
+ ]
+ sanitized = text
+ for pattern in patterns:
+ sanitized = re.sub(pattern, "[redacted-auth-path]", sanitized)
+ sanitized = sanitized.replace("storage_state.json", "[redacted-auth-path]")
+ return sanitized
+
+
+def run_notebooklm(
+ args: list[str],
+ *,
+ notebook_id: str | None = None,
+ json_output: bool = False,
+) -> dict | str:
+ """Run notebooklm and optionally parse JSON output."""
+ command = build_command(
+ args,
+ notebook_id=notebook_id,
+ json_output=json_output,
+ )
+ command[0] = require_notebooklm()
+
+ result = subprocess.run(
+ command,
+ capture_output=True,
+ text=True,
+ check=False,
+ )
+
+ if result.returncode != 0:
+ raise RuntimeError(sanitize_error(result.stderr or result.stdout))
+
+ if json_output:
+ return json.loads(result.stdout or "{}")
+ return result.stdout.strip()
diff --git a/notebooklm/agent-harness/setup.py b/notebooklm/agent-harness/setup.py
new file mode 100644
index 000000000..c6679bd04
--- /dev/null
+++ b/notebooklm/agent-harness/setup.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+"""
+setup.py for cli-anything-notebooklm
+
+Install with: pip install -e .
+"""
+
+from setuptools import setup, find_namespace_packages
+
+with open("cli_anything/notebooklm/README.md", "r", encoding="utf-8") as fh:
+ long_description = fh.read()
+
+setup(
+ name="cli-anything-notebooklm",
+ version="0.1.0",
+ author="cli-anything contributors",
+ author_email="",
+ description="Experimental CLI harness for NotebookLM via an installed notebooklm CLI. Unofficial and community-maintained.",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ url="https://github.com/HKUDS/CLI-Anything",
+ packages=find_namespace_packages(include=["cli_anything.*"]),
+ classifiers=[
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ ],
+ python_requires=">=3.10",
+ install_requires=[
+ "click>=8.0.0",
+ "prompt-toolkit>=3.0.0",
+ ],
+ extras_require={
+ "dev": [
+ "pytest>=7.0.0",
+ "pytest-cov>=4.0.0",
+ ],
+ },
+ entry_points={
+ "console_scripts": [
+ "cli-anything-notebooklm=cli_anything.notebooklm.notebooklm_cli:main",
+ ],
+ },
+ package_data={
+ "cli_anything.notebooklm": ["skills/*.md"],
+ },
+ include_package_data=True,
+ zip_safe=False,
+)
From 0a4d8237c5616101d7e3f09bfc7adcfb79e1a345 Mon Sep 17 00:00:00 2001
From: liuche <1257067825@qq.com>
Date: Tue, 17 Mar 2026 20:49:31 +0800
Subject: [PATCH 2/4] fix: address notebooklm review feedback
---
.../cli_anything/notebooklm/README.md | 6 ++--
.../cli_anything/notebooklm/notebooklm_cli.py | 2 +-
.../cli_anything/notebooklm/skills/SKILL.md | 6 ++--
.../cli_anything/notebooklm/tests/TEST.md | 25 +++++++++++++
.../notebooklm/tests/test_cli_smoke.py | 19 ++++++++++
.../notebooklm/tests/test_core.py | 16 +++++++++
.../notebooklm/utils/notebooklm_backend.py | 35 ++++++++++++++++++-
7 files changed, 101 insertions(+), 8 deletions(-)
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/README.md b/notebooklm/agent-harness/cli_anything/notebooklm/README.md
index 2751f83d8..88fff930f 100644
--- a/notebooklm/agent-harness/cli_anything/notebooklm/README.md
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/README.md
@@ -38,7 +38,7 @@ python3 -m playwright install chromium
# Show help
cli-anything-notebooklm --help
-# Check auth state
+# Check auth state (wraps `notebooklm auth check`)
cli-anything-notebooklm auth status
# List notebooks
@@ -57,7 +57,7 @@ python3 -m cli_anything.notebooklm.notebooklm_cli --help
| Group | Purpose |
| --- | --- |
-| `auth` | login, auth status, and lightweight auth checks |
+| `auth` | login helpers and authentication checks |
| `notebook` | list, create, and summarize notebooks |
| `source` | inspect sources and add URL sources |
| `chat` | ask questions and inspect history |
@@ -78,7 +78,7 @@ cli-anything-notebooklm artifact generate-report --notebook nb_123
## For AI Agents
- Prefer explicit notebook IDs with `--notebook` instead of relying on ambient state.
-- Use `--json` whenever the command supports machine-readable output.
+- Use `--json` only on commands whose upstream `notebooklm` subcommand supports machine-readable output.
- Treat NotebookLM auth state as sensitive local data and never print cookie or storage files.
- Treat this harness as a thin wrapper around `notebooklm`, not a reimplementation of NotebookLM.
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py b/notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
index 53640752b..5da8612e6 100644
--- a/notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
@@ -84,7 +84,7 @@ def auth():
@handle_error
def auth_status():
"""Check authentication status."""
- emit(run_notebooklm(["status"], json_output=_json_output))
+ emit(run_notebooklm(["auth", "check"], json_output=_json_output))
@auth.command("login")
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md b/notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
index 9a8c6b514..12940c3a7 100644
--- a/notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
@@ -47,7 +47,7 @@ cli-anything-notebooklm --json notebook list
| Group | Purpose |
| --- | --- |
-| `auth` | login and auth status |
+| `auth` | login and auth validation |
| `notebook` | notebook list, create, summary |
| `source` | source listing and URL add |
| `chat` | ask questions and inspect history |
@@ -60,12 +60,12 @@ cli-anything-notebooklm --json notebook list
1. Check auth with `cli-anything-notebooklm auth status`
2. Discover notebook IDs with `cli-anything-notebooklm --json notebook list`
3. Use explicit `--notebook` for follow-up commands
-4. Prefer `--json` for list and inspection commands
+4. Prefer `--json` only where the upstream `notebooklm` command supports it
## Agent Guidance
- Prefer explicit notebook IDs with `--notebook`.
-- Use `--json` for machine-readable output.
+- Use `--json` for machine-readable output only on commands that support it upstream.
- Treat this harness as experimental and unofficial.
- Do not expose auth files or cookies in logs.
- NotebookLM is a Google product; this harness is unofficial and not affiliated with Google.
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md b/notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
index 26a3afe23..24b37f86a 100644
--- a/notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
@@ -62,3 +62,28 @@ python3 -m cli_anything.notebooklm.notebooklm_cli --help
- Added doc-level assertions so the package README and skill file now explicitly cover installation, tests, safety boundaries, and unofficial Google attribution.
- Added `_resolve_cli`-style subprocess smoke coverage so the CLI can be exercised through a resolved command path, not only through Click's in-process test runner.
+
+## Review Fix Verification
+
+Verified on 2026-03-17 after addressing PR review feedback about JSON passthrough and auth command semantics.
+
+### Commands Run
+
+```bash
+python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q
+python3 -m pytest cli_anything/notebooklm/tests/test_cli_smoke.py -q
+python3 -m pytest cli_anything/notebooklm/tests -q
+python3 -m cli_anything.notebooklm.notebooklm_cli --json auth login
+```
+
+### Results
+
+- targeted backend tests: pass
+- targeted CLI routing tests: pass
+- full NotebookLM harness suite: pass
+- `--json auth login`: fails fast with a structured JSON error instead of passing an invalid `--json` flag through to upstream login
+
+### Notes
+
+- `auth status` now wraps upstream `notebooklm auth check`, which matches authentication semantics.
+- JSON passthrough is now limited to wrapper commands whose upstream `notebooklm` command has verified `--json` support.
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py
index e9c440f64..d803d5758 100644
--- a/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py
@@ -56,6 +56,25 @@ class TestSubcommandHelp:
assert "List notebooks" in result.output
+class TestCommandRouting:
+ def test_auth_status_routes_to_auth_check(self, monkeypatch):
+ calls = []
+
+ def fake_run(args, **kwargs):
+ calls.append((args, kwargs))
+ return {"ok": True}
+
+ monkeypatch.setattr(
+ "cli_anything.notebooklm.notebooklm_cli.run_notebooklm",
+ fake_run,
+ )
+
+ result = CliRunner().invoke(cli, ["auth", "status"])
+
+ assert result.exit_code == 0
+ assert calls == [(["auth", "check"], {"json_output": False})]
+
+
class TestModuleExecution:
def test_python_m_module_help_emits_output(self):
result = subprocess.run(
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py
index 7ef1a4889..bc9d2f770 100644
--- a/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py
@@ -9,7 +9,9 @@ import pytest
from cli_anything.notebooklm.core.session import Session
from cli_anything.notebooklm.utils.notebooklm_backend import (
build_command,
+ command_supports_json,
require_notebooklm,
+ run_notebooklm,
sanitize_error,
)
@@ -45,6 +47,20 @@ class TestCommandBuilder:
command = build_command(["list"])
assert command == ["notebooklm", "list"]
+ def test_command_supports_json_for_verified_command(self):
+ assert command_supports_json(["download", "report"]) is True
+
+ def test_command_supports_json_rejects_unsupported_command(self):
+ assert command_supports_json(["login"]) is False
+
+
+class TestRunNotebooklm:
+ def test_run_notebooklm_rejects_json_for_unsupported_command(self):
+ with patch("cli_anything.notebooklm.utils.notebooklm_backend.subprocess.run") as run_mock:
+ with pytest.raises(RuntimeError, match="JSON output is not supported for command: login"):
+ run_notebooklm(["login"], json_output=True)
+ run_mock.assert_not_called()
+
class TestErrorSanitization:
def test_sanitize_error_redacts_storage_state_path(self):
diff --git a/notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py b/notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py
index 4ff424097..6603d980f 100644
--- a/notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py
+++ b/notebooklm/agent-harness/cli_anything/notebooklm/utils/notebooklm_backend.py
@@ -21,6 +21,23 @@ import shutil
import subprocess
+JSON_SUPPORTED_COMMANDS = {
+ ("auth", "check"),
+ ("status",),
+ ("list",),
+ ("create",),
+ ("source", "list"),
+ ("source", "add"),
+ ("ask",),
+ ("history",),
+ ("artifact", "list"),
+ ("generate", "report"),
+ ("download", "report"),
+ ("share", "status"),
+}
+TWO_PART_COMMAND_GROUPS = {"auth", "source", "artifact", "generate", "download", "share"}
+
+
def require_notebooklm() -> str:
"""Resolve the notebooklm command from PATH."""
path = shutil.which("notebooklm")
@@ -33,6 +50,17 @@ def require_notebooklm() -> str:
)
+def command_supports_json(args: list[str]) -> bool:
+ """Return whether the wrapped notebooklm command supports --json."""
+ if not args:
+ return False
+ if len(args) > 1 and args[0] in TWO_PART_COMMAND_GROUPS:
+ key = tuple(args[:2])
+ else:
+ key = tuple(args[:1])
+ return key in JSON_SUPPORTED_COMMANDS
+
+
def build_command(
args: list[str],
*,
@@ -43,7 +71,7 @@ def build_command(
command = ["notebooklm", *args]
if notebook_id:
command.extend(["-n", notebook_id])
- if json_output:
+ if json_output and command_supports_json(args):
command.append("--json")
return command
@@ -69,6 +97,11 @@ def run_notebooklm(
json_output: bool = False,
) -> dict | str:
"""Run notebooklm and optionally parse JSON output."""
+ if json_output and not command_supports_json(args):
+ raise RuntimeError(
+ f"JSON output is not supported for command: {' '.join(args)}"
+ )
+
command = build_command(
args,
notebook_id=notebook_id,
From 8e93f3bf426517242d1e708c283815a322d518fd Mon Sep 17 00:00:00 2001
From: liuche <1257067825@qq.com>
Date: Wed, 18 Mar 2026 08:50:47 +0800
Subject: [PATCH 3/4] docs: surface notebooklm harness and trim PR scope
---
.gitignore | 7 +-
README.md | 31 +++
.../2026-03-17-notebooklm-harness-scaffold.md | 192 ------------------
docs/plans/2026-03-17-notebooklm-pr-polish.md | 116 -----------
registry.json | 177 ++++++++++++++++
5 files changed, 214 insertions(+), 309 deletions(-)
delete mode 100644 docs/plans/2026-03-17-notebooklm-harness-scaffold.md
delete mode 100644 docs/plans/2026-03-17-notebooklm-pr-polish.md
create mode 100644 registry.json
diff --git a/.gitignore b/.gitignore
index d2c12313f..1869e1618 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,6 @@
!/CONTRIBUTING.md
!/assets/
!/.claude-plugin/
-!/docs/
!/.github/
# Step 3: Allow cli-anything-plugin, codex-skill, and skill_generation tests
@@ -102,6 +101,12 @@ assets/gen_typing_gif.py
!README_CN.md
!opencode-commands/
!/qoder-plugin/
+
+# Step 10: Allow CLI Hub registry and frontend
+!/registry.json
+!/docs/
+/docs/*
+!/docs/hub/
!/notebooklm/
/notebooklm/*
/notebooklm/.*
diff --git a/README.md b/README.md
index d5add4e3e..9ca71c176 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ CLI-Anything: Bridging the Gap Between AI Agents and the World's Software
+
@@ -24,6 +25,8 @@ CLI-Anything: Bridging the Gap Between AI Agents and the World's Software
@@ -38,6 +41,10 @@ CLI-Anything: Bridging the Gap Between AI Agents and the World's Software Thanks to all invaluable efforts from the community! More updates continuously on the way everyday..
+- **2026-03-18** 🧠 Added an **experimental NotebookLM harness scaffold** from the community. It wraps the installed `notebooklm` CLI for notebook discovery, source management, chat, artifact workflows, downloads, and sharing while preserving a clear experimental/community-maintained boundary.
+
+- **2026-03-17** 🌐 Launched the **[CLI-Hub](https://hkuds.github.io/CLI-Anything/hub/)** — a central registry where you can browse, search, and install any CLI with a single `pip` command. Contributors can add new CLIs or update existing ones by simply opening a PR with a `registry.json` entry. The hub updates automatically on merge.
+
- **2026-03-16** 🤖 Added **SKILL.md generation** (Phase 6.5) — every generated CLI now ships with an AI-discoverable skill definition inside the Python package. ReplSkin auto-detects the skill file after `pip install`, and the REPL banner displays the absolute path for agents. Includes `skill_generator.py`, Jinja2 template, `package_data` in all setup.py files, and 51 new tests.
- **2026-03-15** 🐾 Support for **OpenClaw** from the community! Merged Windows `cygpath` guard to ensure CLI-Anything works reliably in Windows bash environments. Community contributions continue to strengthen cross-platform support.
@@ -611,6 +618,29 @@ Each application received complete, production-ready CLI interfaces — not demo
> **100% pass rate** across all 1,588 tests — 1,138 unit tests + 450 end-to-end tests.
+### 🧪 Experimental / Community Harnesses
+
+These contributions extend CLI-Anything into adjacent agent-native surfaces while keeping their support boundary explicit.
+
+
+
+| Software |
+Domain |
+CLI Command |
+Backend |
+Tests |
+
+
+| 🧠 NotebookLM |
+AI Research & Knowledge Workspace |
+cli-anything-notebooklm |
+Installed notebooklm CLI (notebooklm-py) |
+✅ 21 |
+
+
+
+> Experimental/community-maintained scaffold: wraps the installed NotebookLM CLI for auth checks, notebook selection, source ingestion, Q&A, artifact generation, downloads, and sharing. Unofficial and not affiliated with Google.
+
---
## 📊 Test Results
@@ -701,6 +731,7 @@ cli-anything/
├── 📐 drawio/agent-harness/ # Draw.io CLI (138 tests)
├── 🧜 mermaid/agent-harness/ # Mermaid Live Editor CLI (10 tests)
├── ✨ anygen/agent-harness/ # AnyGen CLI (50 tests)
+├── 🧠 notebooklm/agent-harness/ # NotebookLM CLI (experimental, 21 tests)
└── 🖼️ comfyui/agent-harness/ # ComfyUI CLI (70 tests)
```
diff --git a/docs/plans/2026-03-17-notebooklm-harness-scaffold.md b/docs/plans/2026-03-17-notebooklm-harness-scaffold.md
deleted file mode 100644
index 5d38a7faa..000000000
--- a/docs/plans/2026-03-17-notebooklm-harness-scaffold.md
+++ /dev/null
@@ -1,192 +0,0 @@
-# NotebookLM Harness Scaffold Implementation Plan
-
-> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
-
-**Goal:** Add an experimental `cli-anything-notebooklm` scaffold that wraps an installed `notebooklm` CLI, includes attribution files, and establishes the first round of tests and docs.
-
-**Architecture:** Create a service-style harness under `notebooklm/agent-harness/` that mirrors the existing CLI-Anything package layout. The backend adapter will shell out to the installed `notebooklm` command, sanitize sensitive errors, and keep notebook context in a lightweight session file for REPL use.
-
-**Tech Stack:** Python 3.10+, Click, prompt-toolkit, pytest, subprocess-based backend wrapper
-
-### Task 1: Establish the tracked scaffold area
-
-**Files:**
-- Modify: `.gitignore`
-- Create: `docs/plans/2026-03-17-notebooklm-harness-scaffold.md`
-
-**Step 1: Write the failing test**
-
-No behavior test for this task. It is repository plumbing needed to track the new harness path and plan document.
-
-**Step 2: Run test to verify it fails**
-
-Not applicable.
-
-**Step 3: Write minimal implementation**
-
-- Allow `docs/`
-- Allow `notebooklm/`
-- Allow `notebooklm/agent-harness/`
-
-**Step 4: Run test to verify it passes**
-
-Run: `git status --short`
-Expected: new scaffold files are visible to git
-
-**Step 5: Commit**
-
-```bash
-git add .gitignore docs/plans/2026-03-17-notebooklm-harness-scaffold.md
-git commit -m "chore: prepare notebooklm harness scaffold"
-```
-
-### Task 2: Write the first failing backend tests
-
-**Files:**
-- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py`
-- Test: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py`
-
-**Step 1: Write the failing test**
-
-Cover:
-- backend finds `notebooklm` on PATH
-- backend raises clear install guidance if missing
-- backend builds explicit commands with `-n `
-- backend sanitizes secret-bearing auth path output
-- session file stores current notebook context
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q`
-Expected: FAIL with import errors because the package does not exist yet
-
-**Step 3: Write minimal implementation**
-
-Create:
-- `cli_anything/notebooklm/utils/notebooklm_backend.py`
-- `cli_anything/notebooklm/core/session.py`
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add notebooklm/agent-harness/cli_anything/notebooklm
-git commit -m "feat: add notebooklm backend scaffold"
-```
-
-### Task 3: Write the first failing CLI tests
-
-**Files:**
-- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py`
-- Test: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py`
-
-**Step 1: Write the failing test**
-
-Cover:
-- root `--help` shows experimental NotebookLM wording
-- root `--help` exposes command groups
-- `auth status --help` and `notebook list --help` execute
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_cli_smoke.py -q`
-Expected: FAIL because `notebooklm_cli.py` is missing
-
-**Step 3: Write minimal implementation**
-
-Create:
-- `cli_anything/notebooklm/notebooklm_cli.py`
-- `cli_anything/notebooklm/__init__.py`
-- `cli_anything/notebooklm/__main__.py`
-
-Use placeholder command handlers that route through the backend wrapper.
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_cli_smoke.py -q`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add notebooklm/agent-harness/cli_anything/notebooklm/notebooklm_cli.py
-git commit -m "feat: add notebooklm cli skeleton"
-```
-
-### Task 4: Add packaging and attribution docs
-
-**Files:**
-- Create: `notebooklm/agent-harness/setup.py`
-- Create: `notebooklm/agent-harness/NOTEBOOKLM.md`
-- Create: `notebooklm/agent-harness/ATTRIBUTION.md`
-- Create: `notebooklm/agent-harness/THIRD_PARTY_NOTICES.md`
-- Create: `notebooklm/agent-harness/cli_anything/notebooklm/README.md`
-- Create: `notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md`
-- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md`
-- Create: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_manual_e2e.md`
-
-**Step 1: Write the failing test**
-
-Add assertions that:
-- `setup.py` exposes `cli-anything-notebooklm`
-- skill file exists
-- README includes acknowledgement text
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py -q`
-Expected: FAIL on missing files and packaging metadata
-
-**Step 3: Write minimal implementation**
-
-Create all packaging and documentation files with explicit attribution and experimental disclaimers.
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add notebooklm/agent-harness
-git commit -m "docs: add notebooklm harness attribution and packaging"
-```
-
-### Task 5: Verify the scaffold end to end
-
-**Files:**
-- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md`
-
-**Step 1: Write the failing test**
-
-No new behavior. This task is verification and documentation.
-
-**Step 2: Run test to verify it fails**
-
-Not applicable.
-
-**Step 3: Write minimal implementation**
-
-Run:
-- `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
-- `cd notebooklm/agent-harness && python3 -m cli_anything.notebooklm.notebooklm_cli --help`
-
-Append the verification notes to `TEST.md`.
-
-**Step 4: Run test to verify it passes**
-
-Expected:
-- targeted tests PASS
-- CLI help exits 0
-
-**Step 5: Commit**
-
-```bash
-git add notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
-git commit -m "test: verify notebooklm harness scaffold"
-```
diff --git a/docs/plans/2026-03-17-notebooklm-pr-polish.md b/docs/plans/2026-03-17-notebooklm-pr-polish.md
deleted file mode 100644
index 3b2f0d536..000000000
--- a/docs/plans/2026-03-17-notebooklm-pr-polish.md
+++ /dev/null
@@ -1,116 +0,0 @@
-# NotebookLM PR Polish Implementation Plan
-
-> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
-
-**Goal:** Tighten the experimental NotebookLM harness into a more upstream-ready contribution with stronger docs, explicit attribution, and subprocess-level CLI smoke coverage.
-
-**Architecture:** Keep the current service-style wrapper architecture intact. Improve PR readiness by expanding package-facing documentation and adding lightweight subprocess tests that verify the packaged CLI interface without requiring a live authenticated NotebookLM session.
-
-**Tech Stack:** Python 3, Click, pytest, subprocess, Markdown docs
-
-### Task 1: Add failing tests for PR-facing expectations
-
-**Files:**
-- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_core.py`
-- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/test_cli_smoke.py`
-
-**Step 1: Write the failing test**
-
-Add tests that require:
-- README to document installation, test execution, safety boundaries, and references
-- SKILL.md to include installation, usage, and explicit unofficial guidance
-- subprocess CLI help to render through a resolved `cli-anything-notebooklm` entry path
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
-
-Expected: FAIL on missing README/SKILL sections or missing subprocess helper behavior
-
-**Step 3: Write minimal implementation**
-
-Expand documentation and add the smallest test helper needed for subprocess smoke coverage.
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
-
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add notebooklm/agent-harness/cli_anything/notebooklm/tests notebooklm/agent-harness/cli_anything/notebooklm/README.md notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
-git commit -m "test: harden notebooklm harness smoke coverage"
-```
-
-### Task 2: Improve docs for upstream review
-
-**Files:**
-- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/README.md`
-- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md`
-- Modify: `notebooklm/agent-harness/NOTEBOOKLM.md`
-
-**Step 1: Write the failing test**
-
-Covered by Task 1 doc assertions.
-
-**Step 2: Run test to verify it fails**
-
-Covered by Task 1.
-
-**Step 3: Write minimal implementation**
-
-Document:
-- installation and local prerequisites
-- run and test commands
-- command group overview
-- agent guidance and safe-by-default behavior
-- explicit references and unofficial attribution boundary
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests/test_core.py cli_anything/notebooklm/tests/test_cli_smoke.py -q`
-
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add notebooklm/agent-harness/NOTEBOOKLM.md notebooklm/agent-harness/cli_anything/notebooklm/README.md notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md
-git commit -m "docs: polish notebooklm harness contribution docs"
-```
-
-### Task 3: Verify and record final state
-
-**Files:**
-- Modify: `notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md`
-
-**Step 1: Write the failing test**
-
-No new behavior test. This task records verification evidence.
-
-**Step 2: Run test to verify it fails**
-
-Not applicable.
-
-**Step 3: Write minimal implementation**
-
-Run:
-- `cd notebooklm/agent-harness && python3 -m pytest cli_anything/notebooklm/tests -q`
-- `cd notebooklm/agent-harness && python3 -m cli_anything.notebooklm.notebooklm_cli --help`
-
-Append fresh results to `TEST.md`.
-
-**Step 4: Run test to verify it passes**
-
-Expected:
-- all NotebookLM scaffold tests PASS
-- module help exits 0 and prints command groups
-
-**Step 5: Commit**
-
-```bash
-git add notebooklm/agent-harness/cli_anything/notebooklm/tests/TEST.md
-git commit -m "test: record notebooklm harness verification"
-```
diff --git a/registry.json b/registry.json
new file mode 100644
index 000000000..4758c86db
--- /dev/null
+++ b/registry.json
@@ -0,0 +1,177 @@
+{
+ "meta": {
+ "repo": "https://github.com/HKUDS/CLI-Anything",
+ "description": "CLI-Hub — Agent-native stateful CLI interfaces for softwares, codebases, and Web Services",
+ "updated": "2026-03-18"
+ },
+ "clis": [
+ {
+ "name": "anygen",
+ "display_name": "AnyGen",
+ "version": "1.0.0",
+ "description": "Generate docs, slides, websites and more via AnyGen cloud API",
+ "requires": "ANYGEN_API_KEY",
+ "homepage": "https://anygen.com",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=anygen/agent-harness",
+ "entry_point": "cli-anything-anygen",
+ "skill_md": "anygen/agent-harness/cli_anything/anygen/skills/SKILL.md",
+ "category": "generation"
+ },
+ {
+ "name": "audacity",
+ "display_name": "Audacity",
+ "version": "1.0.0",
+ "description": "Audio editing and processing via sox",
+ "requires": "sox (apt install sox)",
+ "homepage": "https://www.audacityteam.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=audacity/agent-harness",
+ "entry_point": "cli-anything-audacity",
+ "skill_md": "audacity/agent-harness/cli_anything/audacity/skills/SKILL.md",
+ "category": "audio"
+ },
+ {
+ "name": "blender",
+ "display_name": "Blender",
+ "version": "1.0.0",
+ "description": "3D modeling, animation, and rendering via blender --background --python",
+ "requires": "blender",
+ "homepage": "https://www.blender.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=blender/agent-harness",
+ "entry_point": "cli-anything-blender",
+ "skill_md": "blender/agent-harness/cli_anything/blender/skills/SKILL.md",
+ "category": "3d"
+ },
+ {
+ "name": "comfyui",
+ "display_name": "ComfyUI",
+ "version": "1.0.0",
+ "description": "AI image generation workflow management via ComfyUI REST API",
+ "requires": "ComfyUI running at http://localhost:8188",
+ "homepage": "https://github.com/comfyanonymous/ComfyUI",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=comfyui/agent-harness",
+ "entry_point": "cli-anything-comfyui",
+ "skill_md": null,
+ "category": "ai"
+ },
+ {
+ "name": "drawio",
+ "display_name": "Draw.io",
+ "version": "1.0.0",
+ "description": "Diagram creation and export via draw.io CLI",
+ "requires": "draw.io desktop app",
+ "homepage": "https://www.drawio.com",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=drawio/agent-harness",
+ "entry_point": "cli-anything-drawio",
+ "skill_md": "drawio/agent-harness/cli_anything/drawio/skills/SKILL.md",
+ "category": "diagrams"
+ },
+ {
+ "name": "gimp",
+ "display_name": "GIMP",
+ "version": "1.0.0",
+ "description": "Raster image processing via gimp -i -b (batch mode)",
+ "requires": "gimp (apt install gimp)",
+ "homepage": "https://www.gimp.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=gimp/agent-harness",
+ "entry_point": "cli-anything-gimp",
+ "skill_md": "gimp/agent-harness/cli_anything/gimp/skills/SKILL.md",
+ "category": "image"
+ },
+ {
+ "name": "inkscape",
+ "display_name": "Inkscape",
+ "version": "1.0.0",
+ "description": "SVG vector graphics with export via inkscape --export-filename",
+ "requires": "inkscape (apt install inkscape)",
+ "homepage": "https://inkscape.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=inkscape/agent-harness",
+ "entry_point": "cli-anything-inkscape",
+ "skill_md": "inkscape/agent-harness/cli_anything/inkscape/skills/SKILL.md",
+ "category": "image"
+ },
+ {
+ "name": "kdenlive",
+ "display_name": "Kdenlive",
+ "version": "1.0.0",
+ "description": "Video editing and rendering via melt",
+ "requires": "melt (apt install melt)",
+ "homepage": "https://kdenlive.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=kdenlive/agent-harness",
+ "entry_point": "cli-anything-kdenlive",
+ "skill_md": "kdenlive/agent-harness/cli_anything/kdenlive/skills/SKILL.md",
+ "category": "video"
+ },
+ {
+ "name": "libreoffice",
+ "display_name": "LibreOffice",
+ "version": "1.0.0",
+ "description": "Create and manipulate ODF documents, export to PDF/DOCX/XLSX/PPTX via headless mode",
+ "requires": "libreoffice",
+ "homepage": "https://www.libreoffice.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=libreoffice/agent-harness",
+ "entry_point": "cli-anything-libreoffice",
+ "skill_md": "libreoffice/agent-harness/cli_anything/libreoffice/skills/SKILL.md",
+ "category": "office"
+ },
+ {
+ "name": "mermaid",
+ "display_name": "Mermaid",
+ "version": "1.0.0",
+ "description": "Mermaid Live Editor state files and renderer URLs",
+ "requires": null,
+ "homepage": "https://mermaid.js.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=mermaid/agent-harness",
+ "entry_point": "cli-anything-mermaid",
+ "skill_md": null,
+ "category": "diagrams"
+ },
+ {
+ "name": "notebooklm",
+ "display_name": "NotebookLM",
+ "version": "0.1.0",
+ "description": "Experimental NotebookLM harness scaffold wrapping the installed notebooklm CLI for notebook, source, chat, artifact, download, and sharing workflows",
+ "requires": "notebooklm CLI from notebooklm-py + valid local NotebookLM login session",
+ "homepage": "https://notebooklm.google.com",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=notebooklm/agent-harness",
+ "entry_point": "cli-anything-notebooklm",
+ "skill_md": "notebooklm/agent-harness/cli_anything/notebooklm/skills/SKILL.md",
+ "category": "ai"
+ },
+ {
+ "name": "obs-studio",
+ "display_name": "OBS Studio",
+ "version": "1.0.0",
+ "description": "Create and manage streaming/recording scenes via command line",
+ "requires": "obs-studio",
+ "homepage": "https://obsproject.com",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=obs-studio/agent-harness",
+ "entry_point": "cli-anything-obs-studio",
+ "skill_md": "obs-studio/agent-harness/cli_anything/obs_studio/skills/SKILL.md",
+ "category": "streaming"
+ },
+ {
+ "name": "shotcut",
+ "display_name": "Shotcut",
+ "version": "1.0.0",
+ "description": "Video editing and rendering via melt/ffmpeg",
+ "requires": "melt (apt install melt), ffmpeg (apt install ffmpeg)",
+ "homepage": "https://shotcut.org",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=shotcut/agent-harness",
+ "entry_point": "cli-anything-shotcut",
+ "skill_md": "shotcut/agent-harness/cli_anything/shotcut/skills/SKILL.md",
+ "category": "video"
+ },
+ {
+ "name": "zoom",
+ "display_name": "Zoom",
+ "version": "1.0.0",
+ "description": "Meeting management via Zoom REST API (OAuth2)",
+ "requires": "Zoom account + OAuth app credentials",
+ "homepage": "https://zoom.us",
+ "install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=zoom/agent-harness",
+ "entry_point": "cli-anything-zoom",
+ "skill_md": "zoom/agent-harness/cli_anything/zoom/skills/SKILL.md",
+ "category": "communication"
+ }
+ ]
+}
From 54f78f65d2ef8a2e67e96d46fd46a350b3994daa Mon Sep 17 00:00:00 2001
From: liuche <1257067825@qq.com>
Date: Wed, 18 Mar 2026 15:30:14 +0800
Subject: [PATCH 4/4] docs: trim notebooklm readme mentions
---
README.md | 24 ------------------------
1 file changed, 24 deletions(-)
diff --git a/README.md b/README.md
index 333a71783..c1c353bbd 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,6 @@ CLI-Anything: Bridging the Gap Between AI Agents and the World's Software Thanks to all invaluable efforts from the community! More updates continuously on the way everyday..
-- **2026-03-18** 🧠 Added an **experimental NotebookLM harness scaffold** from the community. It wraps the installed `notebooklm` CLI for notebook discovery, source management, chat, artifact workflows, downloads, and sharing while preserving a clear experimental/community-maintained boundary.
- **2026-03-17** 🌐 Launched the **[CLI-Hub](https://hkuds.github.io/CLI-Anything/hub/)** — a central registry where you can browse, search, and install any CLI with a single `pip` command. Contributors can add new CLIs or update existing ones by simply opening a PR with a `registry.json` entry. The hub updates automatically on merge.
- **2026-03-16** 🤖 Added **SKILL.md generation** (Phase 6.5) — every generated CLI now ships with an AI-discoverable skill definition inside the Python package. ReplSkin auto-detects the skill file after `pip install`, and the REPL banner displays the absolute path for agents. Includes `skill_generator.py`, Jinja2 template, `package_data` in all setup.py files, and 51 new tests.
@@ -617,29 +616,6 @@ Each application received complete, production-ready CLI interfaces — not demo
> **100% pass rate** across all 1,588 tests — 1,138 unit tests + 450 end-to-end tests.
-### 🧪 Experimental / Community Harnesses
-
-These contributions extend CLI-Anything into adjacent agent-native surfaces while keeping their support boundary explicit.
-
-
-
-| Software |
-Domain |
-CLI Command |
-Backend |
-Tests |
-
-
-| 🧠 NotebookLM |
-AI Research & Knowledge Workspace |
-cli-anything-notebooklm |
-Installed notebooklm CLI (notebooklm-py) |
-✅ 21 |
-
-
-
-> Experimental/community-maintained scaffold: wraps the installed NotebookLM CLI for auth checks, notebook selection, source ingestion, Q&A, artifact generation, downloads, and sharing. Unofficial and not affiliated with Google.
-
---
## 📊 Test Results