[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6BZRP4WT9WP3FT9TS09P29P":3,"skill-same:01M6BZRP4WT9WP3FT9TS09P29P":181},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":21,"frontMatter":22,"refName":23,"commitSha":24,"skillDirectory":25,"forksCount":13,"repositoryHtmlUrl":26,"repositoryHomepageUrl":6,"ownerHtmlUrl":27,"ownerBlogUrl":6,"ownerDescription":28,"updatedAt":29,"install":30,"resources":43},"01M6BZRP4WT9WP3FT9TS09P29P","heartbeat",null,"twidxuga\u002Fdotfiles","twidxuga","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F12471681?v=4","01M6BZR45BH8JCC79Q9SKSS6SC","Ricardo Santos","01M6BZR49CRKSBZYQD1WNQWCXW",0,"MIT","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fheartbeat\u002FSKILL.md",[],[5],"2026-11-10 10:12:30",false,"---\nname: heartbeat\ndescription: Manage the opencode heartbeat system — hourly cron-driven headless opencode sessions that execute a task register. Primitives: heartbeat-deploy, heartbeat-add, heartbeat-remove, heartbeat-uninstall, heartbeat-read.\n---\n\n# heartbeat\n\nThe heartbeat system runs a headless opencode session on a cron schedule (hourly by default). Each run consults a task register and executes any tasks that are due. All output is timestamped and appended to a log file with clear separators.\n\n## Paths (all systems)\n\n```\nHEARTBEAT_DIR  = ~\u002F.local\u002Fshare\u002Fheartbeat\u002F\nTASK_REGISTER  = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-tasks.json\nSESSION_ID     = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-session.id\nOUTPUT_LOG     = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-output.log\nCRON_LOG       = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-cron.log\nRUNNER         = ~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-runner.sh\nSKILL_DIR      = ~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002F\n```\n\nThe session in opencode is titled **\"heartbeat\"** and uses model **`openai\u002Fgpt-5.6-luna`**.  \nWorking directory for the heartbeat opencode session: `~\u002F.local\u002Fshare\u002Fheartbeat\u002F`.\n\n---\n\n## Primitive: heartbeat-deploy\n\n**When invoked:** User says \"heartbeat-deploy\", \"install heartbeat\", \"setup heartbeat cron\", or similar.\n\n**What it does:** Installs the heartbeat cron job (or launchd plist on macOS) so the runner fires every hour. Creates the task register if it doesn't exist yet.\n\n**Steps to execute:**\n\n1. Detect OS: `uname -s`\n2. Resolve the runner path: `RUNNER=\"${HOME}\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-runner.sh\"`\n3. Ensure the runner is executable: `chmod +x \"${RUNNER}\"`\n4. Ensure HEARTBEAT_DIR exists: `mkdir -p \"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\"`\n5. Initialise task register if missing (see schema below).\n6. Install the cron entry (with timestamped log output):\n\n```bash\nRUNNER=\"${HOME}\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-runner.sh\"\nHEARTBEAT_DIR=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\"\nCRON_LINE=\"0 * * * * { ${RUNNER} 2>&1; } | while IFS= read -r line; do echo \\\"\\$(date '+%Y-%m-%d %H:%M:%S') \\$line\\\"; done >> ${HEARTBEAT_DIR}\u002Fheartbeat-cron.log\"\n\n( crontab -l 2>\u002Fdev\u002Fnull | grep -v \"heartbeat-runner.sh\" ; echo \"${CRON_LINE}\" ) | crontab -\n```\n\n7. Verify installation: `crontab -l | grep heartbeat-runner`\n8. Report: print the installed cron line and the path to the task register.\n\n**macOS note:** crontab works fine on macOS. `~\u002F.local\u002Fshare\u002Fheartbeat\u002F` is used for all data files to avoid macOS TCC\u002FSIP restrictions on `~\u002FDocuments\u002F`. launchd is NOT required.\n\n**Task register initial schema (if creating from scratch):**\n```json\n{\n  \"version\": 1,\n  \"tasks\": []\n}\n```\n\n---\n\n## Primitive: heartbeat-add\n\n**When invoked:** User says \"heartbeat-add\", \"add task to heartbeat\", or describes a new recurring task.\n\n**What it does:** Adds a new task entry to the task register.\n\n**Required fields to collect from user (ask if not provided):**\n- `name` — unique short identifier (snake_case, no spaces)\n- `description` — human-readable description\n- `frequency_hours` — how often to run. The cron fires every hour; tasks only execute when `(now - last_run) >= frequency_hours`. Use any integer ≥ 1:\n  - `1` — every hour\n  - `6` — every 6 hours\n  - `24` — daily\n  - `168` — weekly\n  - `720` — monthly (approx 30 days)\n- `enabled` — boolean, default true\n- ONE of:\n  - `script` — absolute path to a shell script to execute (script-based tasks)\n  - `prompt` — string prompt to send to the heartbeat opencode session (LLM-based tasks)\n\n**Steps to execute:**\n\n```bash\nTASK_REGISTER=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-tasks.json\"\n```\n\n1. Read the current register.\n2. Check for duplicate `name` — if exists, refuse and ask the user to remove first or use a different name.\n3. Build the new task object:\n```json\n{\n  \"name\": \"\u003Cname>\",\n  \"description\": \"\u003Cdescription>\",\n  \"frequency_hours\": \u003CN>,\n  \"enabled\": true,\n  \"script\": \"\u003Cpath or omit>\",\n  \"prompt\": \"\u003Cprompt or omit>\",\n  \"last_run\": \"\"\n}\n```\n4. Append to `tasks` array, write back to register with `indent=2`.\n5. Confirm to user: \"Task `\u003Cname>` added. Next heartbeat run will execute it.\"\n\n---\n\n## Primitive: heartbeat-remove\n\n**When invoked:** User says \"heartbeat-remove\", \"remove task\", \"delete heartbeat task\", or names a task to remove.\n\n**What it does:** Removes a task from the task register by name.\n\n**Steps to execute:**\n\n1. Read `heartbeat-tasks.json`.\n2. List current tasks with names and descriptions so user can confirm the right one.\n3. Confirm: \"Remove task `\u003Cname>`? (yes\u002Fno)\"\n4. On confirmation: filter out the task and write back.\n5. Report: \"Task `\u003Cname>` removed.\"\n\n**Note:** Does NOT stop a currently-running heartbeat. Takes effect on the next run.\n\n---\n\n## Primitive: heartbeat-uninstall\n\n**When invoked:** User says \"heartbeat-uninstall\", \"remove heartbeat cron\", \"uninstall heartbeat\", or similar.\n\n**What it does:** Removes the cron entry. Leaves the task register, output log, and session ID intact.\n\n**Steps to execute:**\n\n```bash\n# Remove the heartbeat cron line:\ncrontab -l 2>\u002Fdev\u002Fnull | grep -v \"heartbeat-runner.sh\" | crontab -\n\n# Verify removal:\nif crontab -l 2>\u002Fdev\u002Fnull | grep -q \"heartbeat-runner.sh\"; then\n  echo \"WARNING: cron entry still present — remove manually\"\nelse\n  echo \"Heartbeat cron removed.\"\nfi\n```\n\nReport: \"Heartbeat cron uninstalled. Task register and logs preserved at ${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002F.\"\n\n---\n\n## Primitive: heartbeat-read\n\n**When invoked:** User says \"heartbeat-read\", \"show heartbeat log\", \"what did heartbeat do\", \"check heartbeat output\", or similar.\n\n**What it does:** Reads and displays the heartbeat output log (and optionally the Datadog alerts log).\n\n**Steps to execute:**\n\n```bash\nOUTPUT_LOG=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-output.log\"\nALERTS_LOG=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-datadog-alerts.log\"\n```\n\n1. Check if `OUTPUT_LOG` exists. If not: \"No heartbeat runs recorded yet.\"\n2. By default show the **last 100 lines** of OUTPUT_LOG (use `tail -n 100`).\n3. If user asks for \"all\" or \"full\", show the entire file.\n4. If user asks specifically about \"alerts\" or \"Datadog\", show the last 100 lines of ALERTS_LOG instead.\n5. Also show current task register summary: `cat heartbeat-tasks.json | python3 -c \"import json,sys; d=json.load(sys.stdin); [print(f'  {t[\\\"name\\\"]} (every {t[\\\"frequency_hours\\\"]}h, last: {t.get(\\\"last_run\\\",\\\"never\\\")})') for t in d[\\\"tasks\\\"]]\"`\n\n**Additional flags (user may ask for):**\n- \"last N runs\" — show last N run separators and their content\n- \"task \u003Cname>\" — filter log lines to only show entries for that task\n- \"errors\" — filter to lines containing ERROR or WARN\n\n---\n\n## Task Register Schema\n\n```json\n{\n  \"version\": 1,\n  \"tasks\": [\n    {\n      \"name\": \"string — unique snake_case identifier\",\n      \"description\": \"string — human description\",\n      \"frequency_hours\": 1,\n      \"enabled\": true,\n      \"script\": \"\u002Fabsolute\u002Fpath\u002Fto\u002Fscript.sh\",\n      \"prompt\": \"omit if using script\",\n      \"last_run\": \"2026-06-25T14:00:00Z or empty string\"\n    }\n  ]\n}\n```\n\n**Rules:**\n- `name` must be unique. snake_case. No spaces.\n- Exactly one of `script` or `prompt` must be set (not both, not neither).\n- `frequency_hours` minimum: 1.\n- `last_run` is managed automatically by the runner — never set manually.\n- `enabled: false` skips the task without removing it.\n\n---\n\n## Built-in Tasks\n\nThe following tasks ship with the heartbeat skill and can be added via `heartbeat-add`:\n\n### datadog-alert-diff\n\nMonitors Datadog for CRITICAL and HIGH severity alerts. Logs only changes (new, resolved, changed) vs the previous run. First run logs the full snapshot.\n\n```json\n{\n  \"name\": \"datadog-alert-diff\",\n  \"description\": \"Log new\u002Fresolved\u002Fchanged Datadog CRITICAL and HIGH alerts vs previous hour\",\n  \"frequency_hours\": 1,\n  \"enabled\": true,\n  \"script\": \"~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-datadog-alerts.sh\",\n  \"last_run\": \"\"\n}\n```\n\nOutput log: `~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-datadog-alerts.log`  \nState file: `~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-datadog-alerts.state.json`\n\nRequires: `DD_API_KEY` and `DD_APP_KEY` environment variables, OR a Datadog config file at `~\u002FLibrary\u002FApplication Support\u002FDatadog\u002Fconfig.json` containing `api_key` and `app_key` fields.\n\n---\n\n## Runner Architecture\n\n```\ncron (every hour)\n  └─ heartbeat-runner.sh\n       ├─ Reads heartbeat-tasks.json\n       ├─ Filters tasks by frequency_hours + last_run\n       ├─ Resolves\u002Fcreates persistent \"heartbeat\" opencode session\n       │    └─ Stored in heartbeat-session.id\n       │    └─ opencode run --session \u003Cid> --dir HEARTBEAT_DIR --model anthropic\u002Fclaude-sonnet-4-6\n       └─ For each due task:\n            ├─ script tasks → exec the script directly\n            └─ prompt tasks → opencode run --session \u003Cid> \"\u003Cprompt>\"\n            └─ Appends output to heartbeat-output.log with timestamp + separator\n            └─ Updates last_run in task register\n```\n\n---\n\n## Troubleshooting\n\n**Cron not firing:**\n- Check `crontab -l` for the entry.\n- Check `~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-cron.log` for raw cron output.\n\n**Session not resuming:**\n- Delete `heartbeat-session.id` to force creation of a new session next run.\n\n**Datadog task failing:**\n- Ensure `DD_API_KEY` and `DD_APP_KEY` are set in the cron environment (add to the cron line: `DD_API_KEY=xxx DD_APP_KEY=yyy 0 * * * * ...`), or configure them in `~\u002FLibrary\u002FApplication Support\u002FDatadog\u002Fconfig.json`.\n- Run the script manually: `~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-datadog-alerts.sh`\n","# heartbeat\n\nThe heartbeat system runs a headless opencode session on a cron schedule (hourly by default). Each run consults a task register and executes any tasks that are due. All output is timestamped and appended to a log file with clear separators.\n\n## Paths (all systems)\n\n```\nHEARTBEAT_DIR  = ~\u002F.local\u002Fshare\u002Fheartbeat\u002F\nTASK_REGISTER  = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-tasks.json\nSESSION_ID     = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-session.id\nOUTPUT_LOG     = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-output.log\nCRON_LOG       = ~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-cron.log\nRUNNER         = ~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-runner.sh\nSKILL_DIR      = ~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002F\n```\n\nThe session in opencode is titled **\"heartbeat\"** and uses model **`openai\u002Fgpt-5.6-luna`**.  \nWorking directory for the heartbeat opencode session: `~\u002F.local\u002Fshare\u002Fheartbeat\u002F`.\n\n---\n\n## Primitive: heartbeat-deploy\n\n**When invoked:** User says \"heartbeat-deploy\", \"install heartbeat\", \"setup heartbeat cron\", or similar.\n\n**What it does:** Installs the heartbeat cron job (or launchd plist on macOS) so the runner fires every hour. Creates the task register if it doesn't exist yet.\n\n**Steps to execute:**\n\n1. Detect OS: `uname -s`\n2. Resolve the runner path: `RUNNER=\"${HOME}\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-runner.sh\"`\n3. Ensure the runner is executable: `chmod +x \"${RUNNER}\"`\n4. Ensure HEARTBEAT_DIR exists: `mkdir -p \"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\"`\n5. Initialise task register if missing (see schema below).\n6. Install the cron entry (with timestamped log output):\n\n```bash\nRUNNER=\"${HOME}\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-runner.sh\"\nHEARTBEAT_DIR=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\"\nCRON_LINE=\"0 * * * * { ${RUNNER} 2>&1; } | while IFS= read -r line; do echo \\\"\\$(date '+%Y-%m-%d %H:%M:%S') \\$line\\\"; done >> ${HEARTBEAT_DIR}\u002Fheartbeat-cron.log\"\n\n( crontab -l 2>\u002Fdev\u002Fnull | grep -v \"heartbeat-runner.sh\" ; echo \"${CRON_LINE}\" ) | crontab -\n```\n\n7. Verify installation: `crontab -l | grep heartbeat-runner`\n8. Report: print the installed cron line and the path to the task register.\n\n**macOS note:** crontab works fine on macOS. `~\u002F.local\u002Fshare\u002Fheartbeat\u002F` is used for all data files to avoid macOS TCC\u002FSIP restrictions on `~\u002FDocuments\u002F`. launchd is NOT required.\n\n**Task register initial schema (if creating from scratch):**\n```json\n{\n  \"version\": 1,\n  \"tasks\": []\n}\n```\n\n---\n\n## Primitive: heartbeat-add\n\n**When invoked:** User says \"heartbeat-add\", \"add task to heartbeat\", or describes a new recurring task.\n\n**What it does:** Adds a new task entry to the task register.\n\n**Required fields to collect from user (ask if not provided):**\n- `name` — unique short identifier (snake_case, no spaces)\n- `description` — human-readable description\n- `frequency_hours` — how often to run. The cron fires every hour; tasks only execute when `(now - last_run) >= frequency_hours`. Use any integer ≥ 1:\n  - `1` — every hour\n  - `6` — every 6 hours\n  - `24` — daily\n  - `168` — weekly\n  - `720` — monthly (approx 30 days)\n- `enabled` — boolean, default true\n- ONE of:\n  - `script` — absolute path to a shell script to execute (script-based tasks)\n  - `prompt` — string prompt to send to the heartbeat opencode session (LLM-based tasks)\n\n**Steps to execute:**\n\n```bash\nTASK_REGISTER=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-tasks.json\"\n```\n\n1. Read the current register.\n2. Check for duplicate `name` — if exists, refuse and ask the user to remove first or use a different name.\n3. Build the new task object:\n```json\n{\n  \"name\": \"\u003Cname>\",\n  \"description\": \"\u003Cdescription>\",\n  \"frequency_hours\": \u003CN>,\n  \"enabled\": true,\n  \"script\": \"\u003Cpath or omit>\",\n  \"prompt\": \"\u003Cprompt or omit>\",\n  \"last_run\": \"\"\n}\n```\n4. Append to `tasks` array, write back to register with `indent=2`.\n5. Confirm to user: \"Task `\u003Cname>` added. Next heartbeat run will execute it.\"\n\n---\n\n## Primitive: heartbeat-remove\n\n**When invoked:** User says \"heartbeat-remove\", \"remove task\", \"delete heartbeat task\", or names a task to remove.\n\n**What it does:** Removes a task from the task register by name.\n\n**Steps to execute:**\n\n1. Read `heartbeat-tasks.json`.\n2. List current tasks with names and descriptions so user can confirm the right one.\n3. Confirm: \"Remove task `\u003Cname>`? (yes\u002Fno)\"\n4. On confirmation: filter out the task and write back.\n5. Report: \"Task `\u003Cname>` removed.\"\n\n**Note:** Does NOT stop a currently-running heartbeat. Takes effect on the next run.\n\n---\n\n## Primitive: heartbeat-uninstall\n\n**When invoked:** User says \"heartbeat-uninstall\", \"remove heartbeat cron\", \"uninstall heartbeat\", or similar.\n\n**What it does:** Removes the cron entry. Leaves the task register, output log, and session ID intact.\n\n**Steps to execute:**\n\n```bash\n# Remove the heartbeat cron line:\ncrontab -l 2>\u002Fdev\u002Fnull | grep -v \"heartbeat-runner.sh\" | crontab -\n\n# Verify removal:\nif crontab -l 2>\u002Fdev\u002Fnull | grep -q \"heartbeat-runner.sh\"; then\n  echo \"WARNING: cron entry still present — remove manually\"\nelse\n  echo \"Heartbeat cron removed.\"\nfi\n```\n\nReport: \"Heartbeat cron uninstalled. Task register and logs preserved at ${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002F.\"\n\n---\n\n## Primitive: heartbeat-read\n\n**When invoked:** User says \"heartbeat-read\", \"show heartbeat log\", \"what did heartbeat do\", \"check heartbeat output\", or similar.\n\n**What it does:** Reads and displays the heartbeat output log (and optionally the Datadog alerts log).\n\n**Steps to execute:**\n\n```bash\nOUTPUT_LOG=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-output.log\"\nALERTS_LOG=\"${HOME}\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-datadog-alerts.log\"\n```\n\n1. Check if `OUTPUT_LOG` exists. If not: \"No heartbeat runs recorded yet.\"\n2. By default show the **last 100 lines** of OUTPUT_LOG (use `tail -n 100`).\n3. If user asks for \"all\" or \"full\", show the entire file.\n4. If user asks specifically about \"alerts\" or \"Datadog\", show the last 100 lines of ALERTS_LOG instead.\n5. Also show current task register summary: `cat heartbeat-tasks.json | python3 -c \"import json,sys; d=json.load(sys.stdin); [print(f'  {t[\\\"name\\\"]} (every {t[\\\"frequency_hours\\\"]}h, last: {t.get(\\\"last_run\\\",\\\"never\\\")})') for t in d[\\\"tasks\\\"]]\"`\n\n**Additional flags (user may ask for):**\n- \"last N runs\" — show last N run separators and their content\n- \"task \u003Cname>\" — filter log lines to only show entries for that task\n- \"errors\" — filter to lines containing ERROR or WARN\n\n---\n\n## Task Register Schema\n\n```json\n{\n  \"version\": 1,\n  \"tasks\": [\n    {\n      \"name\": \"string — unique snake_case identifier\",\n      \"description\": \"string — human description\",\n      \"frequency_hours\": 1,\n      \"enabled\": true,\n      \"script\": \"\u002Fabsolute\u002Fpath\u002Fto\u002Fscript.sh\",\n      \"prompt\": \"omit if using script\",\n      \"last_run\": \"2026-06-25T14:00:00Z or empty string\"\n    }\n  ]\n}\n```\n\n**Rules:**\n- `name` must be unique. snake_case. No spaces.\n- Exactly one of `script` or `prompt` must be set (not both, not neither).\n- `frequency_hours` minimum: 1.\n- `last_run` is managed automatically by the runner — never set manually.\n- `enabled: false` skips the task without removing it.\n\n---\n\n## Built-in Tasks\n\nThe following tasks ship with the heartbeat skill and can be added via `heartbeat-add`:\n\n### datadog-alert-diff\n\nMonitors Datadog for CRITICAL and HIGH severity alerts. Logs only changes (new, resolved, changed) vs the previous run. First run logs the full snapshot.\n\n```json\n{\n  \"name\": \"datadog-alert-diff\",\n  \"description\": \"Log new\u002Fresolved\u002Fchanged Datadog CRITICAL and HIGH alerts vs previous hour\",\n  \"frequency_hours\": 1,\n  \"enabled\": true,\n  \"script\": \"~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-datadog-alerts.sh\",\n  \"last_run\": \"\"\n}\n```\n\nOutput log: `~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-datadog-alerts.log`  \nState file: `~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-datadog-alerts.state.json`\n\nRequires: `DD_API_KEY` and `DD_APP_KEY` environment variables, OR a Datadog config file at `~\u002FLibrary\u002FApplication Support\u002FDatadog\u002Fconfig.json` containing `api_key` and `app_key` fields.\n\n---\n\n## Runner Architecture\n\n```\ncron (every hour)\n  └─ heartbeat-runner.sh\n       ├─ Reads heartbeat-tasks.json\n       ├─ Filters tasks by frequency_hours + last_run\n       ├─ Resolves\u002Fcreates persistent \"heartbeat\" opencode session\n       │    └─ Stored in heartbeat-session.id\n       │    └─ opencode run --session \u003Cid> --dir HEARTBEAT_DIR --model anthropic\u002Fclaude-sonnet-4-6\n       └─ For each due task:\n            ├─ script tasks → exec the script directly\n            └─ prompt tasks → opencode run --session \u003Cid> \"\u003Cprompt>\"\n            └─ Appends output to heartbeat-output.log with timestamp + separator\n            └─ Updates last_run in task register\n```\n\n---\n\n## Troubleshooting\n\n**Cron not firing:**\n- Check `crontab -l` for the entry.\n- Check `~\u002F.local\u002Fshare\u002Fheartbeat\u002Fheartbeat-cron.log` for raw cron output.\n\n**Session not resuming:**\n- Delete `heartbeat-session.id` to force creation of a new session next run.\n\n**Datadog task failing:**\n- Ensure `DD_API_KEY` and `DD_APP_KEY` are set in the cron environment (add to the cron line: `DD_API_KEY=xxx DD_APP_KEY=yyy 0 * * * * ...`), or configure them in `~\u002FLibrary\u002FApplication Support\u002FDatadog\u002Fconfig.json`.\n- Run the script manually: `~\u002F.config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-datadog-alerts.sh`\n",{},"main","e25eb555e87aa9eeb59b520834f46fd926ad19a3","opencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fheartbeat","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles","https:\u002F\u002Fgithub.com\u002Ftwidxuga","Software developer, data scientist, applications architect and all round computer geek.","2026-10-28 03:46:24",{"source":7,"skillName":5,"commands":31,"prompt":41,"zipAvailable":42},[32,35,38],{"tool":33,"command":34},"npx","npx skills add twidxuga\u002Fdotfiles --skill heartbeat",{"tool":36,"command":37},"bunx","bunx skills add twidxuga\u002Fdotfiles --skill heartbeat",{"tool":39,"command":40},"pnpm","pnpm dlx skills add twidxuga\u002Fdotfiles --skill heartbeat","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fheartbeat\u002FSKILL.md",true,[44,50,54,58,62,66,70,74,78,82,86,90,94,98,102,105,109,113,117,123,127,131,135,139,143,147,151,155,159,163,167,171,175],{"path":45,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":48,"sourceHtmlUrl":49},"assets\u002Fadapters\u002Fantigravity\u002Fgemini.md","ASSET","资产文件",241,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fantigravity\u002Fgemini.md",{"path":51,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":52,"sourceHtmlUrl":53},"assets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-final-reviewer.md",119,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-final-reviewer.md",{"path":55,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":56,"sourceHtmlUrl":57},"assets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-fixer.md",104,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-fixer.md",{"path":59,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":60,"sourceHtmlUrl":61},"assets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-implementer.md",121,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-implementer.md",{"path":63,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":64,"sourceHtmlUrl":65},"assets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-re-reviewer.md",140,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-re-reviewer.md",{"path":67,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":68,"sourceHtmlUrl":69},"assets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-task-reviewer.md",154,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fclaude\u002Fagents\u002Fsuperpowers-task-reviewer.md",{"path":71,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":72,"sourceHtmlUrl":73},"assets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-final-review.toml",308,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-final-review.toml",{"path":75,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":76,"sourceHtmlUrl":77},"assets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-fixer.toml",240,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-fixer.toml",{"path":79,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":80,"sourceHtmlUrl":81},"assets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-implementer.toml",299,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-implementer.toml",{"path":83,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":84,"sourceHtmlUrl":85},"assets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-re-reviewer.toml",285,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-re-reviewer.toml",{"path":87,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":88,"sourceHtmlUrl":89},"assets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-task-reviewer.toml",247,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcodex\u002Fagents\u002Fsuperpowers-task-reviewer.toml",{"path":91,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":92,"sourceHtmlUrl":93},"assets\u002Fadapters\u002Fcursor\u002Fagents\u002Fgeneral-purpose.md",796,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fagents\u002Fgeneral-purpose.md",{"path":95,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":96,"sourceHtmlUrl":97},"assets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-final-reviewer.md",134,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-final-reviewer.md",{"path":99,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":100,"sourceHtmlUrl":101},"assets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-fixer.md",120,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-fixer.md",{"path":103,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":96,"sourceHtmlUrl":104},"assets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-implementer.md","https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-implementer.md",{"path":106,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":107,"sourceHtmlUrl":108},"assets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-re-reviewer.md",129,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-re-reviewer.md",{"path":110,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":111,"sourceHtmlUrl":112},"assets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-task-reviewer.md",133,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fagents\u002Fsuperpowers-task-reviewer.md",{"path":114,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":115,"sourceHtmlUrl":116},"assets\u002Fadapters\u002Fcursor\u002Fhooks.json",199,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fhooks.json",{"path":118,"resourceType":119,"resourceTypeDesc":120,"sizeBytes":121,"sourceHtmlUrl":122},"assets\u002Fadapters\u002Fcursor\u002Fhooks\u002Fenforce-subagent-model.sh","SCRIPT","脚本",1063,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Fhooks\u002Fenforce-subagent-model.sh",{"path":124,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":125,"sourceHtmlUrl":126},"assets\u002Fadapters\u002Fcursor\u002Frules\u002Fsubagent-model-policy.mdc",807,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fadapters\u002Fcursor\u002Frules\u002Fsubagent-model-policy.mdc",{"path":128,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":129,"sourceHtmlUrl":130},"assets\u002Fconventions\u002Fcore.md",1513,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fcore.md",{"path":132,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":133,"sourceHtmlUrl":134},"assets\u002Fconventions\u002Fdesign.md",2918,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fdesign.md",{"path":136,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":137,"sourceHtmlUrl":138},"assets\u002Fconventions\u002Fdevops.md",1392,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fdevops.md",{"path":140,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":141,"sourceHtmlUrl":142},"assets\u002Fconventions\u002Fgsd.md",369,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fgsd.md",{"path":144,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":145,"sourceHtmlUrl":146},"assets\u002Fconventions\u002Fkarpathy.md",317,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fkarpathy.md",{"path":148,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":149,"sourceHtmlUrl":150},"assets\u002Fconventions\u002Fmatt.md",2317,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fmatt.md",{"path":152,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":153,"sourceHtmlUrl":154},"assets\u002Fconventions\u002Fponytail.md",2497,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fponytail.md",{"path":156,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":157,"sourceHtmlUrl":158},"assets\u002Fconventions\u002Fsuperpowers.md",8073,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fsuperpowers.md",{"path":160,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":161,"sourceHtmlUrl":162},"assets\u002Fconventions\u002Fvibecoding.md",58,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fconventions\u002Fvibecoding.md",{"path":164,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":165,"sourceHtmlUrl":166},"assets\u002Fskillsw",8110,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Fskillsw",{"path":168,"resourceType":46,"resourceTypeDesc":47,"sizeBytes":169,"sourceHtmlUrl":170},"assets\u002Ftemplates\u002Fprototype\u002FAGENTS.md",252,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Fassets\u002Ftemplates\u002Fprototype\u002FAGENTS.md",{"path":172,"resourceType":119,"resourceTypeDesc":120,"sizeBytes":173,"sourceHtmlUrl":174},"heartbeat-runner.sh",8253,"https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fheartbeat\u002Fheartbeat-runner.sh",{"path":176,"resourceType":177,"resourceTypeDesc":178,"sizeBytes":179,"sourceHtmlUrl":180},"references\u002Fsensitive-file-access.md","REFERENCE","参考文档",2226,"https:\u002F\u002Fgithub.com\u002FJinsYin\u002Fskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsetup-rules\u002Freferences\u002Fsensitive-file-access.md",[182,214,228,245,261,273],{"skillNo":183,"name":184,"nameZh":6,"description":185,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":186,"categories":187,"keywords":196,"publishedAt":18},"01M6C9Z7VKBN4HAFBDXD67K3E1","terraform-test","Comprehensive guide for writing and running Terraform tests. Use when creating test files (.tftest.hcl), writing test scenarios with run blocks, validating infrastructure behavior with assertions, mocking providers and data sources, testing module outputs and resource configurations, or troubleshooting Terraform test syntax and execution.","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fterraform-test\u002FSKILL.md",[188,193],{"categoryNo":189,"categoryName":190,"taxonomyType":191,"taxonomyTypeDesc":192},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":194,"categoryName":195,"taxonomyType":191,"taxonomyTypeDesc":192},"01JBSEEDCAT000000000000011","运维与部署",[197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213],"test","terraform","terraform test","testing","writing","infrastructure","run","data","ibm","Providers","execution","troubleshooting","syntax","behavior","guide","use","files",{"skillNo":215,"name":216,"nameZh":6,"description":217,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":218,"categories":219,"keywords":221,"publishedAt":18},"01M6C9Z4GWWTXCXAS8NK747K07","terraform-style-guide","Generate Terraform HCL code following HashiCorp's official style conventions and best practices. Use when writing, reviewing, or generating Terraform configurations.","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fterraform-style-guide\u002FSKILL.md",[220],{"categoryNo":194,"categoryName":195,"taxonomyType":191,"taxonomyTypeDesc":192},[222,211,198,223,224,225,226,201,227,212],"terraform style guide","official","generate","code","best practices","hashicorp",{"skillNo":229,"name":230,"nameZh":6,"description":231,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":232,"categories":233,"keywords":235,"publishedAt":18},"01M6C9Z1DCAC8YQQ1WS0AHBB14","terraform-stacks","Comprehensive guide for working with HashiCorp Terraform Stacks. Use when creating, modifying, or validating Terraform Stack configurations (.tfcomponent.hcl, .tfdeploy.hcl files), working with stack components and deployments from local modules, public registry, or private registry sources, managing multi-region or multi-environment infrastructure, or troubleshooting Terraform Stacks syntax and structure.","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fterraform-stacks\u002FSKILL.md",[234],{"categoryNo":194,"categoryName":195,"taxonomyType":191,"taxonomyTypeDesc":192},[198,236,237,213,238,239,240,241,202,242,205,227,243,208,209,244,211,212],"terraform stacks","multi-environment","deployments","public","modules","components","registry","stack","environment",{"skillNo":246,"name":247,"nameZh":6,"description":248,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":249,"categories":250,"keywords":252,"publishedAt":18},"01M6C9YYAVCNTR81V4HGZWPFW1","terraform-search-import","Discover existing cloud resources using Terraform Search queries and bulk import them into Terraform management. Use when bringing unmanaged infrastructure under Terraform control, auditing cloud resources, or migrating to IaC.","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fterraform-search-import\u002FSKILL.md",[251],{"categoryNo":194,"categoryName":195,"taxonomyType":191,"taxonomyTypeDesc":192},[253,254,198,212,255,202,256,205,206,257,258,259,260],"terraform search import","search","support","cloud","list","management","version","iac",{"skillNo":262,"name":263,"nameZh":6,"description":264,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":265,"licenseFileUrl":6,"sourceHtmlUrl":266,"categories":267,"keywords":269,"publishedAt":18},"01M6BZS7EAXHWK32RG213VE65G","run-acceptance-tests","Guide for running acceptance tests for a Terraform provider. Use this when asked to run an acceptance test or to run a test with the prefix `TestAcc`.","MPL-2.0","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fterraform-run-acceptance-tests\u002FSKILL.md",[268],{"categoryNo":194,"categoryName":195,"taxonomyType":191,"taxonomyTypeDesc":192},[270,271,203,197,198,272,205],"run acceptance tests","acceptance","terraform provider",{"skillNo":274,"name":275,"nameZh":6,"description":276,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":277,"categories":278,"keywords":286,"publishedAt":18},"01M6BZS4MJD31PY7M7654ZWQ56","refactor-module","Transform monolithic Terraform configurations into reusable, maintainable modules following HashiCorp's module design principles and community best practices.","https:\u002F\u002Fgithub.com\u002Ftwidxuga\u002Fdotfiles\u002Fblob\u002Fmain\u002Fopencode\u002Fdot-config\u002Fopencode\u002Fskills\u002Fterraform-refactor-module\u002FSKILL.md",[279,282,283],{"categoryNo":280,"categoryName":281,"taxonomyType":191,"taxonomyTypeDesc":192},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":194,"categoryName":195,"taxonomyType":191,"taxonomyTypeDesc":192},{"categoryNo":284,"categoryName":285,"taxonomyType":191,"taxonomyTypeDesc":192},"01JBSEEDCAT000000000000015","视觉设计",[287,288,226,198,205,227,289],"refactor module","refactor","design"]