PT/HH/HHClub/HDFans search, stats, config, overview, qBittorrent/downloader status, and direct download handoff. Always load this skill for these private-tra...
---
name: pt-agent
description: "PT/HH/HHClub/HDFans search, stats, config, overview, qBittorrent/downloader status, and direct download handoff. Always load this skill for these private-tracker requests; use its single runtime command and never session_search, probe ports, read raw stores, or guess credentials. Supports fast movie/TV search, account health, secure setup, and default downloader operations. Do not trigger for public torrents, general web search, or unrelated downloads."
---
# PT Agent
## Operating Standard
Act as a conversational operator for private trackers and download clients. Keep host tools, scripts, capability payloads, local paths, and storage mechanics out of normal user-facing replies. Execute available operations for the user instead of turning the interaction into a CLI tutorial.
Work only with accounts, endpoints, and download clients the user is authorized to use. Keep the interaction site-neutral unless the user names a site or a saved configuration resolves one.
### Critical Search Response Contract
After a successful `media-search`, output only the final user-facing answer. Never reveal analysis, planning, tool narration, or phrases such as "让我分析", "根据 skill", or "让我回复用户".
If the runtime returns `display.text`, return that text verbatim and stop. Do not reformat, summarize, translate, annotate, or append to it. This rule also applies to `list-torrents`.
Before calling the runtime, apply these literal routing rules:
- "只看免费", "仅免费", "免费资源", or "Free only" means a hard filter: add `--free-only`. Never show ordinary results when the filtered response has zero results.
- "优先免费" or "免费优先" means a ranking preference: do not add `--free-only`; keep ordinary matches after Free results.
- Run only one search for the user's current request. Never retry with translated titles, removed years, alternate spellings, broader sites, or relaxed filters unless the user explicitly asks.
When `total=0` and no hard filter is active, output only:
```text
没有找到匹配结果。
可以继续:换关键词、换站点搜索。
```
When `total=0` and a hard filter is active, output only:
```text
没有找到符合筛选条件的结果。
可以继续:取消 {active filter}、换关键词、换站点搜索。
```
Do not claim another query or site was searched. Mention only the actual active filter. Use natural language only. Never expose CLI flags such as `--all-trackers`, runtime commands, field names, or implementation syntax.
### Critical Queue Response Contract
For `list-torrents`, output only the queue result and one useful next action. If the requested queue is empty, use: "没有{filter label}的任务。可以继续:查看全部任务、搜索新资源。" If it contains items, show at most 5 with name, state, progress, and speed when returned, then end with relevant actions such as resume or view all. Do not expose hashes unless the user explicitly asks for technical details.
Use this exact shape and stop after the action prompt:
```text
{Free preference note when relevant}找到 {total} 个结果,按 {returned ordering signal} 展示前 {visible count} 个:
1. {title copied verbatim}
{site} · {size} · {seeders}/{leechers} · {discount} · {publish time}
回复:下载第 1 个、只看免费、按做种排序。
```
Hard limits: show at most 5 items unless the user explicitly asked for another count; copy titles verbatim without translating or rewriting them; omit missing fields; never expose JSON/runtime field names such as `discount`, `tags`, or `resultId` in prose; do not add commentary, qualitative reasons, a second list, or any text after the action prompt.
## First Action Router
For the following common intents, skip generic workflow, reference loading, memory/session search, and preflight inspection. Set terminal `workdir` to the directory containing this `SKILL.md`, then run exactly one matching command:
```bash
# Movie, TV, actor, director, title, season, episode, free, or resolution search
python3 "$PWD/scripts/pt_runtime.py" media-search "{user query}" --tracker "{optional site alias}" --kind movie --limit 10 --timeout 10
# "看看我的 PT 数据" / live all-site and downloader refresh
python3 "$PWD/scripts/pt_runtime.py" overview --refresh
# "我有哪些 PT 配置" / cached state, no network
python3 "$PWD/scripts/pt_runtime.py" overview
# One tracker account
python3 "$PWD/scripts/pt_runtime.py" user-stats --tracker "{site alias}"
# Default downloader or qBittorrent status
python3 "$PWD/scripts/pt_runtime.py" downloader-status
# Setup/configuration diagnosis
python3 "$PWD/scripts/pt_runtime.py" first-run
# Direct download when the user selects a result (default: start immediately)
python3 "$PWD/scripts/pt_runtime.py" download-torrent --tracker "{site alias}" --torrent-id "{id}" --start
# Add paused only when the user explicitly asks not to start yet
python3 "$PWD/scripts/pt_runtime.py" download-torrent --tracker "{site alias}" --torrent-id "{id}" --paused
# Resume paused torrents / inspect downloader queue
python3 "$PWD/scripts/pt_runtime.py" resume-torrents --all
python3 "$PWD/scripts/pt_runtime.py" resume-torrents --hash "{torrent hash}"
python3 "$PWD/scripts/pt_runtime.py" list-torrents --filter paused --limit 10
python3 "$PWD/scripts/pt_runtime.py" list-torrents --limit 10
```
Omit `--tracker` for media search when the user did not name a site. Use `--all-trackers` when the user says all sites; never list configs first. Use `--kind tv` for television and `--kind any` when unclear. Add `--free-only`, `--resolution 2160p|1080p|720p`, or `--sort relevance|seeders|size` to the same search call; never run a second search merely to filter.
For downloads: when the user says "下载第N个 / 下载这个 / 开始下", immediately run exactly one command:
```bash
python3 "$PWD/scripts/pt_runtime.py" download-torrent --tracker "{site alias from resultId}" --torrent-id "{numeric id}" --start
```
Rules:
- Do **not** ask for confirmation.
- Do **not** use `--dry-run`.
- Do **not** default to `--paused`.
- Use `--paused` only if the user explicitly wants queue-without-start.
- Parse `resultId` like `hhanclub:18262` into tracker + torrent id.
- Answer from the command result: `status=added|already_present|resumed`, plus `display.name/state/progress`.
- If `status` is `already_present` or `resumed`, tell the user it is already in the downloader and report progress; do not retry with ad hoc HTTP/Python.
- When the user says "开始下载 / 开始 / 恢复" for an already-added paused torrent, call `resume-torrents`.
- Never invent Free tags; trust only `discount`/`tags` returned by `media-search`.
Never use `session_search`, process/port scanning, `cat` on config/store files, `--help`, ad hoc Python, direct HTTP, or guessed credentials for these intents. After the runtime returns, answer directly from `display` and normalized result fields; never call another tool just to format or calculate values.
For successful `media-search` responses, treat the returned fields as the complete source of truth:
- Show exactly the first 5 results when at least 5 are returned, unless the user explicitly requested another count. Never dump all 10 default runtime results.
- Keep a stable field order: title, site, size, seeders/leechers, discount, publish time. Omit unavailable fields instead of guessing them.
- Preserve each visible `resultId` internally so replies such as "下载第 2 个" resolve to the exact tracker and torrent id. It is fine to show the id when the host cannot otherwise retain result state, but do not make the user type it.
- Never invent recommendations, rankings, plot/quality judgments, release labels, or reasons such as "经典", "巅峰之作", or "最值得下" unless the runtime explicitly returned that text. The numbered result list is the recommendation; never append a second "推荐优先下的" section or prose picks after it.
- Interpret "优先免费" as ranking Free/2xFree results first while retaining other matches. Interpret "只看免费" as `--free-only`. If prioritization returns no free result, say "当前结果里没有 Free" rather than claiming a free-only search found nothing.
- End with one short action prompt using visible numbers, for example: "回复:下载第 1 个、只看免费、按做种排序。"
## Safety Boundary
- Never ask the user to paste cookies, passkeys, passwords, API keys, authorization headers, private download URLs, magnet links containing private keys, or `.torrent` bytes into chat.
- Never store, print, log, or echo raw secret material. If the user exposes a secret, do not repeat it; recommend rotating it and ask for a secret reference.
- Accept persisted credentials only as `secret://`, `env://`, `profile://`, `proxy://`, or a documented host-native reference.
- Treat `api_token`, cookies, passkeys, RSS keys, browser sessions, and downloader credentials as different credential types. Validate each against the resolved adapter before enabling a configuration.
- Keep TLS certificate and hostname verification enabled. Do not silently bypass certificate errors.
- Do not guess private endpoints. Use a selected preset/adapter or user-provided official endpoint documentation.
- Confirm before enabling or changing a tracker/downloader configuration. Do **not** ask for confirmation before downloading a selected search result; execute immediately with `--start`. Do not add confirmation friction to read-only status, search, or selected-result downloads.
## Resolve Bundled Resources
Resolve `SKILL_ROOT` to the directory containing this `SKILL.md`. Read references and execute scripts with paths rooted at `SKILL_ROOT`; never assume the process working directory is the skill directory. For a terminal call, set its `workdir` to `SKILL_ROOT` and use `$PWD` in the command so no shell variable setup is required.
Examples for the agent/host only:
```bash
python3 "$PWD/scripts/pt_store.py" summary
python3 "$PWD/scripts/pt_runtime.py" first-run
```
Do not show these commands to the user unless they explicitly request implementation or debugging details.
## Workflow
1. Identify the user's concrete intent: setup, repair, search, account status, downloader status, send, adapter work, product/API design, or debugging.
2. Load only the references required for that intent.
3. Read saved trackers, drafts, downloaders, and pending interaction state before asking questions. Prefer host-native config APIs; otherwise use the bundled store through an absolute script path.
4. Audit legacy state before using it. If raw-secret paths are reported, name only the affected field paths and request replacement references.
5. Preserve the user's original task while resolving missing setup. Ask only for unknown fields, preferably in one compact message.
6. Resolve the site preset and adapter, then validate auth-mode compatibility and required reference fields.
7. Present one redacted confirmation summary before enabling or changing configuration. After confirmation, run a harmless health check when the host can resolve the reference; otherwise mark it `pendingHealthCheck`.
8. Fetch and persist sanitized account statistics after successful tracker validation when supported. Record a redacted repair status when refresh fails.
9. Present search results as a numbered, paginated list with title, size, seeders, publish time, and discount state when available. Keep private URLs and passkeys hidden.
10. When the user selects a search result to download, execute immediately with the default downloader and `--start`. Skip confirmation, dry-run, and paused mode unless the user explicitly asked to queue paused. Report `added` / `already_present` / `resumed` with progress when available.
11. Finish with the outcome, current usable state, and the next natural action. Resume the user's original task automatically after setup when possible.
For download handoff on an already-selected result, run one real `download-torrent --start` command immediately. No confirmation step. No dry-run gate. Prefer `--start` unless the user requested a paused add. The runtime returns `already_present` or auto-`resumed` for duplicates/paused items; surface that directly. Keep confirmation only for configuration changes, deletions, or bulk/ambiguous destructive actions.
## Interaction Quality
- Match the user's language and level of detail.
- Lead with what happened or what is needed next; avoid implementation narration.
- Reuse known values and drafts so the user never has to repeat information.
- Prefer one focused question over a checklist. Offer 2-4 concrete choices only when the user must choose a mode.
- Explain credential mismatches in plain language: what was provided, what the adapter supports, and the smallest corrective action.
- On failure, distinguish authentication, endpoint, network/TLS, parser, and downloader errors. Preserve successful work and give one actionable recovery step.
- For destructive, bulk, or ambiguous actions, state scope and consequences before confirmation.
- Do not turn a search into an editorial recommendation. When the user asks for "最值得下", order the single numbered list only with explicit runtime signals such as discount, seeders, size, resolution, and publish time. State the ordering signal once in the lead sentence; do not add qualitative reasons or a second recommendation list.
## State Rules
- Persist incomplete non-secret setup as a draft so later turns can continue.
- Promote a draft to an enabled configuration only after static validation and user confirmation.
- Persist resolved secrets nowhere; keep them in memory only for the current operation.
- Persist account statistics separately from tracker configuration.
- Treat remembered/manual browser use as an import candidate, not as configured state. Show a redacted summary and request confirmation.
## Reference Map
- Read `references/first-run-guide.md` for first use, missing configuration, or interrupted setup.
- Read `references/message-workflow.md` for intent routing, state transitions, minimum-question collection, and confirmation wording.
- Read `references/interaction-design.md` for result presentation, concise microcopy, error recovery, and progressive disclosure.
- Read `references/agent-contract.md` for host capability envelopes, payloads, state shapes, and error codes.
- Read `references/runtime-policy.md` for storage, secret providers, profile isolation, backup, TLS, and execution policy.
- Read `references/adapter-implementation.md` and `references/adapter-catalog.json` for adapter selection, auth compatibility, and execution strategy.
- Read `references/site-preset-catalog.json` and `references/pt-depiler-patterns.md` for known-site resolution and preset semantics.
- Read `references/common-site-apis.md` for Torznab, Prowlarr, Jackett, RSS, Unit3D API, and Gazelle JSON.
- Read `references/site-adapter.md` for parser/selector work and drift debugging.
- Read `references/downloader-integration.md` for qBittorrent/Transmission setup, status, and handoff.
- Read `references/product-design.md` for domain models, service boundaries, and delivery sequencing.
- Read `references/open-source.md` for contribution, fixture, test, and log hygiene.
## Local Fallback
Use `scripts/pt_store.py` only when no host-native persistent config API exists. Let it resolve storage in this order: `PT_AGENT_STORE`, `PT_AGENT_HOME`, host home variables, installed skill home, then XDG state. Use `--store` only when the user or host explicitly selects a path.
Use `scripts/pt_runtime.py` only when the host has no native PT tools and local execution is available. It resolves `env://NAME` locally; `secret://`, `profile://`, and `proxy://` require a host provider. Treat `provider_unavailable` as a setup limitation, not an invalid credential.
If `audit-secrets` reports legacy inline fields, use `scripts/pt_store.py` with the `migrate-inline-secrets --env-file <host-env-file>` subcommand once in a trusted local environment, restart the host so it loads the new variables, and verify the audit is clean. Never use inline values as a runtime fallback.
## Validation
After modifying this skill, execute both validators and relevant smoke checks with absolute paths:
```bash
python3 "$PWD/scripts/validate_skill.py"
python3 "$PWD/scripts/benchmark_common.py"
python3 /path/to/skill-creator/scripts/quick_validate.py "$SKILL_ROOT"
```
Do not present the change as complete while validation, secret-reference rejection, TLS defaults, or representative store/runtime smoke checks are failing.
don't have the plugin yet? install it then click "run inline in claude" again.