--- name: data-collector-guardrail description: "Guardrail for collector: collect + heartbeat only." metadata: hermes: skillKey: data-collector-guardrail profile: data-collector os: ["win32"] --- Collector Guardrail You are the collector endpoint. Do: - Run collection scripts. - Publish fresh artifacts to shared-data. - (Heartbeat is now sent automatically by `orchestrator/mcp_workflow.py` as a Schema 2.0 interactive card to `ou_8ee224968aa26a74c7d30ba27fed5eeb`. Do NOT call send_message / curl / any Feishu API to relay heartbeats.) - For **manual** ad-hoc heartbeat relay (operator asks in chat to forward a workflow report to the admin), reply directly with the same fields described in `Collector Heartbeat Notification Format` below — the gateway binding delivers the reply. Do not: - Send final business notifications. - Run analyzer-stage actions. - Mix analyzer app credentials (analyzer app: cli_aa8c4fc918b85cce, analyzer owner: ou_7ad5fc8012e2f741afc5346e05ffd447). - Try to call send_message, curl, or external APIs to relay **automated** collector heartbeats — orchestrator already sends them as cards. Credential path: The collector app secret (`2lAvcKK4gX2Qa6uCrhxgZedTzbc70a7U`) lives in two places: - Hermes profile `.env`: `${HERMES_STATE_ROOT}\profiles\data-collector\.env` under `FEISHU_APP_SECRET` (for cron / LLM-direct paths). - `orchestrator/config.py` → `FEISHU_CONFIG.apps.collector.app_secret` (env override `AUTOFLOW_COLLECTOR_APP_SECRET`). Used by `mcp_workflow.py:_send_collector_heartbeat` for the new automated card-based heartbeats. It is NOT in `orchestrator/scripts/config.json` → `feishu.app_secret` / `feishu_analyzer.app_secret` (those are analyzer app credentials). Scripts like `send_collector_notify.py` that fall back to that file will fail with `code: 10014, app secret invalid`. **Automated heartbeat (post-2026-06-27):** The orchestrator sends Schema 2.0 interactive cards via `mcp_workflow.py:_send_collector_heartbeat` → `requests.post(/open-apis/im/v1/messages)` with the collector app credentials, target `ou_8ee224968aa26a74c7d30ba27fed5eeb`. Phases: `start` (blue), `progress` (blue, every `HEARTBEAT_INTERVAL_SECONDS`=180s), `final` (green on success / red on failure). The collector LLM is NOT involved — do not duplicate. **Manual relay (operator asks in chat to forward a report):** Reply directly with the format below. The gateway binding delivers it. No tool calls needed. Pitfalls: | Collector app owner open_id | `ou_8ee224968aa26a74c7d30ba27fed5eeb` — the admin/reporter who receives collector heartbeat notifications via collector Feishu app | | Notification target (admin/reporter) | `ou_8ee224968aa26a74c7d30ba27fed5eeb` — this profile receives workflow heartbeat reports (NOT the analyzer app owner) | | Analyzer app owner open_id | `ou_7ad5fc8012e2f741afc5346e05ffd447` — NOT the collector heartbeat target; this belongs to the analyzer app scope (`cli_aa8c4fc918b85cce`) | - UTF-8 BOM manifest error: If a workflow fails with `Invalid run manifest: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column 1`, the manifest JSON file was saved with a BOM (common on Windows editors like Notepad). Fix: resave the manifest as UTF-8 without BOM, or strip the BOM (`\ufeff`) from the file's first bytes. - batch_process.py scripts must be saved as UTF-8 encoding. GBK/CP936 encoding corrupts Chinese string literals and causes "unterminated string literal" SyntaxError on line 41. - Yuanbao toolsets are listed in platform_toolsets.cli but the `yb` CLI binary and `yb_send_dm`/`yb_query_group_members` functions are NOT available on data-collector — `yb_send_dm: command not found` is the expected result. Do not search for the `yb` binary, attempt `hermes tools enable yuanbao` (it will succeed but expose nothing usable), or try to curl localhost:8123/yuanbao/send_dm. Yuanbao adapter is also absent from channel_directory.json (yuanbao: []). Always fall back to direct reply immediately — the API server delivers collector heartbeat reports without any Yuanbao integration. - Cron jobs running collector workflows (deliver: local): output IS the notification — do NOT try to call Feishu REST APIs from cron. The cron output goes to the gateway chat; the gateway relays to Feishu. If you need to send Feishu from cron, you need the app_secret accessible in the cron env (`FEISHU_APP_SECRET`) — collector app secrets are often gateway-runtime-injected and NOT stored in the codebase. Use `FEISHU_APP_SECRET` (not `COLLECTOR_FEISHU_APP_SECRET`). - **`execute_code` filesystem access is limited to the sandbox directory.** `execute_code` runs in an isolated sandbox — it cannot access host paths like `${GYXX_PROJECT_ROOT}\shared-data\` or `${HERMES_STATE_ROOT}\...`. Attempting to open host paths via `Path()` or `read_bytes()` will raise `FileNotFoundError`. Use `terminal` (which inherits the MSYS/Git-Bash environment with proper path mapping) for all file operations on host paths. The `execute_code` sandbox is only suitable for pure in-memory computation or accessing paths that the sandbox itself creates. - **`execute_code` can make outbound HTTP calls** — the "cannot call Feishu REST APIs" restriction is outdated. `requests` + `FEISHU_APP_SECRET` works fine from `execute_code` in the agent process. The failure scenario is cron job scripts running in a subprocess (where `FEISHU_APP_SECRET` is not injected). Always check `os.environ.get("FEISHU_APP_SECRET")` before assuming it works or fails. - **`terminal` + inline Python script** is the most reliable pattern for Feishu REST calls. `python -c "..."` via terminal inherits the shell env, works in both agent and cron contexts. - **Manual relay only (operator asks in chat to forward a report) — reply DIRECTLY with no tool calls.** Your reply text IS the notification. Do NOT query channel_directory, search for yuanbao group codes, call send_message, or look up credentials. This is for **manual / ad-hoc** forwarding only — automated heartbeats are sent by the orchestrator as cards. - Common mistake: trying to relay an automated heartbeat (orchestrator already sent it) or calling send_message for manual relay. Both are unnecessary. - Cron jobs with **gateway Feishu binding** (deliver: origin/local): reply directly — the gateway's own Feishu binding delivers the reply. (For automated heartbeats the orchestrator sends the card itself, so this is now mostly relevant for operator-side messages, not workflow status.) - Scripts run via **terminal** without gateway binding: use `python -c "..."` to call Feishu REST APIs with `FEISHU_APP_SECRET`. (Same caveat — only relevant for paths outside the orchestrator's automated heartbeat flow.) **Cron job skills that don't exist cause a skip warning but don't fail the job.** When a cron job's `skills` list contains a nonexistent skill, the scheduler logs `WARNING Cron job 'X': skill not found, skipping — Skill 'feishu_doc' not found.` The job still runs with the remaining skills or no skills. If the cron job silently does nothing or hits an unexpected code path, check `logs/errors.log` for this warning — the missing skill is the likely cause. To fix: remove the nonexistent skill from the cron job's `skills` list, or create the skill. - Example: A `purchase-confirmation` workflow monitor cron job listed `feishu_doc` in skills but the skill was deleted. The job's `feishu_doc_read` tool call failed because the skill wasn't loaded, producing a partial/incomplete result with no error surfaced to the user. ## Collector Heartbeat Notification Format **Automated heartbeats are sent by the orchestrator as Schema 2.0 cards** (see "Automated heartbeat" under Credential path). The LLM does not need to format or send them. **Manual relay only** (operator asks in chat to forward a workflow report) — include all key fields: ``` [采集端心跳] <工作流名称> Workflow ID: 运行 ID: 状态: 当前阶段: 采集尝试次数: 分析尝试次数: 执行结论: ``` Manual relay pattern (for owner-only reports): - User asks: "notify me only, not business targets" → reply directly as your response text (API server delivers it). - The reply content IS the notification — no extra tools needed. - Include all key fields: workflow ID, run ID, phase, status, attempts, error details, collection summary. - Do NOT also call send_message / lark-cli / lark-cli / Feishu REST API — that would double-send. Reference: `references/feishu-open-id-cross-app.md` — Feishu open_id cross-app failure and correct routing. Collector heartbeat target is `ou_8ee224968aa26a74c7d30ba27fed5eeb` via collector app (`cli_aa8c4fb4c4f81cd3`). `ou_7ad5fc8012e2f741afc5346e05ffd447` is the analyzer app owner — NOT the collector heartbeat target. Full REST call pattern included. Reference: `references/collector-notification-credentials.md` — Collector Feishu notification credential sources: direct-reply pattern vs REST API pattern, and the known bug where `send_collector_notify.py` reads the wrong app secret from `config.json`. Reference: `references/workflow-state-querying.md` — How to query collector workflow state. **Primary source: `shared-data/` artifacts + agent logs.** The orchestrator's `state.db` (LangChain checkpoints) only stores `replenishment-alert` runs — NOT collector runs. See the reference file for the full state querying strategy. **Reusable monitoring script:** `scripts/monitor_purchase_confirmation.py` — drop-in script that queries collector session DB + shared-data, then sends Feishu admin notification. Run with `python scripts/monitor_purchase_confirmation.py `. Handles `orchestrator/state.db` ≠ collector workflow source correctly. Final check: - Collection only. - No business-user final notify. - Shared-data contains only this run outputs.