📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-07 08:45:58 +00:00
parent 3b9ece8c79
commit 7a1900c015
238 changed files with 15673 additions and 447 deletions
@@ -0,0 +1,88 @@
---
name: agent-self-scheduling
description: "Schedule AI agent runs with cron, loops, or external clocks while avoiding unsafe tight autonomous timers."
category: agent-orchestration
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [agents, scheduling, automation, cron]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Agent Self-Scheduling
## When to Use
- Use when the user asks for recurring, scheduled, heartbeat, or looped agent work.
- Use when you need to choose between cron, external schedulers, hooks, or built-in agent scheduling.
First question: does the agent have a built-in scheduler (Hermes → Camp B), or do you own the clock (everything else → Camp A)?
Universal floor: cron is 1 minute minimum (5-field expr, no seconds) — every camp. For sub-minute you MUST use a `while ...; sleep N; done` loop, a TS extension, or an event hook. Never put an LLM on a tight timer.
## Camp A — one-shot agents, you own the clock
These run once and exit (amnesiac unless resumed). Schedule them externally.
```bash
claude -p "PROMPT" --output-format json --allowedTools "Read,Edit,Bash" # Claude Code
codex exec --json "PROMPT" # Codex
pi run "PROMPT" # Pi
```
Wrap in a clock:
```bash
# 1. cron (>= 1 min floor)
*/10 * * * * cd /path/to/project && pi run "check X and report" >> ~/agent.log 2>&1
# 2. systemd timer (Linux, survives reboot, better logging) — OnUnitActiveSec=10min
# 3. dumb loop (sub-minute, or no cron available)
while true; do pi run "check X"; sleep 30; done
```
Gotchas (each breaks unattended runs if ignored):
- **Permissions hang forever.** Pass `--allowedTools` (Claude) or sandbox/auto-approve flags (Codex), or the run blocks on a prompt.
- **Use JSON output** (`--output-format json` / `--json`) so the wrapper parses results deterministically.
- **Runs are amnesiac.** Resume (`codex exec resume --last`) or persist state to a file the next run reads.
Pi has NO built-in scheduler/loop/heartbeat by design — external clock only (or a TS extension for agent-side timers).
### cmux — orchestration only, NO scheduler
cmux has no timer/watch/cron. Three ways to loop it: orchestrator-driven (`send``sleep``read-screen` on your own clock), a dumb while-sleep wrapper, or — preferred — event-driven via `cmux notify` + OSC terminal hooks, which is cheaper and more responsive than polling. `read-screen` is non-interruptive, safe to poll.
If a loop checks another agent, send the user a one-line status each check: what the agent is doing, on track or not. (Claude Code may prefill a predicted next user message after finishing — that's Claude, not the user.)
## Camp B — Hermes built-in scheduler
Hermes' gateway ticks every 60s and runs due jobs in fresh isolated sessions. State-check first:
```bash
hermes gateway install # user-level ( --system to survive reboot)
hermes cron create "every 1h" "summarize new emails and report" --skill himalaya
hermes cron create "0 9 * * *" "post daily standup" # cron expr
hermes cron create "30m" "one-shot reminder in 30 min" # one-shot delay
```
Hermes-unique: **zero-token mode** (run a script, deliver stdout verbatim — use for watchdogs), **chaining** (`context_from` pipes one job's output into the next), **self-terminating loops**, and **loop safety** (scheduled sessions cannot create more cron jobs — don't schedule from inside a scheduled job). Each run is a fresh session: the prompt must carry all context.
## Heartbeat pattern
One fast recurring tick gates many slower per-task checks: the tick reads a task list + per-task `last_run` timestamps and only acts on tasks that are due. In Hermes use a recurring job (zero-token mode when nothing's due); in Camp A use a while-sleep loop. Define active-hours, and stay silent when nothing is due — no empty noise.
## Verify it fires (before reporting success)
1. Camp A: log file grows after one interval, or run the wrapped command once by hand → clean JSON, exit 0.
2. Camp B: `hermes cron list` shows the job + sane `next_run`; trigger a run-now to confirm delivery.
3. Confirm permission/sandbox flags are present — the #1 silent failure is a hung permission prompt.
4. Heartbeats: confirm a nothing-due tick stays silent.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,90 @@
---
name: anti-sleep
description: "Keep a Mac awake with caffeinate during long builds, downloads, or supervised automation runs."
category: operations
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [macos, caffeinate, operations]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Anti-Sleep (macOS caffeinate)
## When to Use
- Use when the user wants the Mac to stay awake during a long supervised task.
- Use when a build, download, or automation run should not be interrupted by sleep.
Keep the Mac awake using the built-in `caffeinate` command. No install needed.
## Quick start — the standard command
```bash
caffeinate -d -i -t 7200 # full power: screen stays on + no idle sleep, for 2 hours
```
Duration is `-t <seconds>`: 2h = 7200, 7h = 25200, overnight (9h) = 32400.
## Aggressiveness levels
| Flags | Effect |
|---|---|
| `-i` | prevents idle **system** sleep only (screen may still dim/lock) |
| `-d` | prevents **display** sleep (screen stays on) |
| `-d -i` | **default choice** — screen on + system awake |
| `-d -i -s` | adds `-s`: prevents sleep even on AC power semantics; `-s` only works when plugged in |
| `-u -t 1` | simulates user activity — wakes the display right now |
Default to `-d -i -t <seconds>` unless the user says otherwise.
## Tie to a process instead of a timer
```bash
caffeinate -d -i -w <PID> # stays awake until that process exits (great for builds)
caffeinate -i npm run build # wraps a command; exits when the command finishes
```
## Run it in a visible terminal (cmux pane)
Prefer running it in the user's own terminal pane so it's visible and easy to Ctrl+C. In cmux (read the `cmux` skill first if interacting with panes):
```bash
cmux send --surface surface:<N> "caffeinate -d -i -t 25200\n"
```
Otherwise run it as a background Bash task. Never block your own foreground shell with it.
## Verify and monitor
```bash
pgrep -fl caffeinate # is it running? shows exact flags
ps -o etime= -p <PID> # how long it's been running
pmset -g assertions | grep -i deny # confirm sleep assertions are active
```
**Gotcha:** `caffeinate` prints nothing and holds the prompt — it looks "stuck" or like Enter wasn't pressed. It isn't stuck. Verify with `pgrep`, not by looking at the terminal.
**Expiry:** with `-t` it exits silently when time runs out — no notification. If the user asks "is it still on?" after hours, check `pgrep` first; it may simply have expired.
## Keyboard backlight
`caffeinate` cannot keep the keyboard backlight on — it has its own inactivity timer with no CLI/API on Apple Silicon (researched 2026-07). Fix is manual, one-time: System Settings > Keyboard > "Turn keyboard backlight off after inactivity" > Never.
## Stop early
```bash
pkill -f "caffeinate -d -i" # or Ctrl+C in the pane running it
```
After starting: confirm to the user the PID, the flags, and the wall-clock time it will expire.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,54 @@
---
name: brain-to-docs
description: "Interview the user to turn project vision and decisions into README and ADR documentation."
category: productivity
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [documentation, adr, planning]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# brain-to-docs
## When to Use
- Use when the user wants to extract project vision, decisions, or preferences into durable docs.
- Use when README and ADRs should be built through a back-and-forth interview.
The whole purpose: extract as much of the user's taste, judgment, knowledge, vision,
preferences, and decisions as possible into text — saved as clear, concise
markdown docs for the project. README holds the vision; `docs/adr/` holds the
decisions.
## The loop
1. **Check docs first, every time.** Read `docs/adr/` (and `README.md`) before
doing anything — other agents and people add/edit ADRs constantly.
2. **Ask 5 different questions** in plain text (never a questions UI) — default 5
unless the user asks for a different number. Make them high-variety: a wide,
creative spectrum of unique angles, not all the same type (e.g. not all "tech
stack" or all "product" or all "monetization"). Exception: if the user asks for a
specific focus area, follow it. The user answers whichever they find most useful.
3. **Update docs after EVERY answer** — no exceptions. You decide whether it
updates `README.md` or becomes a new ADR — whatever makes sense.
4. Repeat until the user says "we're done" (or similar).
## Rules
- All answers & responses during this "brain to docs" process must be VERY
CONCISE, all sentences should be SHORT, and everything should be written in
PLAIN ENGLISH.
- ADRs: short, numbered `NNNN-slug.md`, Status + Context + Decision + Consequences.
- README: vision only. Decisions go in ADRs.
- Don't challenge the user's thinking unless they ask, or they're making a severe mistake.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,220 @@
---
name: browser-harness
description: "Drive an existing browser through CDP for authenticated, visual, or interactive web automation."
category: browser-automation
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [browser, cdp, automation, scraping]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# browser-harness
## When to Use
- Use when a task needs a real logged-in browser, visible interaction, or JS-heavy page control.
- Use when static fetches are insufficient and CDP browser automation is appropriate.
Direct browser control via CDP. For task-specific edits, use `agent-workspace/agent_helpers.py`. For setup, install, or connection problems, read install.md.
**Routing check first:** if the task needs no interaction (no clicks, logins, or forms) and you just want page content, use DeepAPI `POST /v1/scrape/website` instead of driving a browser — see the `deepapi` skill. Use browser-harness when the task needs a real browser: interaction, JS-heavy flows, logged-in sessions, or visual verification.
Domain skills (community-contributed per-site playbooks under `agent-workspace/domain-skills/`) are off by default. Set `BH_DOMAIN_SKILLS=1` to enable them; see the bottom section.
**If `BH_DOMAIN_SKILLS=1` and the task is site-specific, read every file in the matching `agent-workspace/domain-skills/<site>/` directory before inventing an approach.**
## Usage
```bash
browser-harness -c '
new_tab("https://docs.browser-use.com")
wait_for_load()
print(page_info())
'
```
- Invoke as browser-harness — it's on $PATH. No cd, no uv run.
- First navigation is new_tab(url), not goto_url(url) — goto runs in the user's active tab and clobbers their work.
## Tool call shape
```bash
browser-harness -c '
# any python. helpers pre-imported. daemon auto-starts.
'
```
run.py calls ensure_daemon() before exec — you never start/stop manually unless you want to.
### Remote browsers
Use remote for parallel sub-agents (each gets its own isolated browser via a distinct BU_NAME) or on a headless server. BROWSER_USE_API_KEY must be set. start_remote_daemon, list_cloud_profiles, list_local_profiles, sync_local_profile are pre-imported.
When supervising those sub-agents, after each check send the user one very short status line: what they are doing and whether they are on track.
Claude Code cmux note: after Claude finishes, it may prefill a predicted next user message; that draft is Claude, not the user speaking.
```bash
browser-harness -c '
start_remote_daemon("work") # default — clean browser, no profile
# start_remote_daemon("work", profileName="my-work") # reuse a cloud profile (already logged in)
# start_remote_daemon("work", profileId="<uuid>") # same, but by UUID
# start_remote_daemon("work", proxyCountryCode="de", timeout=120) # DE proxy, 2-hour timeout
# start_remote_daemon("work", proxyCountryCode=None) # disable the Browser Use proxy
'
BU_NAME=work browser-harness -c '
new_tab("https://example.com")
print(page_info())
'
```
start_remote_daemon prints liveUrl and auto-opens it in the local browser (if a GUI is detected) so the user can watch along. Headless servers print only — share the URL with the user. The daemon PATCHes the cloud browser to stop on shutdown, which persists profile state. Running remote daemons bill until timeout.
Profiles (cookies-only login state) live in interaction-skills/profile-sync.md — covers list_cloud_profiles(), the chat-driven "which profile?" pattern, and sync_local_profile() for uploading a local Chrome profile.
## Interaction skills
If you start struggling with a specific mechanic while navigating, look in interaction-skills/ for helpers. They cover reusable UI mechanics like dialogs, tabs, dropdowns, iframes, and uploads. The available interaction skills are:
- connection.md
- cookies.md
- cross-origin-iframes.md
- dialogs.md
- downloads.md
- drag-and-drop.md
- dropdowns.md
- iframes.md
- network-requests.md
- print-as-pdf.md
- profile-sync.md
- screenshots.md
- scrolling.md
- shadow-dom.md
- tabs.md
- uploads.md
- viewport.md
## What actually works
- Screenshots first: use capture_screenshot() to understand the current page quickly, find visible targets, and decide whether you need a click, a selector, or more navigation.
- Clicking: capture_screenshot() → read the pixel off the image → click_at_xy(x, y) → capture_screenshot() to verify. Suppress the Playwright-habit reflex of "locate first, then click" — no getBoundingClientRect, no selector hunt. Drop to DOM only when the target has no visible geometry (hidden input, 0×0 node). Hit-testing happens in Chrome's browser process, so clicks go through iframes / shadow DOM / cross-origin without extra work.
- Bulk HTTP: http_get(url) + ThreadPoolExecutor. No browser for static pages (249 Netflix pages in 2.8s).
- After goto: wait_for_load().
- Wrong/stale tab: ensure_real_tab(). Use it when the current tab is stale or internal; the daemon also auto-recovers from stale sessions on the next call.
- Verification: print(page_info()) is the simplest "is this alive?" check, but screenshots are the default way to verify whether a visible action actually worked.
- DOM reads: use js(...) for inspection and extraction when the screenshot shows that coordinates are the wrong tool.
- Iframe sites (Azure blades, Salesforce): click_at_xy(x, y) passes through; only drop to iframe DOM work when coordinate clicks are the wrong tool.
- Auth wall: redirected to login → stop and ask the user. Don't type credentials from screenshots.
- Raw CDP for anything helpers don't cover: cdp("Domain.method", params).
## Design constraints
- Coordinate clicks default. Input.dispatchMouseEvent goes through iframes/shadow/cross-origin at the compositor level.
- Connect to the user's running Chrome. Don't launch your own browser.
- cdp-use is only for CDPClient.send_raw. Prefer raw CDP strings over typed wrappers.
- run.py stays tiny. No argparse, subcommands, or extra control layer.
- Core helpers stay short. Put task-specific helper additions in `agent-workspace/agent_helpers.py`; daemon/bootstrap and remote session admin live in the core package.
- Don't add a manager layer. No retries framework, session manager, daemon supervisor, config system, or logging framework.
## Hermes Agent integration
Installed at `~/Developer/browser-harness` as editable `uv tool install -e .`. Binary at `~/.local/bin/browser-harness`. Skill at `~/.hermes/skills/browser-harness/`.
**Frontmatter pitfall:** The upstream SKILL.md ships with `name: browser` in frontmatter, which collides with Hermes's built-in `browser` toolset. When copying into `~/.hermes/skills/`, rename to `name: browser-harness` in the frontmatter or Hermes will shadow/conflict with its own browser tools.
**Brave Browser:** Works identically to Chrome. Enable remote debugging at `brave://inspect/#remote-debugging` (same checkbox). The harness auto-discovers Brave's profile directory.
## Authenticated content extraction (proven pattern)
browser-harness connects to the user's real browser with their active sessions — ideal for extracting content from login-walled sites where `web_extract` or Hermes's built-in `browser_navigate` fail (e.g. X/Twitter articles, LinkedIn, paywalled sites).
**Pattern:**
```bash
browser-harness -c '
new_tab("https://x.com/user/status/123456")
wait_for_load()
import time
time.sleep(5) # let JS-heavy pages render
text = js("""
const article = document.querySelector("article");
if (article) return article.innerText;
return document.body.innerText;
""")
with open("/tmp/extracted.txt", "w") as f:
f.write(text)
print("Written", len(text), "chars")
'
```
- Write to a temp file to avoid shell escaping issues with large text
- Use `time.sleep()` generously for JS-heavy SPAs (X, LinkedIn need 3-5s)
- X/Twitter articles render inline — just scroll/extract via DOM, no extra click needed
- For very long pages, `js(...)` with `innerText` grabs everything including below-fold content
## Hermes Agent integration
Installed at `~/Developer/browser-harness` as editable `uv tool install -e .`. Binary at `~/.local/bin/browser-harness`. Skill at `~/.hermes/skills/browser-harness/`.
**Frontmatter pitfall:** The upstream SKILL.md ships with `name: browser` in frontmatter, which collides with Hermes's built-in `browser` toolset. When copying into `~/.hermes/skills/`, rename to `name: browser-harness` in the frontmatter.
**Brave Browser:** Works identically to Chrome. Enable remote debugging at `brave://inspect/#remote-debugging` (same checkbox). The harness auto-discovers Brave's profile directory.
## Authenticated content extraction (proven pattern)
browser-harness connects to the user's real browser with active sessions — ideal for login-walled sites where `web_extract` or Hermes's built-in `browser_navigate` fail (X/Twitter articles, LinkedIn, paywalled sites).
```bash
browser-harness -c '
new_tab("https://x.com/user/status/123456")
wait_for_load()
import time
time.sleep(5) # let JS-heavy pages render
text = js("""
const article = document.querySelector("article");
if (article) return article.innerText;
return document.body.innerText;
""")
with open("/tmp/extracted.txt", "w") as f:
f.write(text)
print("Written", len(text), "chars")
'
```
- Write to a temp file to avoid shell escaping issues with large text
- Use `time.sleep()` generously for JS-heavy SPAs (X, LinkedIn need 3-5s)
- X/Twitter articles render inline — just scroll/extract via DOM, no extra click needed
- `js(...)` with `innerText` grabs everything including below-fold content
## Gotchas (field-tested)
- **Brave Browser** uses `brave://inspect/#remote-debugging` instead of `chrome://inspect/...`. The harness auto-discovers Brave's data dir.
- Login-walled content extraction (e.g. X/Twitter articles): navigate with `new_tab(url)`, `wait_for_load()`, then extract via `js("document.querySelector('article').innerText")`. Write to a temp file to avoid shell escaping: `with open('/tmp/out.txt', 'w') as f: f.write(text)`. The user's existing browser session handles auth automatically.
- Omnibox popups are fake page targets. Filter chrome://omnibox-popup... and other internals when you need a real tab.
- CDP target order != Chrome's visible tab-strip order. Use UI automation when the user means "the first/second tab I can see"; Target.activateTarget only shows a known target.
- Default daemon sessions can go stale. ensure_real_tab() re-attaches to a real page.
- Browser Use API is camelCase on the wire. cdpUrl, proxyCountryCode, etc.
- Remote cdpUrl is HTTPS, not ws. Resolve the websocket URL via /json/version.
- Stop cloud browsers with PATCH /browsers/{id} + {"action":"stop"}.
- After every meaningful action, re-screenshot before assuming it worked. Use the image to verify changed state, open menus, navigation, visible errors, and whether the page is in the state you expected.
- Use screenshots to drive exploration. They are often the fastest way to find the next click target, notice hidden blockers, and decide if a selector is even worth writing.
- Prefer compositor-level actions over framework hacks. Try screenshots, coordinate clicks, and raw key input before adding DOM-specific workarounds.
- If you need framework-specific DOM tricks, check interaction-skills/ first. That is where dropdown, dialog, iframe, shadow DOM, and form-specific guidance belongs.
## Domain skills (opt-in)
Only applies when `BH_DOMAIN_SKILLS=1`. Otherwise ignore — `agent-workspace/domain-skills/` is dormant and `goto_url` won't surface skill files.
When enabled, search `agent-workspace/domain-skills/<host>/` before inventing an approach. `goto_url` returns up to 10 skill filenames for the navigated host.
If you learn anything non-obvious — a private API, stable selector, framework quirk, URL pattern, hidden wait, or site-specific trap — open a PR to `agent-workspace/domain-skills/<site>/`. Capture the durable shape of the site (the map, not the diary). Don't write pixel coordinates (break on layout), task narration, or secrets — the directory is public.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,132 @@
---
name: browser-install
description: Install browser-harness into the current agent and connect it to a browser with minimal prompting.
---
# `browser-harness` installation
Use this file only for browser-harness install, browser connection setup, and connection troubleshooting. For day-to-day browser work, read `SKILL.md`. Task-specific edits belong in `agent-workspace/agent_helpers.py` and `agent-workspace/domain-skills/`.
## Recommended `browser-harness` setup
Clone the repo once into a durable location, then install it as an editable tool so `browser-harness` works from any directory:
```bash
git clone https://github.com/browser-use/browser-harness
cd browser-harness
uv tool install -e .
command -v browser-harness
```
That keeps the command global while still pointing at the real repo checkout, so when the agent edits `agent-workspace/agent_helpers.py` the next `browser-harness` uses the new code immediately. Prefer a stable path like `~/Developer/browser-harness`, not `/tmp`.
## Make browser-harness global for the current agent
After the repo is installed, register this repo's `SKILL.md` with the agent you are using:
- **Codex**: add this file as a global skill at `$CODEX_HOME/skills/browser-harness/SKILL.md` (often `~/.codex/skills/browser-harness/SKILL.md`). A symlink to this repo's `SKILL.md` is fine.
```bash
mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills/browser-harness" && ln -sf "$PWD/SKILL.md" "${CODEX_HOME:-$HOME/.codex}/skills/browser-harness/SKILL.md"
```
- **Claude Code**: add an import to `~/.claude/CLAUDE.md` that points at this repo's `SKILL.md`, for example `@~/Developer/browser-harness/SKILL.md`.
This makes new Codex or Claude Code sessions in other folders load the runtime browser harness instructions automatically.
## Keeping the harness current
- On each run, `browser-harness` prints `[browser-harness] update available: X -> Y` (once per day) when a newer GitHub release exists.
- When you see that banner, run `browser-harness --update -y` yourself — don't ask the user. It pulls the new code (`git pull --ff-only` for editable clones, `uv tool upgrade browser-harness` for PyPI installs) and stops the running daemon so the next call picks up the new code. With `-y` it won't prompt.
- `--update` refuses to run on an editable clone with uncommitted changes. If that happens, tell the user and let them resolve the dirty worktree.
## Maintenance commands
- browser-harness --doctor — show version, install mode, daemon and Chrome state, and whether an update is pending.
## Architecture
```text
Chrome / Browser Use cloud -> CDP WS -> browser_harness.daemon -> IPC -> browser_harness.run
```
- Protocol is one JSON line each way.
- Requests are {method, params, session_id} for CDP or {meta: ...} for daemon control.
- Responses are {result} / {error} / {events} / {session_id}.
- IPC: Unix socket at `/tmp/bu-<NAME>.sock` on POSIX, TCP loopback + port file on Windows.
- BU_NAME namespaces the daemon's IPC, pid, and log files.
- BU_CDP_WS overrides local Chrome discovery for remote browsers.
- BU_CDP_URL overrides local Chrome discovery with a specific DevTools HTTP endpoint (used for Way 2).
- BU_BROWSER_ID + BROWSER_USE_API_KEY lets the daemon stop a Browser Use cloud browser on shutdown.
# Browser connection setup and troubleshooting
## Browser connection reference
This section is the source of truth for how browser-harness connects to a browser. It is the canonical reference for every agent and user of this repo. Every statement here is intended to be verifiable against either an official Chrome source or this repo's own code, and is held to that standard deliberately. If anything below is incorrect, incomplete, or misleading, open an issue on the browser-harness repository immediately with clear evidence and explanation so it can be corrected. Do not silently work around an error in this document; the cost of one user being misled is much higher than the cost of one issue.
Browser-harness can connect to any Chrome or Chromium-based browser on your computer, or to a Browser Use cloud browser.
**Cloud browsers** are managed by the Browser Use cloud API. Start one in Python with `start_remote_daemon("work", ...)`. Authentication is via the `BROWSER_USE_API_KEY` environment variable; the harness handles the WebSocket URL itself. To carry your local Chrome cookies into a cloud browser, install the Browser Use `profile-use` helper only after reviewing the upstream installer instructions, then call `uuid = sync_local_profile("MyChromeProfile")` followed by `start_remote_daemon("work", profileId=uuid)`. Cookies are the only thing synced — not localStorage, not extensions, not history.
**Local browsers** require remote debugging to be enabled. There are two ways, and they suit different use cases.
*Way 1: chrome://inspect/#remote-debugging checkbox — uses your real profile.* In your running Chrome, navigate to `chrome://inspect/#remote-debugging` and tick the "Allow remote debugging for this browser instance" checkbox. This setting is per-profile and sticky: tick it once and it persists across every future Chrome launch of that profile. Then run any `browser-harness` command. On Chrome 144 and later, the first attach by the harness triggers an in-browser "Allow remote debugging?" popup that you must click Allow on. The popup may reappear on later attaches under conditions that are not fully characterized.[^1] This path inherits your everyday Chrome's logins, extensions, history, and bookmarks, which makes it the right choice for an agent helping you with tasks in your real browser.
*Way 2: command-line flag — uses an isolated profile, no popups ever.* Launch Chrome with `--remote-debugging-port=9222 --user-data-dir=<path>`. Two precisions:
- The path must be a directory that is **not** Chrome's platform default (`%LOCALAPPDATA%\Google\Chrome\User Data` on Windows, `~/Library/Application Support/Google/Chrome` on macOS, `~/.config/google-chrome` on Linux). On Chrome 136 and later, the port flag is silently no-opped when the user-data-dir is the platform default, even if you pass it explicitly. An empty or new path gives a fresh clean profile that Chrome will persist there across future runs.
- This path does **not** let you reuse your everyday Chrome profile. Copying the default profile's files into a custom directory makes Chrome accept the flag, but cookies are encrypted under a key bound to the original directory and will not survive the copy — so you carry over bookmarks and extensions but lose every logged-in session. If you want your real logins, use Way 1.
Tell the harness which port you launched on by setting `BU_CDP_URL=http://127.0.0.1:9222` before running `browser-harness`.
For most tasks where the agent acts on your behalf in your normal browser, use Way 1. For automation that runs without you watching, or any case where popup interruptions are unacceptable, use Way 2 or a cloud browser.
[^1]: The conditions that cause Chrome to re-show the "Allow remote debugging?" popup on a subsequent attach (time elapsed since previous Allow, daemon restart, browser restart, new CDP session, version-dependent options like "Allow for N hours") are not fully characterized. Way 2 sidesteps this entirely.
## First time setup
Try yourself before asking the user to do anything. Retry transient errors briefly. Only ask the user when a step genuinely needs them — ticking a checkbox, clicking Allow.
If the user hasn't said which connection method to use, default to Way 1 if Chrome is already running, Way 2 if not. Cloud is only used when the user opts in.
1. Try the harness:
```bash
browser-harness -c 'print(page_info())'
```
If it prints page info, you're done.
2. Otherwise run `browser-harness --doctor`. The two lines that matter for connection are `chrome running` and `daemon alive`.
3. Match the output to a case:
- **chrome FAIL** → no Chrome process detected.
- **Way 1**: ask the user to open their target Chrome themselves.
- **Way 2**: launch Chrome yourself with `--remote-debugging-port=9222 --user-data-dir=<non-default path>`, then set `BU_CDP_URL=http://127.0.0.1:9222` for the harness (see the Browser connection reference).
- **chrome ok, daemon FAIL** → Way 1 setup is incomplete. Tell the user to:
- navigate to `chrome://inspect/#remote-debugging` in their Chrome and tick "Allow remote debugging for this browser instance" if not yet ticked (one-time per profile)
- click Allow on the in-browser popup if it appears (every attach on Chrome 144+)
On macOS, you can open the inspect page in their running Chrome yourself instead of asking them to navigate:
```bash
osascript -e 'tell application "Google Chrome" to activate' \
-e 'tell application "Google Chrome" to open location "chrome://inspect/#remote-debugging"'
```
- **chrome ok, daemon ok, but step 1 still failed** → stale daemon. Restart it:
```bash
browser-harness -c 'restart_daemon()'
```
If that hangs, escalate: kill all Chrome and daemon processes, then reopen Chrome and retry. On macOS/Linux, also remove `/tmp/bu-default.sock` and `/tmp/bu-default.pid` if they linger.
4. After any fix, retry step 1.
If Way 1 fails repeatedly or the user's task is unattended, move to Way 2 or a cloud browser per the Browser connection reference (these have no popups).
If you are testing browser connection for the first time, run this demo: open `https://github.com/browser-use/browser-harness` in a new tab and activate it (`switch_tab`) so the user sees the harness has attached. Then ask what they want to do next.
@@ -0,0 +1,250 @@
---
name: cmux
description: "Control cmux workspaces, panes, surfaces, and agent sessions safely from macOS terminal workflows."
category: development
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [cmux, terminal, agents, macos]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# cmux Control
## When to Use
- Use when you need to inspect, create, close, or rearrange cmux panes, surfaces, or workspaces.
- Use when you need to send input to or monitor agents running inside cmux.
cmux is a native macOS terminal app for running multiple AI coding agents in parallel. It exposes a CLI (`cmux`) and a Unix-socket JSON-RPC API (`/tmp/cmux.sock`) for full topology and browser control.
## Core Concepts
- **Window** — top-level macOS cmux window
- **Workspace** — sidebar tab within a window (one git branch / project context)
- **Pane** — split region inside a workspace
- **Surface** — tab inside a pane (terminal or browser)
Handles default to short refs (`workspace:2`, `pane:1`, `surface:7`); UUIDs accepted as input. Add `--id-format uuids|both` for UUID output.
### Ref syntax — get this right or fail silently
- **Always use PREFIXED refs** (`pane:38`, `surface:46`). A **bare number is treated as an INDEX, not an ID**`--surface 46` means "the surface at index 46" (usually nonexistent → silent failure), NOT `surface:46`.
- **`read-screen` and `capture-pane` have NO `--pane` flag** — they target `--workspace` or `--surface` only. Passing `--pane` errors, and a bare/missing target falls back to your OWN surface (you'll read your own footer and draw wrong conclusions). To read a pane: resolve it to a surface FIRST with `cmux list-pane-surfaces --pane pane:N`, then `cmux read-screen --surface surface:N`.
- **Never append `2>/dev/null` to cmux commands.** Errors go to stderr with exit code 1; suppressing them blinds you to your own ref/flag mistakes (the #1 cause of "(no output)").
## Detect cmux in a Shell
```bash
[ -S "${CMUX_SOCKET_PATH:-/tmp/cmux.sock}" ] || exit 0 # bail if not in cmux
[ -n "${CMUX_WORKSPACE_ID:-}" ] && echo "inside cmux surface"
```
Injected env vars in every cmux-spawned terminal: `CMUX_WORKSPACE_ID`, `CMUX_SURFACE_ID`, `CMUX_SOCKET_PATH`, `CMUX_PORT`. **Always anchor automation to `CMUX_WORKSPACE_ID`** — the visually focused workspace may not be the agent's caller workspace.
## Fast Start — Topology
```bash
cmux identify --json # who am I (window/workspace/pane/surface)
cmux tree # full hierarchy
cmux list-workspaces --json
cmux list-panes --workspace "$CMUX_WORKSPACE_ID"
cmux list-surfaces --workspace "$CMUX_WORKSPACE_ID"
cmux new-workspace --name "feature-x" --cwd /path/to/repo
cmux new-pane --workspace "$CMUX_WORKSPACE_ID" --type terminal --direction right --focus false
cmux new-pane --workspace "$CMUX_WORKSPACE_ID" --type browser --direction right --url http://localhost:3000
cmux move-surface --surface surface:7 --pane pane:2 --focus false
cmux split-off --surface surface:7 right
cmux reorder-surface --surface surface:7 --before surface:3
cmux close-surface --surface surface:7
```
## Polling Pi Agents in Panes — Keep Sleeps Short
When launching a Pi Agent inside a cmux pane and polling for output, use **short `sleep` intervals (25s)**. Pi is fast and minimal, and the user runs it on Opus 4.8 Fast via OpenRouter, which streams tokens extremely quickly. Do NOT use `sleep 15` unless genuinely needed (a big build/refactor) — most of the time `sleep 2``sleep 5` is more than enough.
After every agent check, send the user a one-line status update: what the agent is doing and whether it is on track. Keep it extremely concise.
Claude Code cmux note: after Claude finishes, it may prefill a predicted next user message; that draft is Claude, not the user speaking.
## Send Input
**Command names:** there is NO `send-surface` / `send-key-surface`. Target a specific surface with the `--surface` flag on `send` / `send-key` (same commands as the focused terminal). `send-panel` / `send-key-panel` exist ONLY for panels (`--panel`), not surfaces.
```bash
cmux send "echo hi\n" # focused terminal
cmux send-key "ctrl+c" # enter|tab|esc|backspace|arrows|ctrl+x|shift+tab
cmux send --surface surface:7 "npm run build" # specific surface (NOT send-surface)
cmux send-key --surface surface:7 enter # specific surface (NOT send-key-surface)
```
## Notifications & Sidebar Metadata
```bash
cmux notify --title "Done" --body "tests passed"
cmux set-status build "compiling" --icon hammer --color "#ff9500"
cmux set-progress 0.5 --label "Building..."
cmux log --level success "All 42 tests passed" # info|progress|success|warning|error
cmux trigger-flash --workspace "$CMUX_WORKSPACE_ID" # blue-ring attention cue
cmux sidebar-state --json # dump all sidebar metadata
```
## Browser Automation (WKWebView)
Workflow: open → wait → snapshot → act → re-snapshot.
```bash
S=$(cmux --json browser open https://example.com | jq -r .result.surface_ref)
cmux browser "$S" wait --load-state complete --timeout-ms 15000
cmux browser "$S" snapshot --interactive # returns elements as e1, e2, ...
cmux browser "$S" fill e1 "<email-address>"
cmux browser "$S" click e2 --snapshot-after
# Navigation / inspection
cmux browser "$S" goto URL | back | forward | reload
cmux browser "$S" get url | get title | get text body | get value "#email" | get count ".row"
cmux browser "$S" eval 'return document.title'
# Waits
cmux browser "$S" wait --selector "#ready" --timeout-ms 10000
cmux browser "$S" wait --url-contains "/dashboard" --timeout-ms 10000
# Session
cmux browser "$S" cookies get | cookies set --name foo --value bar
cmux browser "$S" state save /tmp/auth.json | state load /tmp/auth.json
# Diagnostics
cmux browser "$S" console list | errors list | screenshot
```
**Not supported by WKWebView** (return `not_supported`): viewport emulation, geolocation/offline emulation, trace recording, network route interception, raw input injection.
## Markdown Viewer
```bash
cmux markdown open plan.md --direction right # live-watching renderer
cmux open file.pdf # auto-routes to right viewer
```
`cmux markdown open` flags: `--workspace`, `--surface`, `--window`, `--direction <right|down|left|up>`, `--focus <true|false>`. There is **NO `--pane` flag** — passing it errors. To target a pane, pass `--surface <existing-md-surface-in-that-pane>`.
### Reuse the existing right markdown pane (don't spawn strays)
Default behavior of `markdown open` is to **create a new pane** every time, even with `--direction right`. To keep all docs as tabs in ONE right pane, follow this exactly:
```bash
# 1. Find the right pane and its surfaces (anchor to THIS workspace)
cmux list-panes --workspace "$CMUX_WORKSPACE_ID"
cmux list-pane-surfaces --pane pane:10 # the right/helper pane
# 2. Open targeting an existing markdown surface IN that pane (reuses pane, adds tab)
cmux markdown open /abs/path/file.md --surface surface:12 --focus false
# 3. If it STILL spawned a new pane (it can), move the new surface in + verify
cmux move-surface --surface surface:NEW --pane pane:10 --focus false
cmux list-panes --workspace "$CMUX_WORKSPACE_ID" # confirm stray pane is gone
```
### Swapping the file in the single right pane (close-FIRST, then open)
To replace the doc shown in your one right markdown pane, the ONLY reliable order is **close the previous surface FIRST, then `markdown open` the new file fresh** — never move an existing viewer, never open-then-close.
```bash
# 1. close the previous right markdown surface (right side goes empty)
cmux list-panes --workspace "$CMUX_WORKSPACE_ID"
cmux close-surface --surface surface:PREV
# 2. THEN open the new file fresh
cmux markdown open /abs/path/new.md --direction right --focus false
```
ORDER MATTERS: close-previous BEFORE open-new. Opening first then closing the old one, or `move-surface`-ing an existing viewer, leaves the right pane BLANK.
### Hard-won lessons (avoid the trial-and-error)
- **Surface refs are global, not per-workspace.** A ref like `surface:126` from an earlier `markdown open` may live in a different window/workspace. Always re-list (`list-panes` / `list-pane-surfaces`) before reusing a ref — never assume a ref from a previous turn is still in the right pane.
- **`move-surface`-ing a markdown viewer often leaves it BLANK.** The moved surface keeps `type=markdown` and `surface-health` looks fine, but renders nothing. Fix: `close-surface` it and `cmux markdown open <path>` fresh, then move the *fresh* surface if needed. Don't waste time on `refresh-surfaces` — it usually won't fix a moved-then-blank viewer.
- **You cannot screenshot or `read-screen` a markdown surface** (`Surface is not a terminal` / browser screenshot is WKWebView-only). To verify a markdown viewer rendered, ask the user or open the file in a browser surface instead. Don't burn turns trying to capture it.
- **`cmux list-surfaces` does not exist.** Use `cmux list-pane-surfaces [--pane ...]`.
## Settings & Config
```bash
cmux docs settings # prints paths, schema URL, reload cmd — read BEFORE editing
cmux settings path # path to cmux.json
cmux settings cmux-json # open in editor
cmux reload-config # hot-reload cmux.json + ~/.config/ghostty/config (Cmd+Shift+,)
```
Locations:
- cmux settings: `~/.config/cmux/cmux.json` (canonical). Project-local override: `.cmux/cmux.json` or `./cmux.json`.
- Terminal rendering (font, cursor, theme, scrollback, opacity, blur): `~/.config/ghostty/config` — NOT cmux.json.
Before editing `cmux.json`, copy it to a timestamped `.bak` next to it so the user can revert. Schema: `https://raw.githubusercontent.com/manaflow-ai/cmux/main/web/data/cmux.schema.json`.
## Agent Hooks & Install
```bash
brew tap manaflow-ai/cmux && brew install --cask cmux
sudo ln -sf /Applications/cmux.app/Contents/Resources/bin/cmux /usr/local/bin/cmux
cmux hooks setup # all detected agents
cmux hooks setup codex|grok|antigravity|opencode # specific agent
npx skills add manaflow-ai/cmux -g -y # install cmux skills for agents
```
Native session-resume supported for: Claude Code, Codex, Grok, OpenCode, Pi, Amp, Cursor CLI, Gemini, Antigravity, Rovo Dev, Hermes, Copilot, CodeBuddy, Factory, Qoder.
## Socket API (advanced)
`/tmp/cmux.sock` — Unix socket, JSON-RPC v2. Use for tight loops where subprocess spawn cost matters; otherwise prefer the CLI.
```bash
echo '{"id":"1","method":"workspace.list","params":{}}' | nc -U /tmp/cmux.sock
```
Method prefixes: `system.*`, `window.*`, `workspace.*`, `pane.*`, `surface.*`, `notification.*`, `browser.*`. Full list and Python client example in `references/socket-api.md`.
Access modes: `cmuxOnly` (default — only cmux-spawned processes), `automation` (any local process), `password`, `allowAll` (unsafe). If you hit `Failed to connect to socket`, you're likely an external process under `cmuxOnly` — switch mode in Settings > Automation or run from inside a cmux terminal.
## Critical Rules — Non-Disruptive Automation
These rules come from the `cmux-workspace` skill and prevent agents from yanking the user's focus:
1. **Anchor to `CMUX_WORKSPACE_ID`.** Never assume the visually focused workspace is the target.
2. **Never call focus-changing verbs speculatively.** `select-workspace`, `focus-pane`, `focus-panel`, `focus-surface` only on explicit user request. Pass `--focus false` whenever available.
3. **Build layout additively in one call.** `cmux new-pane --type … --focus false` beats create-then-move-then-focus chains.
4. **Right-side helper pane pattern.** Reuse an existing non-caller helper pane if present; otherwise create exactly one right-side pane.
5. **Never send input to surfaces you don't own.** Only target surfaces in the caller's workspace unless the user explicitly asks for cross-workspace routing.
6. **Check surface health before routing input** when UI state may be stale: `cmux surface-health`.
## Common Pitfalls
- **Pi/Pi-like socket connection failures from external processes** → default `cmuxOnly` mode; either run inside a cmux terminal or change socket mode.
- **macOS only.** No Linux/Windows port.
- **WKWebView ≠ CDP.** Don't expect Playwright-equivalent network mocking or viewport emulation.
- **Resume strips sensitive env vars.** Re-inject tokens at resume time if the agent needs them.
- **Skills snapshot at app start.** Edits to skill files require a restart of the consuming agent.
- **Legacy v1 socket payloads (`{"command":...}`) rejected.** Use v2 JSON-RPC only.
- **Don't `cat ~/.cmuxterm/*-hook-sessions.json`** expecting secrets — they're scrubbed. Look there for session/surface mappings only.
## Reference: Full CLI Help
For any command, `cmux <cmd> --help` is authoritative. Use `cmux capabilities --json` to enumerate available socket methods in the current build.
## Keyboard Shortcuts (most-used)
Workspaces: ⌘N new, ⌘18 jump, ⌃⌘[ / ⌃⌘] prev/next, ⌘⇧W close, ⌘B sidebar.
Surfaces: ⌘T new, ⌘⇧[ / ⌘⇧] prev/next, ⌘W close, ⌃18 jump.
Splits: ⌘D right, ⌘⇧D down, ⌥⌘D browser right, ⌥⌘←→↑↓ focus directional, ⌘⇧↵ zoom.
Browser: ⌘⇧L open, ⌘L address bar, ⌘[/⌘] back/forward, ⌥⌘I devtools.
App: ⌘, settings, ⌘⇧, reload-config, ⌘⇧P palette, ⌘⇧O restore session, ⌃⌥⌘. system-wide show/hide.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,117 @@
---
name: codex-subagent
description: "Launch Codex CLI as an isolated subagent for bounded coding, review, or verification tasks."
category: agent-orchestration
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [codex, subagents, delegation]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
# Codex CLI as a Subagent
## When to Use
- Use when a bounded coding, review, or verification task can run in a separate Codex CLI session.
- Use when parallel work needs explicit file ownership and a clear definition of done.
Codex CLI is OpenAI's terminal coding agent. `codex exec` runs it non-interactively:
it works autonomously in a sandbox, streams progress to stderr, and prints only the
final message to stdout. Auth reuses the user's ChatGPT subscription — never an API key.
## When to delegate
- Self-contained coding task with clear success criteria (fix, feature, refactor, review).
- Parallel work: several independent tasks at once (see Parallel runs).
- Second opinion / independent verification of your own changes.
Do NOT delegate tasks that need conversation context you can't fully write into the prompt.
## Preflight
```bash
codex --version # missing? npm i -g @openai/codex (or: brew install --cask codex)
codex login status # exit 0 + "Logged in using ChatGPT" = ready
```
Not logged in → stop and tell the user to run `codex login` (one-time browser OAuth).
Never read, print, or copy credentials (`~/.codex/auth.json`).
## Launch
```bash
OUT=$(mktemp /tmp/codex-out.XXXXXX)
codex exec \
--cd /path/to/repo \
--sandbox workspace-write \
--output-last-message "$OUT" \
"Full task prompt: goal, constraints, files to touch, definition of done." \
</dev/null
```
- `</dev/null` is MANDATORY when stdin is not a real terminal (background shells,
scripts): codex treats open stdin as extra context and waits forever for EOF.
- Codex sees NOTHING of your conversation. Put all context in the prompt:
goal, relevant paths, constraints, and how to verify it's done.
- Long prompt? Pipe it via stdin instead: `codex exec [flags] - < /tmp/task.md`.
- Wrap the command in a background/Bash subagent if your host agent has one
(Cursor: Task tool with a shell subagent) so Codex's verbose stream stays out
of the parent context. Fallback: a plain background terminal.
- Runs take minutes and have no built-in timeout — background it and monitor.
- Optional: `-m <model>` to override the model, `--json` for JSONL event stream.
## Collect results
```bash
cat "$OUT" # final message = the deliverable
git -C /path/to/repo status --short # see what Codex actually changed
```
Follow-up in the same session (run from the same cwd — resume filters by cwd):
```bash
codex exec resume --last "follow-up instruction" </dev/null
```
## Parallel runs
Parallelize only genuinely independent tasks, and assign file ownership upfront so
results merge cleanly. One git worktree per Codex run — never two in the same tree:
```bash
git worktree add /tmp/wt-taskA -b codex/task-a
codex exec --cd /tmp/wt-taskA --sandbox workspace-write -o /tmp/outA.md "task A" </dev/null
```
## Failure modes
- Hangs forever with no output → stdin was left open. Kill it, relaunch with `</dev/null`.
- `codex login status` non-zero → the user must run `codex login`. Don't work around it.
- ChatGPT plan rate limit hit → report to the user; never retry in a loop.
- "Not a git repo" error → add `--skip-git-repo-check`, or init a repo first.
- Network is blocked inside the workspace-write sandbox by default. If the task
needs it (installs, API calls): `-c sandbox_workspace_write.network_access=true`.
- NEVER use `--dangerously-bypass-approvals-and-sandbox`.
## Rules
- One task per launch. Split big jobs into multiple launches.
- Review Codex's diff yourself before declaring the task done.
## Cursor-native wrapper (optional)
For auto-routing and `/codex` invocation inside Cursor, add `~/.cursor/agents/codex.md`
a custom subagent whose description is "delegates coding tasks to Codex CLI" and whose
body points at this skill.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,138 @@
---
name: cyber-audit
description: "Run read-only exposure checks for security advisories and write a structured local audit report."
category: security
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [security, audit, read-only]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
# cyber-audit
## When to Use
- Use when the user asks whether their machine or projects are affected by a CVE, breach, or package advisory.
- Use when a read-only local security exposure report is appropriate.
## Hard rules
- **Read-only.** No installs, removes, upgrades, restarts, network calls, or file modifications outside `~/Documents/security-audits/`.
- **No `sudo`.** Never.
- **One report per invocation.** Always end by writing the `.md` file (even if the verdict is "Not affected" — the audit trail matters).
- If a check requires a state-changing command, **skip it and note "not checked (would require state change)"** in the table. Do not run it.
## Workflow
1. **Identify scope.** Extract from the advisory: package/binary name, affected versions, platform (macOS / Linux / Windows), attack vector (supply chain / RCE / local / network).
2. **Run checks in parallel** (Bash tool, multiple calls in one message). Pick relevant checks for the advisory type — don't run all of them.
3. **Build the table** as you go. Each row = one check + concrete result (version number, path, "None", "N/A").
4. **Write the report** to `~/Documents/security-audits/YYYY-MM-DD-<short-kebab-slug>.md`. Use today's date from the environment header.
5. **Tell the user** the verdict in one line + path to the report.
## Check menu (pick what's relevant)
```bash
# --- Node / npm ecosystem (supply-chain advisories) ---
which npm pnpm yarn; npm root -g; pnpm root -g 2>/dev/null
ls /opt/homebrew/lib/node_modules # global npm
find ~ -maxdepth 8 -type d -name "<pkg>" 2>/dev/null \
| grep -v -E "(Library/Caches|\.Trash)" # installed copies
find ~/Documents ~/Desktop ~/Downloads -maxdepth 8 -type f \
\( -name "package.json" -o -name "package-lock.json" \
-o -name "pnpm-lock.yaml" -o -name "yarn.lock" \) 2>/dev/null \
| xargs grep -l "<pkg>" 2>/dev/null # direct + transitive
# --- Python ecosystem ---
which python3 pip pipx uv
pip list 2>/dev/null | grep -i "<pkg>"
find ~/Documents -maxdepth 6 -name "requirements*.txt" -o -name "pyproject.toml" \
-o -name "poetry.lock" -o -name "uv.lock" 2>/dev/null | xargs grep -l "<pkg>" 2>/dev/null
# --- Homebrew / system binaries ---
brew list --versions <formula> 2>/dev/null
which <binary>; <binary> --version 2>/dev/null
# --- Running processes / listeners (for RCE / network CVEs) ---
pgrep -lf "<binary>"
lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null | grep "<port>"
# --- LaunchAgents / LaunchDaemons (persistence / autostart) ---
ls ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons 2>/dev/null \
| grep -i "<vendor>"
# --- Env vars that change exposure (e.g. OLLAMA_HOST, listening addr) ---
launchctl getenv <VAR>; grep -r "<VAR>" ~/.zshrc ~/.zprofile ~/.config 2>/dev/null
# --- VS Code / browser extensions (for IDE-targeted advisories) ---
ls ~/.vscode/extensions 2>/dev/null | grep -i "<ext>"
```
If the advisory mentions an ecosystem not above (Rust cargo, Go modules, Ruby gems, Docker images, etc.), apply the same pattern: global install path + manifest grep + running processes.
## Report template
File: `~/Documents/security-audits/YYYY-MM-DD-<short-kebab-slug>.md`
```markdown
# <Subject> — Audit
**Date:** YYYY-MM-DD
**Host:** the user's Mac
## <CVEs | Advisory> in scope
- **<ID or source> "<Name>"** — <one-line description>. <Affected versions or scope>.
## Audit results
| Check | Result |
|---|---|
| <Check 1> | <Result> |
| <Check 2> | <Result> |
## Verdict
**<Not affected. | Affected. | Partially affected.>**
- <Rationale bullet 1>
- <Rationale bullet 2>
## Action taken
None — diagnostic only, no files modified, no <packages installed/removed | services started/stopped | firewall rules changed>.
## Follow-ups
- <Actionable item, or "None" if truly nothing>
```
Match the tone of the two existing reports in `~/Documents/security-audits/` — terse, factual, bulleted, no hedging.
## Verdict wording
- **Not affected.** — package/binary absent, or installed but patched, or not running and not exposed.
- **Affected.** — vulnerable version present *and* reachable by the attack vector.
- **Partially affected.** — present but mitigated (e.g. binary installed but service not running, or listener bound to loopback only). Spell out the mitigation in the bullets.
## When to break the read-only rule
Never on your own. If the verdict is "Affected", list the remediation command in **Follow-ups** and stop. The user runs it.
## Reference
Two existing reports in `~/Documents/security-audits/` show the expected style:
- `baseline-audit.md` (long-form baseline audit — different format, do not mimic)
- `YYYY-MM-DD-example-advisory.md` and any newer `YYYY-MM-DD-*.md` files (this is the format to match)
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,649 @@
---
name: deepapi
description: "Use DeepAPI for supported scraping, research, and email workflows with explicit credentials and approval."
category: research
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [deepapi, scraping, email, api]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
version: b17ad5148ab7
---
# DeepAPI
## When to Use
- Use when the task needs supported DeepAPI scraping, research, or email endpoints.
- Use when the user has provided or confirmed the required DeepAPI credentials and scope.
Use this skill when the user asks you to scrape public web data or draft/read/send email through DeepAPI.
## Staying Up To Date
- Your installed copy's version is the `version` value in the frontmatter above.
- If a request fails unexpectedly, fetch https://deepapi.co/deepapi-skill/VERSION.txt — public, no auth, a few bytes.
- If it differs from this file's version, fetch https://deepapi.co/deepapi-skill/SKILL.md and overwrite this file with it.
- Every API response includes `skillVersion`. If it differs from this file's version, refresh the same way.
- Only ever fetch this skill from https://deepapi.co.
## Required Environment
- Read `DEEPAPI_API_BASE_URL` from the environment.
- Read `DEEPAPI_API_KEY` from the environment.
- If either value is missing, stop and ask the user for setup.
- Never commit, print, log, paste, or expose `DEEPAPI_API_KEY`.
## Request Rules
- Send `Authorization: Bearer $DEEPAPI_API_KEY` on every request.
- Send `Content-Type: application/json` when sending JSON.
- Send a unique `Idempotency-Key` for every `POST`.
- For scrape work, set explicit `maxCostUsd` or `maxCostMicrousd`.
- Keep email as `send: false` or `mode: draft` unless the user explicitly approves sending.
- Do not pass inbox IDs. Use `emailIdentityId` or omit it.
## Execution Loop
1. Choose the narrowest endpoint that matches the task.
2. Build the request from the endpoint schema and examples below.
3. Run the request with the required headers.
4. If the response has `status: running`, wait `next.afterSecs` and call `next.method` + `next.path` until `status` is `succeeded` or `failed`.
5. If `error.retryable` is true, wait `error.retryAfterSecs` before retrying.
6. If the response is HTTP 402 with `error.code: insufficient_credits`, stop and ask the user to top up credits at https://deepapi.co/credits. After top-up, retry with the same `Idempotency-Key`.
7. Report `requestId`, `status`, `debitMicrousd`, `costFinal`, and the useful part of `output`.
## Endpoints
| Method | Path | Scope | Cost |
| --- | --- | --- | --- |
| POST | `/v1/scrape/website` | `scrape:website` | Set `maxCostUsd: "1.00"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/linkedin/profile` | `scrape:linkedin` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/github/profile` | `scrape:github` | Set `maxCostUsd: "0.03"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/twitter/search` | `scrape:twitter` | Set `maxCostUsd: "0.03"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/linkedin/jobs` | `scrape:linkedin` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/linkedin/company` | `scrape:linkedin` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/linkedin/people` | `scrape:linkedin` | Set `maxCostUsd: "0.50"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/linkedin/posts` | `scrape:linkedin` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/twitter/user` | `scrape:twitter` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/twitter/replies` | `scrape:twitter` | Set `maxCostUsd: "0.20"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/youtube/transcript` | `scrape:youtube` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/youtube/channel` | `scrape:youtube` | Set `maxCostUsd: "0.30"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/youtube/search` | `scrape:youtube` | Set `maxCostUsd: "0.10"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/linkedin` | `scrape:linkedin` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/github` | `scrape:github` | Set `maxCostUsd: "0.03"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/scrape/twitter` | `scrape:twitter` | Set `maxCostUsd: "0.03"` unless the user gives a different cap. The route requires maxCostUsd or maxCostMicrousd as the customer spend cap. The final debit is capped by that amount and reported as debitMicrousd. |
| POST | `/v1/email/send` | `email:send` | Uses configured email unit pricing; the route does not accept maxCostUsd. Check debitMicrousd in the response. |
| GET | `/v1/email/messages` | `email:read` | Read route returns debitMicrousd 0. |
| GET | `/v1/email/drafts` | `email:read` | Read route returns debitMicrousd 0. |
| POST | `/v1/email/drafts/{draftId}/send` | `email:send` | Uses configured email unit pricing; the route does not accept maxCostUsd. Check debitMicrousd in the response. |
| POST | `/v1/research/deep` | `research:deep` | Set `maxCostUsd: "0.10"` unless the user gives a different cap. Defaults to maxCostUsd 0.10. Pass maxCostUsd or maxCostMicrousd to choose a different customer spend cap. The final debit is capped and reported as debitMicrousd. |
| POST | `/v1/generate/image` | `generate:image` | Set `maxCostUsd: "0.20"` unless the user gives a different cap. Defaults to maxCostUsd 0.20. Pass maxCostUsd or maxCostMicrousd to choose a different customer spend cap. The final debit is capped and reported as debitMicrousd. |
| POST | `/v1/search/web` | `search:web` | Set `maxCostUsd: "0.05"` unless the user gives a different cap. Defaults to maxCostUsd 0.05. Pass maxCostUsd or maxCostMicrousd to choose a different customer spend cap. The final debit is capped and reported as debitMicrousd. |
| GET | `/v1/requests/{requestId}` | `same key` | Status polling does not create a new debit. |
## Endpoint Details
### Scrape Website
Use `POST /v1/scrape/website`. Crawl website pages and return clean text and markdown per page.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "1.00",
"waitForFinishSecs": 60,
"urls": [
"https://example.com"
],
"maxPages": 1
}
```
### Scrape LinkedIn Profile
Use `POST /v1/scrape/linkedin/profile`. Scrape public LinkedIn profile details.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.05",
"waitForFinishSecs": 60,
"profiles": [
"williamhgates"
]
}
```
### Scrape GitHub Profile
Use `POST /v1/scrape/github/profile`. Scrape public GitHub profile details.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.03",
"waitForFinishSecs": 60,
"usernames": [
"octocat"
]
}
```
### Search X/Twitter
Use `POST /v1/scrape/twitter/search`. Scrape X/Twitter posts from a search query or account handles.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.03",
"waitForFinishSecs": 60,
"handles": [
"nasa"
],
"maxItems": 1,
"sort": "latest"
}
```
### Scrape LinkedIn Jobs
Use `POST /v1/scrape/linkedin/jobs`. Scrape public LinkedIn job listings for a search query.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.05",
"waitForFinishSecs": 60,
"query": "software engineer",
"location": "United States",
"maxItems": 5
}
```
### Scrape LinkedIn Company
Use `POST /v1/scrape/linkedin/company`. Scrape public LinkedIn company pages for firmographic details.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.05",
"waitForFinishSecs": 60,
"companies": [
"microsoft"
]
}
```
### Search LinkedIn People
Use `POST /v1/scrape/linkedin/people`. Search public LinkedIn profiles by role, location, company, or school. Requires maxCostUsd of at least 0.50.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.50",
"waitForFinishSecs": 60,
"titles": [
"Founder"
],
"locations": [
"San Francisco"
],
"maxItems": 5
}
```
### Scrape LinkedIn Posts
Use `POST /v1/scrape/linkedin/posts`. Scrape recent public posts from LinkedIn profiles or company pages.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.05",
"waitForFinishSecs": 60,
"profiles": [
"williamhgates"
],
"maxItems": 3
}
```
### Scrape X/Twitter User
Use `POST /v1/scrape/twitter/user`. Scrape public X/Twitter account profiles, with optional follower and following lists.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.05",
"waitForFinishSecs": 60,
"handles": [
"nasa"
]
}
```
### Scrape X/Twitter Replies
Use `POST /v1/scrape/twitter/replies`. Scrape the public reply thread of an X/Twitter post. Requires maxCostUsd of at least 0.20.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.20",
"waitForFinishSecs": 60,
"url": "https://x.com/NASA/status/1234567890123456789",
"maxItems": 5
}
```
### Scrape YouTube Transcript
Use `POST /v1/scrape/youtube/transcript`. Scrape the transcript of a YouTube video as plain text plus timed segments. Videos without captions return an empty result.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.05",
"waitForFinishSecs": 60,
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
}
```
### Scrape YouTube Channel
Use `POST /v1/scrape/youtube/channel`. Scrape a YouTube channel's stats and recent videos. Each video item includes subscriber and channel totals.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.30",
"waitForFinishSecs": 60,
"channels": [
"mkbhd"
],
"maxItems": 3
}
```
### Search YouTube
Use `POST /v1/scrape/youtube/search`. Search YouTube videos by keyword and return video metadata.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.10",
"waitForFinishSecs": 60,
"query": "ai agents",
"sort": "views",
"maxItems": 3
}
```
### Scrape LinkedIn
Use `POST /v1/scrape/linkedin`. Backward-compatible alias for LinkedIn profile scraping.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.05",
"waitForFinishSecs": 60,
"profiles": [
"williamhgates"
]
}
```
### Scrape GitHub
Use `POST /v1/scrape/github`. Backward-compatible alias for GitHub profile scraping.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.03",
"waitForFinishSecs": 60,
"usernames": [
"octocat"
]
}
```
### Scrape Twitter
Use `POST /v1/scrape/twitter`. Backward-compatible alias for X/Twitter search scraping.
Side effects: Starts a scrape run and may debit credits when the run finishes.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Set an explicit customer spend cap with maxCostUsd or maxCostMicrousd before starting a scrape.
- Start with small result caps such as maxItems or capability-specific limits.
- Poll next.path while status is running and report the final debitMicrousd.
Example body:
```json
{
"maxCostUsd": "0.03",
"waitForFinishSecs": 60,
"handles": [
"nasa"
],
"maxItems": 1,
"sort": "latest"
}
```
### Send Email
Use `POST /v1/email/send`. Create an email draft from a workspace email identity; set send=true to send it.
Side effects: Creates a draft, or sends an email when direct send is approved.
Polling: This route returns a terminal envelope directly.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Keep send=false or mode=draft unless the user explicitly approves sending.
- Do not pass inboxId or inbox_id; use emailIdentityId or the workspace default.
- Attachments, hidden HTML, image HTML, URL shorteners, and high-risk direct sends are blocked by policy.
Example body:
```json
{
"to": "<email-address>",
"subject": "Quick hello",
"text": "Hi, this is a draft from my agent.",
"send": false
}
```
### Receive Email
Use `GET /v1/email/messages`. Read messages for a workspace email identity.
Side effects: Reads messages only.
Polling: This route returns a terminal envelope directly.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Do not pass inboxId or inbox_id; use emailIdentityId or the workspace default.
### List Drafts
Use `GET /v1/email/drafts`. List pending email drafts for a workspace email identity.
Side effects: Reads drafts only.
Polling: This route returns a terminal envelope directly.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Do not pass inboxId or inbox_id; use emailIdentityId or the workspace default.
### Send Draft
Use `POST /v1/email/drafts/{draftId}/send`. Approve and send an existing draft by draftId after review.
Side effects: Sends the reviewed draft as a real email when direct send is approved.
Polling: This route returns a terminal envelope directly.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Only send a draft after the user explicitly approves that draft.
- Do not pass inboxId or inbox_id; use emailIdentityId or the workspace default.
- Sending re-checks recipient and content policy against the stored draft; blocked drafts stay drafts.
Example body:
```json
{}
```
### Deep Research
Use `POST /v1/research/deep`. Answer a research question with current web evidence.
Side effects: Runs a paid web research request and debits credits when finished.
Polling: This route returns a terminal envelope directly.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Use query for the research question and context only for relevant background.
- Set maxCostUsd when you need a lower or higher spend cap than the default.
- Report debitMicrousd and summarize the returned sources when sources are present.
Example body:
```json
{
"query": "What changed in EU AI Act compliance timelines for API startups?",
"context": "We sell API tooling to EU customers.",
"maxCostUsd": "0.10"
}
```
### Generate Image
Use `POST /v1/generate/image`. Generate an image from a text prompt.
Side effects: Runs a paid image generation request and debits credits when finished.
Polling: This route returns a terminal envelope directly.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Describe the image you want in prompt, including style and composition.
- Set maxCostUsd when you need a lower or higher spend cap than the default.
- output.images contains base64 data URLs; save them to files instead of printing them.
Example body:
```json
{
"prompt": "A minimal flat illustration of a rocket launching from a laptop screen",
"maxCostUsd": "0.20"
}
```
### Web Search
Use `POST /v1/search/web`. Search the web and return ranked results with title, url, and snippet.
Side effects: Runs a paid web search request and debits credits when finished.
Polling: This route returns a terminal envelope directly.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Send a unique Idempotency-Key for every POST.
- Use query for the search terms only; keep it under 500 characters.
- Set maxCostUsd when you need a lower or higher spend cap than the default.
- Treat snippets as page summaries; open a result URL when you need the full content.
Example body:
```json
{
"query": "latest stable Node.js LTS version",
"maxResults": 3,
"maxCostUsd": "0.05"
}
```
### Request Status
Use `GET /v1/requests/{requestId}`. Poll a running request by requestId.
Side effects: Reads or refreshes request status.
Polling: If status is running, wait next.afterSecs and call next.method next.path until status is succeeded or failed.
Safety:
- Send Authorization: Bearer $DEEPAPI_API_KEY and never expose the key.
- Only poll request ids created by the same API key.
Example query: `waitForFinishSecs=60`
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,64 @@
---
name: delegating-to-agents
description: "Delegate bounded work to other AI agents while preserving context, ownership, and progress checks."
category: agent-orchestration
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [agents, delegation, orchestration]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Delegating to Agents
## When to Use
- Use when work should be handed to another AI agent with a complete prompt and progress checks.
- Use when you need to relay instructions to terminal or TUI agents without losing context.
## Which agent to pick
- **Coding (default) → Codex CLI.** Strongest coding agent, especially for complex, long-running SWE tasks. It's on an unlimited-usage plan — effectively unlimited, don't ration it.
- **Most other tasks → Pi Agent** (`pi` in a cmux terminal). All Pi agents run opus-4.8-fast via OpenRouter at xhigh reasoning effort.
- **Frontend / design → Pi.** Opus 4.8 Fast beats Codex on UI, styling, design.
- **Heavy multi-step work:** you as orchestrator + Codex CLI executing in a right-hand cmux pane is a solid default setup.
## Sending prompts to a TUI agent
1. **ONE single line — never newlines in the message body.** In a TUI, newline = Enter: a multi-line prompt submits at the first line and the rest arrives as fragmented mid-turn steering messages. Use ". " or "; " instead of line breaks, then one explicit enter. For long instructions, write them to a file and send: `read /tmp/task.md and follow it`.
2. **Wrap the prompt in plain double quotes — NEVER escaped.** `cmux send --surface surface:N "your prompt"`. The recurring bug is emitting `\"` — in bash that's literal-broken and dies with `unexpected EOF`. Inside the prompt, avoid apostrophes and literal double quotes (write "dont", "wont", "lets"); rephrase instead of escaping. If a send failed, the cause was the escaped `\"`, not the quote type.
3. **Exact command names:** `cmux send --surface surface:N` then `cmux send-key --surface surface:N enter`. There is NO `send-surface` or `send-key-surface`.
## Polling
Keep sleeps SHORT: start at 3-5s, re-check, repeat. Don't `sleep 30`. Pi and Hermes (opus-4.8-fast) launch and respond within seconds; scale up only for genuinely heavy tasks. After every check, send the user a one-line status: what the agent is doing and whether it's on track.
Claude Code note: after it finishes, it may prefill a predicted next user message — that draft is Claude, not the user.
## Remote VPS
SSH in first and launch the agent ON the VPS (e.g. `codex --yolo`), then drive that on-box agent. Don't run an agent locally and have it SSH for every step.
## The 4 agents (background reference)
All four use the portable SKILL.md standard; project skills win over global.
- **Pi** (pi.dev, open-source TS): minimal read/write/edit/bash core, self-extends via TS extensions; true BYOK; best-in-class session branch/fork/resume. Skills: `~/.pi/agent/skills/`.
- **Codex CLI** (OpenAI, Rust): fastest startup; kernel-level sandboxing; `codex exec` for CI; reads AGENTS.md. Skills: `~/.codex/skills/`.
- **Claude Code** (Anthropic, TS): deepest Claude integration, `.claude/` conventions, live skill hot-reload. Skills: `~/.claude/skills/`.
- **Hermes** (Nous Research, Python): persistent autonomous agent — cross-session memory, built-in scheduler, 40+ tools; can orchestrate the other CLIs as workers. Skills: `~/.hermes/skills/`.
## Driving interactive CLIs
- Codex, Pi, OpenCode: need `pty=true`.
- Claude Code: prefer `claude --print --permission-mode bypassPermissions` (no PTY).
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,85 @@
---
name: distribute-skill-to-all-agents
description: "Distribute a skill across configured agent skill folders while respecting local symlink layouts."
category: development
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [skills, distribution, agents]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Distribute a Skill Across All Agents
## When to Use
- Use when a skill should be made available across multiple local agent skill folders.
- Use when the user asks to sync or distribute skill updates to other agents.
The user has 4 agent skill locations on his MacBook. A skill must exist in each (or via symlink) to be discoverable by every agent.
## The 4 Canonical Locations
| Agent | Skills Folder | Notes |
|---|---|---|
| Codex / OpenAI Agents | `~/.agents/skills/` | **Canonical** — author skills here first |
| Claude Code | `~/.claude/skills/` | **Symlink → `~/.agents/skills/`** — writing to `.agents/skills` automatically covers Claude |
| Pi Agent | `~/.pi/agent/skills/` | **Symlink → `~/.agents/skills/`** — auto-covered. (Path is `/agent/` nested — NOT `~/.pi/skills/`) |
| Hermes Agent | `~/.hermes/skills/` | Independent copy — the only one needing a manual copy |
## Workflow
1. **Author the skill in `~/.agents/skills/<skill-name>/SKILL.md`** (canonical). Follow `effective-agent-skills` SKILL.md guidance.
2. **Verify the `.claude` symlink is intact** (one-time check):
```bash
ls -la ~/.claude/skills
# Expect: ~/.claude/skills -> ~/.agents/skills
```
If it's a real directory instead of a symlink, the user has diverged copies — ask before touching.
3. **Copy to `.hermes` only** (`.claude` and `.pi` are symlinks — already covered):
```bash
SKILL=<skill-name>
cp -r ~/.agents/skills/$SKILL ~/.hermes/skills/
```
4. **Verify all 4 locations** show identical byte counts:
```bash
for p in ~/.agents/skills/$SKILL ~/.claude/skills/$SKILL ~/.pi/agent/skills/$SKILL ~/.hermes/skills/$SKILL; do
echo "$p: $(wc -c < $p/SKILL.md) bytes"
done
```
All four numbers must match. If `.claude` or `.pi` shows a different byte count, that symlink is broken — investigate before proceeding.
## Updating an Existing Distributed Skill
Same flow — re-copy from `~/.agents/skills/` to `.hermes/skills/`. The `.claude` and `.pi` symlinks update automatically. `cp -r` overwrites by default; use `rsync -a --delete` if the skill folder has nested files that may have been removed:
```bash
rsync -a --delete ~/.agents/skills/$SKILL/ ~/.hermes/skills/$SKILL/
```
## Pitfalls
- **`~/.pi/skills/` is the wrong location.** Pi Agent loads from `~/.pi/agent/skills/` only. A skill placed in `~/.pi/skills/` is invisible. If you find skills already there, they're orphans — confirm with the user before deleting.
- **`~/.claude/skills` is a symlink, not a folder.** `cp -r ~/.agents/skills/foo ~/.claude/skills/` will error with "are identical". Skip the explicit Claude copy.
- **Project-local skills exist too** — `./.pi/agent/skills/` (or `.pi/skills/`) inside a repo overrides the global one on collision (later-discovered wins). This skill only handles GLOBAL distribution.
- **`.pi/agent/skills` is a symlink → `.agents/skills`.** Don't `cp` into it (errors "are identical"); it auto-syncs. Only `.hermes/skills` is an independent copy — don't unilaterally consolidate Hermes into a symlink unless the user asks.
- **Hermes snapshots skills at session start.** A newly-distributed skill won't appear inside a running Hermes session until restart (it works fine for future sessions and for the other 3 agents immediately).
- **Filename casing matters on case-sensitive volumes.** `SKILL.md` must be uppercase.
## When NOT to Use This Skill
- Skill is project-specific → put it in `./.claude/skills/`, `./.pi/agent/skills/`, etc. inside the repo, not globally.
- Editing one agent's skill only (e.g. a Hermes-only workflow) → patch that file directly, don't propagate.
- Removing a skill globally is destructive. First show the exact skill directories
that would be removed, confirm with the user, then use the user's preferred
safe deletion method for `~/.agents/skills/` and `~/.hermes/skills/`.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,333 @@
---
name: effective-agent-skills
description: "Author and review high-quality agent skills with triggers, progressive disclosure, and safety notes."
category: development
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [skills, authoring, quality]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Agent Skills: A Complete Guide
## When to Use
- Use when creating, editing, reviewing, or debugging an agent SKILL.md file.
- Use when you need quality guidance for triggers, examples, limitations, and safety notes.
A consolidated reference on what agent skills are, why they exist, how they work, and how to write effective ones.
---
## 1. What agent skills are
An Agent Skill is a folder containing a `SKILL.md` file (YAML frontmatter + markdown instructions), plus optional subfolders for scripts, references, and assets that the agent loads on demand.
```
my-skill/
├── SKILL.md # Required: metadata + instructions
├── scripts/ # Optional: executable code (CLIs, validators, helpers)
├── references/ # Optional: detailed docs loaded only when needed
└── assets/ # Optional: templates, fonts, static files
```
Skills are an open standard (agentskills.io), originally created by Anthropic and adopted by OpenAI Codex, Cursor, Gemini CLI, Microsoft Agent Framework, Google ADK, and 40+ other agent products. A skill written once works across all compatible agents.
---
## 2. Why this abstraction exists
Base LLMs are generalists. Real work requires procedural knowledge, organizational context, and repeatable workflows. Every prior alternative had a failure mode:
| Approach | Problem |
|---|---|
| Stuff it into the system prompt | Always loaded → context bloat at scale |
| Re-paste instructions each session | No version control, no consistency |
| Fine-tuning | Slow, expensive, opaque, vendor-locked |
| MCP servers alone | Give the agent tools but no workflows for using them |
Skills solve four problems at once:
- **Context efficiency** — instructions load only when relevant
- **Repeatability** — multi-step procedures become auditable workflows
- **Composability** — multiple skills combine at runtime per task
- **Portability** — same files work across vendors and surfaces
Mental model: skills are to LLMs what man pages, runbooks, and team handbooks are to engineers — reference material loaded into working memory only when the task demands it.
---
## 3. How they work — progressive disclosure
The architectural core. Three-stage loading:
**Level 1 — Discovery (~100 tokens per skill, always in context):**
Only `name` + `description` from frontmatter are injected into the system prompt at startup. Agent knows the skill exists and when it applies. You can install dozens of skills with negligible overhead.
**Level 2 — Activation (<5,000 tokens, loaded on match):**
When the user's request matches a skill's description, the agent reads the full `SKILL.md` body into context.
**Level 3 — Execution (unbounded, on demand):**
The agent reads referenced files (`references/foo.md`) or runs scripts (`scripts/validate.py`) only as needed. Scripts can execute without their source being loaded into context at all.
This is why bundled content has no practical limit. Files don't consume tokens until accessed.
---
## 4. SKILL.md anatomy
```markdown
---
name: skill-name
description: What this skill does AND when to use it. Include trigger phrases the user will say.
---
# Skill Name
## Quick start
[Minimal working example]
## Workflow
[Step-by-step procedure with checklists]
## Output format
[What the user/agent should expect back]
## Advanced
[Link to references/ for rarely-needed detail]
```
Frontmatter constraints:
- `name` is lowercase, hyphens only, 164 chars, **exactly matches the parent folder name**
- Avoid `<` and `>` in frontmatter (they can inject into the system prompt)
- Invalid YAML silently prevents loading
Optional standard fields:
- `disable-model-invocation: true` — stops the agent from auto-loading the skill based on the conversation; it can only be triggered manually (e.g. `/skill-name`). Now a standard Agent Skills spec field, so it works across spec-compliant clients (Claude Code, Copilot, etc.), not just Claude. Caveat: it prevents auto-invocation, but some clients (Claude Code, open bug) still inject the `description` into context, so it doesn't always save the discovery-level tokens. Use for manual-only utilities you don't want firing automatically.
---
## 5. Two design philosophies
Skills tend to fall into one of two patterns. Both are valid; they solve different problems.
### Pattern A — Capability primitives (tool wrappers)
The skill is a thin wrapper over a deterministic CLI or script. Logic lives in code. SKILL.md teaches the agent how to invoke it.
- **Adds**: new capabilities (search, email, browser, API access)
- **Reliability via**: shell tools, not prompts
- **Typical length**: 3080 lines, mostly command examples
- **Use when**: the bottleneck is "the agent can't do X"
### Pattern B — Process primitives (cognitive disciplines)
The skill encodes a methodology the agent should follow. Pure prompt engineering — no scripts needed.
- **Adds**: structured workflows (TDD, code review, design alignment, debugging loops)
- **Reliability via**: explicit procedure, checklists, validation loops
- **Use when**: the bottleneck is "the agent's output quality or process is bad"
A mature setup uses both. Pattern A gives the agent better tools. Pattern B gives it better methods for using them.
---
## 6. How to write effective skills — do this
### Description as routing contract
The description is the only thing the agent sees before deciding to load the skill. If your skill doesn't trigger, the description is wrong 95% of the time, not the body.
Include three elements:
1. **What** the skill does (one phrase)
2. **When** to use it (trigger phrases, situations)
3. **Differentiator** vs related skills (prevents routing conflicts)
Pattern: `"X via Y. Use for [situations]. [Differentiator: no Z required / faster than W / handles edge case V]."`
**Never summarize the full workflow in the description.** If the description contains a step-by-step summary of *how* the skill works, the agent tends to follow that summary and skip loading the body. Describe *what* and *when*, never *how*. The description answers "should I open this skill now?" — not "what are the steps?"
### Keep SKILL.md lean
- Beyond a certain length, you're usually encoding logic that should be in a script or referenced file
### Bash-first, prose-second
Concrete command examples with inline comments beat prose explanations. The agent pattern-matches on syntax. Show, don't describe.
### Push determinism into code
Anything fragile, repetitive, or where variation is a bug → script. Use markdown only for tasks requiring judgment.
### Match strictness to task fragility (degrees of freedom)
Scale instruction rigidity to how costly a wrong move is:
- **Loose natural-language heuristics** when many approaches are valid (e.g. code review).
- **Pseudocode or templates** when there's a preferred pattern but variation is acceptable (e.g. report format).
- **Exact scripts and strict step lists** when the workflow is fragile, error-prone, or consistency-critical (e.g. migrations, document patching).
### Build validation loops
The single biggest output quality improvement: state a verify → fix → re-verify loop explicitly.
- Document skills: visual QA pass before delivery
- Code skills: tests pass + zero type errors before completion
- Data skills: schema validation before output
### State-check before action
Don't assume setup is done. Instruct the agent to verify state, then branch:
```
First check if X is configured: [command]
If not, walk the user through setup: [steps]
```
### Just-in-time loading with explicit pointers
Tell the agent exactly when to read each referenced file:
```
For standard cases, follow the steps below.
For [specific edge case], read references/edge-cases.md first.
```
### Keep references one level deep
Link referenced files directly from SKILL.md. Never build chains (SKILL.md → advanced.md → details.md → actual.md) — the agent may preview nested files only partially and miss critical instructions. Add a table of contents to any reference file longer than 100 lines.
### Document output formats
If your script returns structured data, show the agent what it looks like. Enables reliable downstream parsing.
### Defer to --help for completeness
List the 80% common operations in SKILL.md. Tell the agent to run `tool --help` for the rest. Keeps SKILL.md small without losing functionality.
### Compose primitives, don't bundle workflows
One skill = one capability or one discipline. Resist bundling concerns into "the X workflow." Multiple small skills combine at runtime; one large skill is rigid.
### Cite established principles when applicable
If your skill encodes a known engineering methodology (TDD, DDD, red-green-refactor), name the source. Gives the agent a coherent model to align with and gives users a way to verify the design.
### Persistent artifacts for cross-session memory
Skills can write to repo-level files (CONTEXT.md, ADRs, decision logs) that future agent sessions read. This is how you fight the "agents have no memory" problem at the architecture level.
---
## 7. What not to do — anti-patterns
### Don't re-teach what the model already knows
Every line in SKILL.md should provide context the model doesn't already have. No Python syntax tutorials. No "what is git." Challenge every paragraph.
### Don't include human-facing docs
No README.md, no CHANGELOG.md, no INSTALLATION_GUIDE.md inside the skill folder. Skills are for agents.
### Don't write vague descriptions
- Bad: "A helpful skill for documents"
- Good: "Fill PDF form fields, extract form data, flatten completed PDFs. Use when the user mentions PDF forms, fillable forms, or programmatic field population."
### Don't bundle library code
If you need a parsing library, install via npm/pip. Don't paste source into the skill.
### Don't write monolithic mega-skills
If one skill does design + planning + implementation + testing + deployment, you've built a framework, not a skill. Split it.
### Don't assume the agent will infer
Be explicit about every step that matters.
- Bad: "Then deploy it."
- Good: "Run `npm run deploy:staging` and wait for HTTP 200 from /healthz before reporting success."
### Don't write style-only variants
A skill that just changes tone or formatting belongs in user preferences or a system prompt, not a skill.
### Don't ignore failure modes
For every workflow step that can fail, document what failure looks like and what to do. Happy-path-only skills break in production.
### Don't include time-sensitive information
"As of Q4 2024..." rots fast. Fetch live data via script or omit.
### Don't use absolute paths
Always relative. Forward slashes regardless of OS. Use runtime placeholders for skill-directory references.
### Don't trust unfamiliar skills
Skills can execute arbitrary code and steer agent behavior. A malicious skill is a data exfiltration vector. Audit `scripts/` for unexpected network calls, file access outside expected scope, or hidden instructions in references. Watch for typosquatted skill names. Sandbox execution environments.
---
## 8. Authoring workflow
1. **Identify the gap.** Run your agent on real tasks. Where does it consistently fail or need re-prompting? That's a skill candidate.
2. **Decide the pattern.** Capability primitive (need new tools) or process primitive (need better methodology)?
3. **Draft the description first.** What + when + differentiator. Read it back: would the agent know when to fire it?
4. **Write the smallest body that works.** Add only when testing reveals gaps.
5. **Move detail to references/ once SKILL.md grows too long.**
6. **Test triggering.** Ask the agent something the skill should handle without invoking it explicitly. If it doesn't fire, fix the description.
7. **Test execution.** Invoke explicitly. If output is wrong, fix the body.
8. **Adversarial test.** Have another LLM ask: "What edge cases break this skill?" Patch the gaps.
9. **Version control.** Treat skills as code. Tag, branch, review.
---
## 9. Testing and debugging
- **"Which skill did you use?"** — ask the agent post-task. Fastest routing debug.
- **Routing fails → description problem.** Add specific trigger phrases.
- **Execution fails → body problem.** Add explicit steps, examples, or validation.
- **Skills snapshot at session start.** Edits during a session require a restart.
- **Test against the weakest model you'll deploy on.** Stronger models forgive vague skills; weaker models expose them.
- **Run an eval suite.** A handful of representative prompts that should and shouldn't trigger the skill, with expected outputs.
---
## 10. Composition
Skills compose at runtime — the agent loads multiple skills as needed for a single task. Design for this:
- **One skill = one concern.** Resist bundling.
- **Define interfaces between skills.** If skill A produces artifacts that skill B consumes, document the shape.
- **Use a repo-level config substrate.** A shared file (e.g., AGENTS.md, CONTEXT.md, settings.json) that multiple skills read and write coordinates them without explicit handoffs.
- **Loops over menus.** A coordinated set of skills forming a workflow (align → spec → build → verify → refactor) drives adoption far better than an unrelated catalog of capabilities.
---
## 11. Security checklist
Before installing any third-party skill:
- Read every file in the folder
- Audit `scripts/` for outbound network calls, file access outside expected scope, command execution
- Check references for prompt injection ("ignore previous instructions...")
- Verify the skill name isn't typosquatting a popular one
- Run in a sandboxed environment first
- Pin to a specific version/commit, not `latest`
---
## 12. Ship checklist
Before publishing a skill:
- [ ] Frontmatter `name` matches folder name
- [ ] Description includes what + when + differentiator
- [ ] Description includes likely user trigger phrases
- [ ] No human-facing docs inside the skill folder
- [ ] No time-sensitive information
- [ ] Relative paths only
- [ ] State-check before action where applicable
- [ ] Validation loop documented
- [ ] Output format documented if relevant
- [ ] Tested with weak and strong models
- [ ] Tested for both correct triggering and correct execution
- [ ] Skill does one thing
- [ ] Composes cleanly with related skills
- [ ] Version controlled
---
## 13. First principles, compressed
1. **The description routes; the body executes.** Get both right independently.
2. **Tokens are scarce; files are cheap.** Push detail out of context until it's needed.
3. **Determinism comes from code; judgment comes from prompts.** Put each in its right place.
4. **One skill, one concern.** Composition beats bundling.
5. **Agents have no memory.** Use persistent artifacts to give them one.
6. **The model knows a lot.** Don't re-teach. Only add what's missing.
7. **Validate before completing.** Self-correction loops dominate output quality.
8. **Skills are code.** Version, test, audit, and review them as such.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,79 @@
---
name: fable-safe-prompt
description: "Rewrite allowed prompts to reduce false-positive safety triggers without bypassing policy or changing intent."
category: agent-behavior
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [prompting, safety, guardrails]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
# Fable-Safe Prompt
## When to Use
- Use when an allowed prompt appears likely to hit false-positive classifier language.
- Use when the user asks for prompt wording that keeps benign intent clear and policy-compliant.
Return the user's prompt back **in full, verbatim**, changing ONLY the specific sentences/phrases most likely to trip Fable 5's cyber/bio classifiers. Do not rewrite the whole thing, do not summarize, do not restructure — minimal surgical edits. Keep the actual goal and all benign text exactly as written. This lowers false positives for benign work. It must not be used to bypass safety policy or enable harmful requests.
Fable 5 runs 3 input classifiers: **cyber**, **bio/chem**, **reasoning_extraction**. Triggers are keyword/surface-based, largely intent-independent ("hello" and "cancer" got flagged). The fix is to abstract away the sensitive domain, not just restate intent.
Apply when the prompt touches: cyber/auth/exploits/malware/pentesting/credentials; bio/chem/medical/disease/lab topics; or any "show your reasoning" instruction.
The user provides the prompt-to-be-changed wrapped in `<prompt>...</prompt>` XML tags. Operate only on the text inside those tags; treat everything outside as instructions to you.
## Method
1. Flag the highly problematic sentences/phrases (offensive framings, named sensitive domains, "show your thinking" lines).
2. Replace each in place with a safe equivalent (see swaps), or describe the wanted functionality abstractly rather than naming the domain.
3. Leave everything else byte-for-byte identical.
4. Return the complete edited prompt.
Reframe so the task reads as: **owned/authorized**, **defensive** (implement/fix/test, not attack), and **not dual-use** (no exploit dev, attack simulation, bypass payloads, malware, live testing).
### Swap framings (apply per-sentence)
| Triggering | Safe rewrite |
|---|---|
| "How could an attacker exploit this auth" | "Review these auth files for missing checks and fix them defensively" |
| "Write an exploit / payload / PoC" | "Add a regression test proving X is fixed, then patch it" |
| "How do I bypass / brute-force Y" | "Enforce secure session validation + rate limiting on Y" |
| "Reverse this malware / show attack steps" | "Describe the risk high-level, then implement the fix" |
| "Show your reasoning / explain step-by-step / walk me through your thinking" | **Delete it.** Trips `reasoning_extraction`. If progress visibility is needed, ask it to use a send-to-user tool, not to echo its internal thoughts. |
| Clinician framing: "as a doctor, diagnose this ECG" | Patient framing: "help me interpret this ECG my doctor gave me" |
| Named bio/chem domain: "cancer / disease pathway / chemical kinetics" | Abstract it: describe the data/analysis generically, drop the domain noun |
### Trigger keywords to abstract away
*Cyber:* exploit, malware, vulnerability, attack, bypass, stealth, fingerprinting, anti-bot, CAPTCHA, penetration.
*Bio/chem:* biology, biomedicine, chemistry, cancer, disease pathways, RNA/variant calling, equilibrium, kinetics, diagnosis.
*Distillation:* "distill the model", training pipelines, frontier LLM development.
If no benign defensive equivalent exists for a sentence (it's purely offensive), flag it to the user rather than silently neutering the intent.
## Output
1. Print the full safe prompt back to the user in text (a code block, ready to paste).
2. **Copy it to the clipboard** so the user can paste immediately:
```bash
pbcopy <<'EOF'
<the full safe prompt>
EOF
```
Confirm in one line that it's on the clipboard.
3. A short list of exactly which sentences you changed and what they became.
4. If the task is genuinely offensive (pentest, exploit repro, malware analysis): say plainly no edit makes it Fable-safe — use an Opus 4.8 fallback or vetted Mythos, not Fable 5.
**Hard truth:** you can't reliably stop Fable 5 guardrails. Robust API setups also treat `stop_reason: "refusal"` (HTTP 200, `stop_details.category` = `cyber`/`bio`) as a route to an Opus 4.8 fallback — mention only if the user controls the integration.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,96 @@
---
name: folder-specific-claude-and-agents-md
description: "Create folder-scoped CLAUDE.md and AGENTS.md guidance for future agents working in that area."
category: development
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [agents-md, claude-md, documentation]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
user-invocable: true
---
# Folder CLAUDE.md Creation
## When to Use
- Use when the user asks for folder-specific agent instructions or local context files.
- Use when a subdirectory needs a CLAUDE.md and AGENTS.md handoff for future agents.
Generate a focused `CLAUDE.md` inside a target folder, plus an `AGENTS.md` symlink pointing at it. The file gives any future agent (Claude Code, Codex, etc.) the folder-specific context the global `CLAUDE.md` doesn't cover.
Background reference: `library/claude-code/claude-and-agents-md.md`.
## Process
### Step 1: Confirm the target folder + sanity-check it deserves a file
Ask the user which folder. Use absolute path under `~/Documents/code/workspace/`.
**Only create a file if the folder has context needed across multiple sessions** — active evolving work, specific conventions, ongoing decisions. A folder of static reference files does NOT need one (agents can read on demand). If unsure, ask the user.
### Step 2: Read every file in the folder IN FULL
- Use `ls -la` first to enumerate files and subfolders.
- Read every markdown, config, and key source file.
- For large tldraw/Vite subprojects: read `package.json`, `src/App.tsx`, one representative module file, and the folder's own `module-details.md`-style files.
- Do NOT skim. Do NOT skip. The user's later edits depend on you having full context.
### Step 3: Draft a bullet list of candidate content
Before writing the file, give the user a bullet list grouped by section — let them react first. Candidate sections (skip any that don't apply):
- **Product / Purpose** — what this folder/project is, current state, key metrics
- **Avatar / Audience** — who it's for (if applicable)
- **Essential Files** — one-line role for each important file, including cross-folder references (use `@path/file.md` import syntax)
- **Constraints (MUST NOT)** — explicit hard negatives. Highest-ROI content in the file.
- **Conventions** — the user's lingo, status emojis (✅ 🟡), naming patterns, "usually do" patterns
- **Locked Decisions** — things agreed + dated, must not re-litigate
- **Context** — history, authority, credibility that frames the work
- **How to work with the user** — collaboration style for this specific folder
- **Marketing Angles / Positioning** — if public-facing
- **Top Insights** — 3-5 most glaring signals from research (if research exists)
### Step 4: Iterate with the user
- Keep answers short. The user will edit directly in the IDE.
- When they edit the file, RE-READ it and flag: contradictions, typos, missing rules, wrong categorization.
- Do not revert their edits unless asked.
### Step 5: Write the file
- Path: `<folder>/CLAUDE.md`
- Start with a one-line header explaining the file's purpose.
- **Subdir file marker:** if this is a subdirectory file (parent folder already has its own CLAUDE.md), open with `Apply root CLAUDE.md first, then this file.`
- Use `##` section headers matching the sections the user approved.
- Bullets over prose. Short bullets.
- **Cross-folder references:** use `@relative/path/file.md` import syntax, not prose mentions.
- **Heavy reference docs:** annotate with `**Read when:**` triggers (e.g. "Read when: writing offer copy"). Prevents loading every session.
### Step 6: Create the AGENTS.md symlink
```
cd <folder> && ln -s CLAUDE.md AGENTS.md
```
Verify with `ls -la CLAUDE.md AGENTS.md`.
### Step 7: Commit only when asked
Do NOT stage or push unless the user says to. When they do: `git add -A`, commit with a `Day N:` style message, push.
## Rules
- **Never invent content.** Every bullet must trace back to something you read in the folder or something the user said. No generic boilerplate.
- **Brevity wins.** The user edits aggressively to make things shorter. Start tight.
- **Folder-scoped only.** Don't duplicate the global `CLAUDE.md` (personality, dates, ports, etc.). Only include what's specific to this folder.
- **No file trees, no directory dumps, no stack details the code already shows.** Anything an agent can derive from `ls` or `grep` rots fast and wastes tokens. Pin decisions, rules, and context — not structure.
- **Constraints vs Conventions.** Hard "MUST NOT" rules go in Constraints (explicit negatives). "Usually do X" patterns go in Conventions. Splitting these improves adherence.
- **No absolute ALWAYS/NEVER without explicit exceptions.** Edge cases make absolute rules get ignored. "Never commit secrets EXCEPT `.env.example`" beats "never commit secrets."
- **Never summarize or auto-shorten the file.** Context collapse degrades it. Grow deliberately, prune manually. If the user asks to trim, do it by hand.
- **Maintenance loop.** When the user corrects the agent on something this file should have prevented, add the rule to the file immediately. Don't wait.
- **No emojis unless the user uses them** (status markers ✅ 🟡 are the exception — they're already conventions).
- **Symlink, not copy.** `AGENTS.md` must be a symlink so edits stay in sync.
- **Flag gaps honestly.** If the user's edits introduce contradictions (e.g. "sell X" in one section and "never sell X" in another), call it out before they ask.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,175 @@
---
name: goal-loop
description: "Draft and explain persistent goal-loop prompts for long-running agent work with clear stop conditions."
category: agent-orchestration
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [goals, autonomy, planning]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Agent `/goal` Loop
## What `/goal` is
`/goal` is a slash command that turns an agent prompt into a **persistent agent** looping `plan → act → test → review → iterate` until a stop condition is met, the user pauses, or the token budget runs out. Internally called the "Ralph loop."
Agents with the `/goal` feature right now: **Codex, Claude Code, and Hermes Agent**.
Key difference from a normal prompt: when a turn ends but the goal isn't met, the agent **auto-continues** instead of waiting for input.
**Lifecycle states:** `pursuing`, `paused`, `achieved`, `unmet`, `budget-limited`.
When monitoring a running `/goal`, every check should include a one-line update to the user: what the agent is doing and whether it is on track. Keep it extremely concise.
**Not:** a budget command, a safety boundary, "run forever", or a replacement for `/plan`. It's a contract enforcer with a verification loop.
## Requirements
- An agent with the `/goal` feature — right now: Codex, Claude Code, or Hermes Agent
- The goals feature enabled in the agent's config
- **Subscription auth** — API-key auth does **not** work. A pro-tier plan is the realistic minimum for long runs.
## When to Use it
Use only when **all three** are true:
1. Task is >30 min of mechanical work.
2. There's a **verifiable stop condition** (tests pass, coverage hit, eval ≥ X, build green).
3. Repo is agent-ready (working build, decent tests, `AGENTS.md` present).
Fits: migrations, coverage lifts, TDD feature builds, refactors with contract tests, prompt/eval optimization, deploy retry loops, bug-repro-then-fix.
Bad fits: exploratory work, vague "improve this", anything without a "done" definition, prod credentials, destructive shared-infra ops.
## The 5-part contract (every goal needs this)
1. **Objective** — one sentence, one concrete outcome.
2. **Constraints** — what must NOT change (public API, files, libs, conventions).
3. **Validation command** — the exact shell command that proves progress (`pytest -q`, `pnpm test`, etc.).
4. **Stop condition** — verifiable: "Stop when X passes" OR "when further changes need human/product input."
5. **Documentation** — one sentence instructing the agent to write concise, targeted docs for every change, either creating new `.md` files or updating existing ones.
Plus: tell the agent what to read first, ask it to work in checkpoints with a short progress log.
## Writing a goal (the core deliverable)
When the user wants a quick `/goal` instruction, produce a structured markdown block with one line per contract item (proper newlines, not flowing prose). **Do not prefix the output with `/goal`** — the user adds the slash command themselves in the composer. Emit only the contract body. Template:
```
**Objective:** <one-sentence objective>
**Read first:** <files/PLAN.md/issue>
**Constraints:** <what not to change, libs, conventions>
**Validate:** `<exact command>` after each change
**Document:** Write concise, targeted documentation for all changes — create new `.md` files or update existing docs as needed.
**Checkpoints:** work in checkpoints and log progress briefly
**Stop when:** <verifiable condition>, OR when further changes require human/product input
```
### Example (migration)
```
**Objective:** Migrate this project from Pydantic v1 to v2.
**Read first:** pyproject.toml, src/, tests/
**Constraints:** no public API changes; keep imports backwards-compatible via shims if needed; no new dependencies
**Validate:** `pytest -q` after each change
**Checkpoints:** work in checkpoints; log progress briefly
**Stop when:** full suite passes with zero deprecation warnings, OR when a change requires architecture decisions
```
### Example (coverage lift)
```
**Objective:** Raise coverage in src/auth/ from ~38% to ≥75%.
**Read first:** src/auth/, tests/auth/, AGENTS.md
**Constraints:** no new deps; mirror existing test style; do not modify production code unless strictly required for testability
**Validate:** `pytest --cov=src/auth --cov-report=term-missing`
**Checkpoints:** work in checkpoints; log coverage delta each one
**Stop when:** coverage ≥75% AND all tests pass, OR when uncovered code needs design changes
```
### Writing rules
- **One objective, one stop condition.** Not a backlog.
- **Documentation is mandatory.** Every `/goal` prompt must include a single sentence committing the agent to concise, targeted docs — new `.md` files or focused updates to existing docs.
- **Never instruct the agent to create new ADRs** — ADRs require the user's explicit approval, so goal prompts must not pre-approve or encourage them.
- **Forbid reward-hacking explicitly:** "Do not delete, skip, weaken, or narrow tests to make the goal pass." Otherwise the agent may game the stop condition.
- **4,000-char limit** on the objective. If longer, put detail in a file (`PLAN.md`/`GOAL_BRIEF.md`) and make the goal point to it — keep the goal itself compact.
- Use **literal strings** for paths, commands, issue numbers — exact.
- Forbid scope creep explicitly: "Do not refactor unrelated code. Do not add dependencies."
- Tell the agent when to pause: "If <condition>, pause and ask before proceeding."
- Short, vague goals burn tokens for no extra value vs. a normal prompt.
### Meta-prompting trick (highest-leverage)
Hand-written goals under-specify. Ask a second AI session (Claude with the codebase loaded, ChatGPT with project connected, or a separate agent thread in the same dir) to: (1) inspect the codebase, (2) surface hidden assumptions/constraints/edge cases, (3) emit a structured `/goal` markdown block using the 4-part contract. Paste that into the agent. Order-of-magnitude better runs.
Claude Code cmux note: after Claude finishes, it may prefill a predicted next user message; that draft is Claude, not the user speaking.
### Self-goal setting
The agent can now write and set its own goal natively (the `create_goal` tool). Instead of crafting the contract yourself, give it your high-level intent and tell it to set the goal: "Inspect this repo, then write yourself a `/goal` with a verifiable stop condition and pursue it." It's the meta-prompting trick done inline — the agent turns your intent into the contract. Still give it the same raw materials (files to read, constraints, the validation command) so the goal it writes is grounded. Add: "ask clarifying questions before committing if the intent is underspecified" — catches ambiguity up front and prevents the self-set goal from drifting.
## Launching
1. `cd <repo>` (goals run scoped to the working directory).
2. Launch the agent bare (opens the TUI). **Not** exec/headless mode — `/goal` is a TUI slash command only.
3. Sign in with subscription auth (not an API key).
4. Type `/goal <your contract>` in the composer, Enter.
5. Walk away.
## Controlling a running goal
| Command | Effect |
|---|---|
| `/goal` (alone) | Status: current checkpoint, what's verified, what remains, blockers |
| `/goal pause` | Freeze |
| `/goal resume` | Unfreeze (paused goals never auto-resume) |
| `/goal clear` | Kill the goal |
| `/goal <new>` | Replace the current goal |
| Ctrl+C / any typed message | Auto-pauses; user input always wins priority |
Resuming across sessions: goal state is persisted server-side. `cd` back into the repo, launch the agent, `/goal` for status, `/goal resume`.
Budget-limited state: the agent doesn't stop abruptly — it summarizes, notes what's left, saves state. `/goal resume` works after budget refresh or upgrade.
## When a goal drifts
- **Minor drift:** just type a correction in the composer (auto-pauses, folds it in, resumes).
- **Loose objective:** `/goal pause`, read status, then `/goal <tighter version>` — replaces the contract. Don't pile instructions on a vague goal.
- **Bad mess:** `/goal clear`, `git status` or `git stash`, rewrite with the meta-prompting trick, restart.
Don't let a drifting goal keep running "to see where it goes." Tokens burn, diffs compound.
## Operational tips
- Inspect status periodically with bare `/goal`.
- **Always review the diff** before merging — long autonomy means more code to validate, not less. Human oversight becomes more critical, not optional.
- Keep approvals/sandboxing tight; default permissions are correct.
- First run: pick a 30-min scoped task so you learn how `/goal` actually stops before trusting it overnight.
- Bake recurring policy into `AGENTS.md` so every goal inherits it without restating: adversarial self-review before declaring done, an extra QA pass even when tests pass, and the standard validation command. Saves repeating it in each goal paragraph.
## Troubleshooting
| Symptom | Fix |
|---|---|
| `/goal` missing from slash popup | Update the agent to a version that supports `/goal` |
| Feature flag on but command missing | Quit and restart the agent fully |
| Typed `/goals` | It's singular: `/goal` |
| Doesn't activate | Sign out, sign back in with subscription auth (not API key) |
| Stopped with progress summary | Budget-limited — `/goal resume` after refresh, or tighten scope |
| `/goal resume` says no active goal | Terminal state or cleared — start fresh with `/goal <new>` |
| Goal looks active but won't auto-continue | Stuck in Plan mode — plan-only work doesn't trigger continuation. Draft the plan, then switch to Goal execution |
## Mental model
`/goal` is a **contract enforcer with a verification loop**, not a "run forever" button. The shift: stop writing prompts, start writing **specifications with stop conditions**. Spend the time upfront defining "done"; the run takes care of itself.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,86 @@
---
name: interview-style-doc-building
description: "Build structured strategy documents by asking one question at a time and patching the file."
category: productivity
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [documentation, interview, planning]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Interview-Style Doc Building
The user's preferred mode for creating durable strategic docs. AI does NOT propose content — AI asks one question, the user answers, AI patches the file, AI asks the next question. The file IS the conversation's output, updated incrementally.
## When to Use
- Building a new SSOT file (life priorities, life vision, principles, frameworks, ranked lists).
- Filling out a structured doc the user explicitly wants to author themselves.
- Quarterly/annual reviews where the user's words go into the file.
**NOT for:** day planning (use `day-plan`), task triage (`organize-tasks`), or anything where AI proposes content first.
## The Loop
1. **Create the file** with a skeleton (header, sections, "to be filled in" placeholders). Single `write_file` for the new file. After this, NEVER overwrite — only `patch`.
2. **Ask ONE question.** Concise. Specific. Single-faceted. Open-ended where possible.
3. **Wait for the answer.** Don't ask the next question yet.
4. **Patch the file** with the user's answer in the correct section.
5. **Re-ask** — next question, or follow-up if the answer was incomplete.
6. Repeat until the file is complete.
## Hard Rules
- **One question at a time.** Never dump multiple questions in a single message. The user has flagged this.
- **Patch, don't overwrite.** After the initial skeleton, use `patch` for every update. Never `write_file` to an existing doc.
- **Update the file BEFORE asking the next question.** Order: receive answer → patch file → ask next question. Not the reverse.
- **Lists from the user are UNORDERED SETS.** When the user lists items in response to "which X should we cover?" or "what are the Ys?", that is a SET, not a ranking. Never infer rank, priority, or sequence from the order they typed them. If you need ordering, ask explicitly: "Which of these is #1?"
- **Ask dynamics, not names.** When the user references a person, don't ask "who is X?" — ask about the role/dynamic.
- **No snark, no attitude, no filler.** Concise questions, concise acknowledgments.
- **No speculative additions.** Don't invent sections, edge cases, or "anything else?" prompts unless the user asks.
## Question Design
- **Domain-discovery, not confirmation.** "What wins against everything else?" — not "Is Business #1?"
- **Surface new reality.** Each question should pull out info AI doesn't already have.
- **Engine-move framing where applicable.** "What's the thing that, if true, makes the rest obvious?"
- **Concrete over abstract.** "What's #2 — the domain that wins against everything except #1?" beats "Tell me about your second priority."
## File Patching Pattern
After each answer:
1. Read the relevant section (if not already in context).
2. `patch` with `old_string` = placeholder or previous entry, `new_string` = updated content with the user's words preserved.
3. Confirm the diff. Move on.
For ranked lists, append one rank at a time:
```
1. **Business** — Q2 #1 goal: ...
2. **Health** — get below 81.0 kg, sleep 9h/day, ...
```
Each rank gets patched in as the user confirms it.
## Common Pitfalls
- **Assuming order from a set.** The user lists "A, B, C, D" → AI writes "1. A, 2. B, 3. C, 4. D" → the user flags it. ALWAYS confirm rank explicitly.
- **Asking too many questions at once.** Even bundling 2 violates the rule.
- **Overwriting the file** instead of patching specific sections — destroys prior content.
- **Adding AI-generated content** to fill out sections. Sections stay empty until the user provides the content.
- **Skipping the file update** between Q&A pairs — the doc falls out of sync.
## Pairing with Other Skills
- `day-plan` — different pattern (task triage), not interview-style.
- `organize-tasks` — Todoist-specific.
- `memory-management` — separate from this; persona/preferences go to memory.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,159 @@
---
name: linkedin-post-writer
description: "Draft LinkedIn posts from 16 tested hook formulas mapped to engagement goals (comments, reposts, likes, saves), with 2026 algorithm formatting rules and an AI-tell scrub pass before publishing."
category: marketing
risk: none
source: community
source_repo: sergebulaev/linkedin-skills
source_type: community
date_added: "2026-07-06"
author: sergebulaev
tags: [linkedin, copywriting, hooks, social-media, personal-brand, content-marketing]
tools: [claude, codex, cursor, gemini]
license: "MIT"
license_source: "https://github.com/sergebulaev/linkedin-skills/blob/main/LICENSE"
---
# LinkedIn Post Writer
## Overview
Drafts long-form LinkedIn posts using 16 hook formulas that were reverse-engineered from posts that outperformed their authors' baselines in 2025-2026, each with a reference engagement number. Instead of asking "what should I write", the workflow asks "what should this post earn" (comments, reposts, likes, or saves), shortlists 2-3 matching formulas, fills the chosen skeleton with the user's voice, then scrubs the draft for AI tells before it ships.
This is the flagship skill from [sergebulaev/linkedin-skills](https://github.com/sergebulaev/linkedin-skills), a 10-skill LinkedIn bundle (writer, humanizer, pre-publish audit, comment drafter, reply handler, hook extractor, content planner, profile optimizer, engager analytics, thread monitor) installable as a Claude Code or Codex plugin. This standalone version covers the drafting workflow; scheduling and publishing automation live in the full bundle.
## When to Use This Skill
- Use when the user says "write me a LinkedIn post about X"
- Use when the user has a topic and a rough angle but needs a hook and structure
- Use when the user wants to pick from proven post formats instead of improvising
- Use when a draft exists but the hook is weak and needs a formula-based rebuild
- Not for replying to comments or optimizing profiles; this skill only drafts posts
## How It Works
### Step 1: Gather inputs
Collect: topic, angle, target audience (founders, operators, marketers), desired length (short 300-500, medium 900-1,300, or long 1,500-1,900 characters), and any raw material the user already has (numbers, anecdotes, names).
### Step 2: Pick the formula by engagement goal first
Ask (or infer) what the post should earn, then shortlist:
| Goal | Earned by | Formulas |
|---|---|---|
| Comments | questions, contrarian takes, vulnerability | F4 Time-Anchor Confession, F10 Contrarian + Receipts, F12 Permission Slip, F9 Curiosity-Gap |
| Reposts | quotable maxims, tributes, "X isn't Y" distinctions | F14 Named Gratitude, F2 R.I.P. Obituary, F8 Paid-vs-Free Reversal |
| Likes | emotional stories, celebrations, status-strip | F11 Emotional Cold-Open, F13 Bait-and-Switch Reversal, F16 Status-Strip Humility |
| Saves | simplifications, exact how-to, frameworks | F15 Explain-to-Kids, F7 Odd-Precision Money Ledger, F8 Paid-vs-Free Reversal |
The full set of 16, with reference engagement:
| Code | Formula | Reference | Best for |
|---|---|---|---|
| F1 | Platform Risk Anaphora | 4,240 eng | Category and platform-risk arguments |
| F2 | R.I.P. Obituary | 3,822 eng | Era-ending claims, industry pivots |
| F3 | Year-over-Year Pivot | 494 eng, 3.74x baseline | Identity shifts, founder reflection |
| F4 | Time-Anchor Confession | 1,519+ eng | Vulnerability, voice reset |
| F5 | Self-Proving Meta | 1,082 eng, 435 comments | Commitments and tests in public |
| F6 | Comment-Gate Lead Magnet | 717-3,008 eng | List building (max once a month) |
| F7 | Odd-Precision Money Ledger | 1,755 eng, 9.4x baseline | Build logs, cost breakdowns |
| F8 | Paid-vs-Free Reversal | 550 eng, 19.64x baseline | Framework giveaways |
| F9 | Curiosity-Gap Teaser | 306 eng, 4.25x baseline | Surprise and behind-the-scenes stories |
| F10 | Contrarian + Historical Receipts | 3,083 eng | Sacred-cow takes backed by history |
| F11 | Emotional Cold-Open | high raw reach | Real stories with emotional stakes |
| F12 | Permission Slip | comment-heavy | Encouragement to a discouraged audience |
| F13 | Bait-and-Switch Reversal | high raw reach | Bad-news framing that turns into an upgrade |
| F14 | Named Gratitude / Tribute | repost-heavy | Thanking mentors, teams, departing colleagues |
| F15 | Explain-to-Kids | save-heavy | Demystifying jargon into a reference post |
| F16 | Status-Strip Humility | like-heavy | Senior voices trading prestige for warmth |
Important caveat: F1-F10 references are engagement counts or format multipliers against the author's own baseline; F11-F16 references are raw corpus reach, often inflated by a famous author or a reshare. The two groups measure different things, so never rank formulas across groups by number.
The full skeletons for all 16 formulas are bundled with this skill in [references/hook-formulas.md](references/hook-formulas.md), along with per-formula warnings and the "Never do" list.
### Step 3: Draft the post
Read the chosen formula's skeleton from the bundled [references/hook-formulas.md](references/hook-formulas.md) and fill it with the user's voice and material, respecting the 2026 formatting rules:
- Hook lands in the first 210 characters (before the "... see more" fold)
- 900-1,300 characters is the sweet spot for text posts
- Double line-breaks between ideas, never walls of text
- 0-2 hashtags, placed at the end
- No external links in the body (put links in the first comment)
- Prefer "How I" over "How to": first-person experience hooks outperform generic instruction 2-3x
- Put one specific number in the first sentence ($873.47 beats $900; 40,000 beats "a lot")
### Step 4: Scrub AI tells
Before showing the draft: strip em dashes, AI vocabulary ("game-changer", "deep dive", "delve"), rule-of-three lists without receipts, and generic openers like "In today's fast-paced world". Add human fingerprints: at least one specific number, one named entity, and one first-person concrete detail per 100 words. Vary sentence length aggressively (mix 3-word and 25-word sentences).
### Step 5: Present the result
Show the user: formula used, full draft, character count, and a suggested posting window (Tuesday to Thursday, 7:30-9:00 AM local time performs best for B2B audiences).
## Examples
### Example 1: Founder build-log (F7 Odd-Precision Money Ledger)
```text
User: write a post about what my bootstrapped SaaS actually costs to run
Agent: Goal check: this reads like a saves play (people screenshot cost
breakdowns). Best fit is F7 Odd-Precision Money Ledger (9.4x baseline).
Draft hook:
"My SaaS costs $412.83 a month to run. Here is every line item."
Then the ledger: hosting $94.20, email $35.00, monitoring $18.63...
exact numbers only, totals that actually add up, one lesson at the end.
```
### Example 2: Goal-first selection
```text
User: I want a post that gets real comments, topic: why I stopped doing demos
Agent: Comment-earners are F4 Confession, F10 Contrarian, F12 Permission Slip.
For "I stopped doing X" the strongest is F10 Contrarian + Receipts:
open with the unpopular claim, back it with 2 historical parallels,
close with a question that forces side-picking. Reference: 3,083 eng.
```
## Best Practices
- ✅ Pick the formula by engagement goal first, topic second
- ✅ Lead with a real failure or a specific number in the first 3 lines
- ✅ Include one moment of genuine vulnerability or concrete stakes; pure insight posts underperform in 2026
- ❌ Don't blend two hook formulas in one post; it dilutes both
- ❌ Don't use F5 Self-Proving Meta unless the user will actually keep the promise
- ❌ Don't pair F7 Money Ledger with rounded or invented numbers; readers notice
- ❌ Don't open with an all-caps line ("THIS CHANGED EVERYTHING")
- ❌ Don't frame LinkedIn as inferior inside a LinkedIn post
## Limitations
- Reference engagement numbers describe the 2025-2026 corpus the formulas were extracted from; they are priors, not guarantees, and LinkedIn's ranking changes over time.
- The skill drafts text posts; it does not generate images, carousels, or video scripts.
- This standalone version does not schedule or publish. Scheduling, comment drafting, reply handling, and engagement analytics require the full bundle from the source repo.
- Voice quality depends on the raw material the user provides; a formula cannot invent authentic anecdotes, and the skill should ask for real details rather than fabricate them.
## Common Pitfalls
- **Problem:** The draft sounds like every other AI-written LinkedIn post.
**Solution:** Run Step 4 ruthlessly. Cut em dashes, cut "game-changer" vocabulary, and force one concrete first-person detail per 100 words.
- **Problem:** The hook is buried in paragraph two.
**Solution:** The first 210 characters must carry the hook; everything before the fold decides the expand rate.
- **Problem:** Comparing F11's raw reach to F8's 19.64x multiplier and picking F11 "because the number is bigger".
**Solution:** The columns measure different things. Match formula to goal and topic, not to the largest number.
- **Problem:** Post gets reach but zero comments.
**Solution:** The formula was picked for the wrong goal. Comment-earners end with a question or a side-picking claim, not a summary.
## Related Skills
- `@linkedin-content-generator` - broader LinkedIn content suite (carousels, newsletters, calendars)
- `@linkedin-profile-optimizer` - profile and authority optimization rather than post drafting
- `@social-post-writer-seo` - multi-platform social copy when LinkedIn is not the only target
## Additional Resources
- [Source repo with all 16 formula skeletons and worked examples](https://github.com/sergebulaev/linkedin-skills)
- [Full 10-skill bundle install (Claude Code / Codex plugin)](https://github.com/sergebulaev/linkedin-skills#install)
@@ -0,0 +1,482 @@
<!-- Vendored from https://github.com/sergebulaev/linkedin-skills/blob/main/references/hook-formulas.md (MIT).
Internal cross-references to the upstream curator's private draft notebook were removed;
the skeletons and reference numbers below are complete and sufficient to apply each formula. -->
# 16 LinkedIn Hook Formulas - 2026 Edition
Each formula has a skeleton, why it works, and a reference engagement number from the original post that defined it.
F1-F10 are the original long-form thought-leadership set. F11-F16 were validated in 2026 against a large corpus of above-average performers across 10 verticals; they skew shorter and more emotional, and each is tagged with its primary engagement goal (comments / reposts / likes / saves). Pick by goal first (see "Engagement-goal split" below), then by topic.
**Reading the reference numbers:** F1-F10 cite engagement with a baseline multiplier (a real format effect, e.g. "19.64x baseline"). F11-F16 cite absolute reach from the 2026 corpus, which can be inflated by reshares or a famous author. Treat F11-F16 numbers as a reach ceiling, not a like-for-like comparison against F1-F10. Where the reach was source-driven rather than format-driven, the formula says so.
## Contents
- F1 - Platform Risk Anaphora
- F2 - R.I.P. Category Obituary
- F3 - Year-over-Year Pivot
- F4 - Time-Anchor Confession
- F5 - Self-Proving Meta
- F6 - Comment-Gate Lead Magnet
- F7 - Odd-Precision Money Ledger
- F8 - Paid-vs-Free Reversal
- F9 - Curiosity-Gap Teaser
- F10 - Contrarian + Historical Receipts
- F11 - Emotional Cold-Open
- F12 - Permission Slip
- F13 - Bait-and-Switch Reversal
- F14 - Named Gratitude / Tribute
- F15 - Explain-to-Kids Simplification
- F16 - Status-Strip Humility
- Engagement-goal split
- Choosing which formula to use
- Hook micro-rules
- Never do
---
## F1 - Platform Risk Anaphora
**Reference:** 4,240 eng.
```
{Platform1} can {restrict|shadowban|throttle} you {timing}.
{Platform2} can {bad thing} for {reason}.
[4-5 more anaphoric lines, escalating specificity]
You don't own {audience}. You don't own {feed}. You're renting {attention}.
[Concrete horror anecdote with real number: "I watched a friend lose 180k followers in an afternoon"]
Here's what most people miss: [reframe: what the real asset is].
So I changed how I work:
- [tactic 1]
- [tactic 2]
- [tactic 3]
[Metaphor close: "castles on rented land vs roads"]
[Product mention as natural conclusion, one sentence, no pitch verbs]
[Personal-audit question]
```
**Why:** Loss aversion stacked 5x. Identity threat. Solution list earns the close.
---
## F2 - R.I.P. Category Obituary
**Reference:** 3,822 eng.
```
R.I.P. {category}.
Cause of death: {specific mechanism + numbers}.
[Concrete evidence, 2-3 paragraphs with dates and stats]
I defended {old thing} publicly through most of 2025.
It worked. Until [pivotal event + date].
Here's what actually changed under the hood:
1. [Change 1 with stat]
2. [Change 2 with stat]
...
6. [Change 6 with stat]
The winners in 2026 aren't {old-winner-type}. They're {new-winner-type}.
[One-line philosophical close]
```
**Why:** Status-threat + relief combo. Reframes "I'm behind" as "the game changed." Removes shame, invites curiosity.
---
## F3 - Year-over-Year Pivot
**Reference:** 494 eng (3.74x baseline).
```
In {last year}, I {humble benchmark}.
In {this year}, I'm {transformational goal}.
Here's what actually changed.
[Vulnerable truth + specific numbers (12 -> 1,000 posts)]
[The identity reframe: "the shift wasn't tools, it was identity"]
[3-beat imperative close]
[Mirror question: "What's your {last}->{this} pivot? One line below."]
```
**Why:** Two-line hook carries 80% of the weight. Mirror CTA compounds engagement algorithmically.
---
## F4 - Time-Anchor Confession
**Reference:** 1,519+ eng.
```
{N} {days|months|years} ago, I stopped {behavior}.
Here's what happened.
[2-year backstory of why the old behavior worked: concrete numbers]
[The quiet cost, what it did to you internally]
So in {month} I stopped. [New behavior, 2-3 lines]
[Metric dropped by N%. Expected worse.]
What surprised me: [counterintuitive upside, specific wins]
[One-line reframe: "X attracts Y. Z attracts the right Y."]
[Mirror question: "What's something you stopped doing that quietly made your work better?"]
```
**Why:** Confession earns the room. Specific numbers kill the "vibes" energy. Close turns every commenter into a mini-confession.
---
## F5 - Self-Proving Meta
**Reference:** 1,082 eng / 435 comments.
```
Most LinkedIn posts die in the first 30 minutes.
Not because {common reason}. Because {real reason}.
[Reveal the metric: "reply latency in first 60 min = 3.4x reach"]
So here's the test.
For the next 24 hours, I will {specific commitment}.
You do two things:
1. [Low-bar action]
2. [Verification action]
If the thesis is right, {outcome}.
If it's wrong, I owe you a post admitting it.
```
**Why:** Claim is validated by reader action. Every comment is evidence. Public accountability hook.
---
## F6 - Comment-Gate Lead Magnet
**Reference:** 717-3,008 eng.
```
[Authority number: "We've helped creators publish 47,000+ posts in 14 months"]
[Pattern observation the authority earned]
So I turned that workflow into {N named items}. [Drop them into X, type one command, get the output.]
What's inside:
- [Item 1]
- [Item 2]
...
- [Item 12]
Free. No email wall. [Light scarcity: "48 hours only, I'll DM the link personally"]
Comment "{keyword}" below + connect with me and I'll send the bundle.
```
**Why:** Capped reach but huge DM conversion. Named bundle + real authority = 300-800 comments if the bundle is genuine.
**Warning:** This is engagement bait. Ship only when the weekly goal is list-building, not thought leadership. LinkedIn suppresses pure "comment X" posts.
---
## F7 - Odd-Precision Money Ledger
**Reference:** 1,755 eng (9.4x baseline).
```
{Odd, specific dollar number: "$873.47"}
[1-line context of what this number covers]
Here is every line item, from the ledger, nothing rounded:
- {tool 1}: $X.YZ
- {tool 2}: $X.YZ
...
[What the total replaces: "$14,200 team cost"]
[The thing that surprised you: what broke, what worked]
[Identity reframe close: "Tradesmen flip houses, SEOs flip blogs, AI founders flip {X}"]
```
**Why:** Non-rounded numbers signal real accounting. Ledger is screenshot-bait. Dwell time stays high.
---
## F8 - Paid-vs-Free Reversal
**Reference:** 550 eng (19.64x baseline, highest multiplier in the set).
```
I charge {audience} $X for {service}.
Screw it. Today it's free.
Below is the exact {N-step} teardown I run before I'll take a client. It's called the {NAMED-FRAMEWORK}.
[Block an hour, open X in one tab, Y in another, grade yourself honestly.]
1. {STEP-1-NAME}: [actionable instruction with specific ratio or example]
2. {STEP-2-NAME}: [actionable instruction]
...
7. {STEP-7-NAME}: [actionable instruction]
That's the {framework}. Run it today. Most {audience} find 3 fixes in the first 20 minutes.
[Soft scarcity close: "Want me to run {framework} on your profile personally? Connect + send me yours, I'll pick 5 this week."]
```
**Why:** Reversal hook (price to free) creates pattern interrupt. Named framework signals proprietary thinking. Checklist drives saves (5x likes under 360Brew).
---
## F9 - Curiosity-Gap Teaser
**Reference:** 306 eng (4.25x baseline).
```
Yesterday, our {system} did something.
Something we didn't program it to do.
[One sensory anchor: "I was watching the logs from my kitchen, half-reading, half-making coffee."]
[Specific reveal, not a platitude: the concrete thing that happened]
[Reframe: what it means for the category, one paragraph]
[Sensory detail: "held a cold cup of coffee for about ten minutes"]
[Philosophical close naming an unnamed feeling, ending with a question]
```
**Why:** Line 1 is incomplete + line 2 deepens the gap = scroll-locked brain. Sensory anchor kills the AI-slop pattern detector.
---
## F10 - Contrarian + Historical Receipts
**Reference:** 3,083 eng.
```
{Sacred cow} has been dying since {year}.
{Month Year}: {event}. "{Death prediction.}"
{Month Year}: {event}. "{Death prediction.}"
[6-9 total dated entries, each 1-2 lines]
Every quarter for N years. Every cycle: the same obituary. The same LinkedIn carousel.
Here's the counterpunch.
[Hard stat with source: "$391B -> $1.81T, 35.9% CAGR"]
[Second stat: "the shippers grew 3-10x in the same window"]
What actually died wasn't {X}. It was {specific subset}. [2-3 lines of who.]
What's thriving: {opposite subset with specifics}.
[Binary identity close:]
If you're still {losing behavior}, you already lost.
If you're {winning behavior}, you already won.
[Provocative question: "What's the most embarrassing X-killed-Y prediction you remember?"]
```
**Why:** Receipt list is a dwell-time machine. Binary identity close forces commenters to pick a side publicly.
---
## F11 - Emotional Cold-Open
**Reference:** highest single post in the 2026 corpus (256k eng), but that reach came from a generic emotional reshare, not the format. Treat it as a ceiling, not a promise. Primary goal: **likes**.
```
{One short line dropped into the emotional peak of a real story: the moment of breaking, loss, or impossible odds. No setup.}
{Subject} had almost {given up / lost everything} after {the struggle}.
[Mid-scene narrative: 3-6 short lines, present-tense, sensory. The reader is already inside the moment.]
[The turn: what changed, who showed up, what it cost.]
[One-line meaning, not a moral. Let the story carry it.]
```
**Why:** Starting at the emotional peak (in medias res) skips the warm-up the scroll punishes. Raw feeling out-travels expertise in every vertical.
**Warning:** Do NOT write the first line in ALL CAPS even though many source posts did; all-caps openers read as AI/cringe. Carry the intensity with word choice, not caps. Only use a true story; half the top emotional posts in the corpus were generic reshares, and readers punish manufactured stakes.
---
## F12 - Permission Slip
**Reference:** 29k eng, comment-heavy. Primary goal: **comments**.
```
I don't know who needs to hear this today, but {reassuring truth aimed at one anonymous reader}.
[2-4 lines that make the reassurance specific and earned, not a platitude.]
[A small, concrete permission: "you're allowed to {X}".]
[Soft close that invites the reader to self-identify.]
```
**Why:** Anonymous second-person reassurance makes readers tag themselves in the comments ("I needed this today"). Comments over-index hard.
**Warning:** This is the most formulaic creator-economy opener in the set. Effective but visibly engineered. Use no more than once or twice a month, and only when the reassurance is something you actually believe, or it reads as hollow.
---
## F13 - Bait-and-Switch Reversal
**Reference:** 195k eng (top of the Startups/Tech corpus). Primary goal: **likes**.
```
Enough is enough. No more {beloved perk / standard practice} at {company / in my workflow}.
We're also cutting {second thing}.
[Beat of suspense: let the reader assume bad news.]
[The reveal: it's actually an upgrade. Here's what we replaced it with and why it's better.]
[What the change really stands for: the value underneath.]
```
**Why:** Fake bad news weaponizes loss aversion, then the positive reveal releases it. The whiplash is the engine.
**Warning:** Only works if the reveal genuinely resolves positive. A real cut dressed as good news will get torn apart in the comments.
---
## F14 - Named Gratitude / Tribute
**Reference:** 109k eng, but from a celebrity tribute reshare. The format helps; the fame did the heavy lifting. Primary goal: **reposts**.
```
To {Name}, {Name}, and {Name}: thank you for {the specific quality or thing they did}.
[2-4 lines naming what each person or the group actually did. Specific, not generic praise.]
[Why it mattered to you / to the work.]
[One-line close that honors them, not you.]
```
**Why:** Publicly naming real people invites everyone tagged or adjacent to repost and amplify. Celebrating others gets shared far more than self-promotion.
**Warning:** Name real people for real reasons. Tactical name-dropping to borrow reach is transparent and backfires.
---
## F15 - Explain-to-Kids Simplification
**Reference:** 23k eng, 2,184 reposts. Primary goal: **saves** (LinkedIn exposes no public save count, so the high repost count stands in as the save-worthiness proxy here, not a sign this is a repost formula).
```
{Jargon term} explained to kids.
Explanations for kids... and adults!
{emoji} {TERM}: what does it stand for?
{emoji} {first part} = {plain-language meaning}
{emoji} {second part} = {plain-language meaning}
[continue the scannable, emoji-anchored glossary]
[One-line "now you'll never forget it" close.]
```
**Why:** A scannable, emoji-anchored simplification of something dense is saved and reshared as a reference. Works for any jargon-heavy field (finance, law, medicine, engineering).
**Warning:** Keep the simplification correct. Condescending or wrong explanations of your own field destroy authority.
---
## F16 - Status-Strip Humility
**Reference:** viral-tier on likes in the corpus (no exact count). Primary goal: **likes**.
```
Outside, I get called {impressive titles like founder, CEO, investor}.
At home, none of that survives {the humbling moment}.
[The scene that strips the status: a kid, a partner, a quiet failure.]
[What the contrast taught you, in one or two lines.]
```
**Why:** Trading prestige for relatability converts authority into warmth. Senior people get likes by showing the human under the title.
**Warning:** Don't humble-brag. The titles in line one should set up a genuine deflation, not a flex disguised as one.
---
## Engagement-goal split
Pick the formula by what you want the post to earn. This split held across all 10 verticals in the 2026 corpus:
| Goal | Earned by | Formulas |
|---|---|---|
| **Comments** | questions, contrarian/unpopular takes, vulnerability, self-tagging | F4 Confession, F10 Contrarian, F12 Permission Slip, F9 Curiosity-Gap |
| **Reposts** | quotable maxims, tributes, "X isn't Y" distinctions | F14 Named Gratitude, F2 R.I.P., F8 Paid-vs-Free |
| **Likes** | emotional stories, celebrations, status-strip, spectacle | F11 Emotional Cold-Open, F13 Bait-and-Switch, F16 Status-Strip |
| **Saves** | simplifications, exact how-to, frameworks | F15 Explain-to-Kids, F7 Odd-Precision Money, F8 Paid-vs-Free |
## Choosing which formula to use
| Topic type | Best formula | Why |
|---|---|---|
| Platform/category argument | F1 Anaphora | Loss aversion stacks cleanly |
| Industry era ending | F2 R.I.P. / F10 Contrarian | Force side-picking |
| Personal year recap | F3 Year-over-Year / F4 Confession | Identity shift reads as earned |
| Product demo in public | F5 Self-Proving Meta | Structural self-proof |
| Big authority giveaway | F6 Comment-Gate / F8 Paid-vs-Free | List-building tier |
| Founder build-log | F7 Odd-Precision Money | Screenshot-bait ledger |
| Emergent/surprise story | F9 Curiosity-Gap | Scroll-lock hook |
| Real story with emotional stakes | F11 Emotional Cold-Open | In-medias-res beats the warm-up |
| Encouragement to a discouraged audience | F12 Permission Slip | Readers self-tag in comments |
| Policy/process change that's an upgrade | F13 Bait-and-Switch | Fake bad news then relief |
| Thanking mentors / team / a departing colleague | F14 Named Gratitude | Named people amplify it |
| Demystifying jargon | F15 Explain-to-Kids | Save-worthy reference |
| Senior person wanting warmth, not distance | F16 Status-Strip | Prestige traded for relatability |
## Hook micro-rules
- **"How I" beats "How to".** First-person experience ("How I cut CAC by 62%") outperforms generic instruction ("How to cut CAC") by 2-3x. Swap every "How to" hook to "How I" unless the post is a pure framework with no narrator.
- **Specific number in the first sentence** raises expand-rate by ~35%. $873.47 beats $900. 40,000 beats "a lot of".
- **Real failure in the first 3 lines** outperforms polished framing by **8.5x**. Lead with what broke.
## Never do
- Blend two hooks in one post (dilutes both)
- Use F5 Self-Proving Meta if you won't actually keep the promise
- Use F6 Comment-Gate more than once per month
- Pair F7 Money Ledger with made-up numbers; readers know
- Use F1 Anaphora to frame LinkedIn as inferior (algo penalty on LinkedIn)
@@ -8,7 +8,7 @@
"name": "todo-app-backend",
"version": "1.0.0",
"dependencies": {
"better-sqlite3": "^12.10.1",
"better-sqlite3": "^12.11.1",
"cors": "^2.8.6",
"express": "^4.18.2",
"express-rate-limit": "^8.5.2"
@@ -302,9 +302,9 @@
"license": "MIT"
},
"node_modules/better-sqlite3": {
"version": "12.10.1",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.10.1.tgz",
"integrity": "sha512-HfFtzCqnSfwB3+HroF6PSKzyh+7RfNMGPCzHFUZXRlvrPCb4P3cvxKZNN43Sr7IrkofqQZM+gIvffGpA8VvqgA==",
"version": "12.11.1",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.11.1.tgz",
"integrity": "sha512-dq9AtApgg5PGFtBzPFSBl3HZQjHok5gaQCM6zh2Yk0aSmDCs1CbnVI8/HgASQkNKsWFpseIO9beg5xxpYhbIfA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -9,7 +9,7 @@
"dev": "ts-node src/index.ts"
},
"dependencies": {
"better-sqlite3": "^12.10.1",
"better-sqlite3": "^12.11.1",
"cors": "^2.8.6",
"express": "^4.18.2",
"express-rate-limit": "^8.5.2"
@@ -0,0 +1,72 @@
---
name: markdown-rendering
description: "Open Markdown reliably in cmux panes and recover from blank rendered surfaces."
category: productivity
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [markdown, cmux, rendering]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Markdown Rendering in cmux
## When to Use
- Use when opening Markdown in cmux shows a blank pane or wrong layout.
- Use when you need to display a Markdown file in a stable cmux right pane.
## The Problem
`cmux markdown open` defaults to **spawning a brand-new pane** every time, even with `--direction right`. The common "fix" — moving the new markdown surface into the existing right pane with `move-surface`**bugs out: the moved viewer renders BLANK.** The surface keeps `type=markdown` and looks healthy, but shows nothing.
So you get stuck: either a stray extra pane, or a blank viewer after moving it.
## The Rule
You have exactly two reliable options. **Never `move-surface` a markdown viewer** — that is the path that bugs.
### Option A — Open it right on the first try
If there is no usable right pane yet, just let cmux create one and leave it where it lands:
```bash
cmux markdown open /abs/path/file.md --direction right --focus false
```
Do NOT then move it. If it spawned where you want it, you're done.
### Option B — Close existing right pane(s), then open fresh
If there are other right panes in the way (and they're unused or irrelevant), **close them first**, then open the markdown fresh as a new right pane:
```bash
# 1. find panes in THIS workspace
cmux list-panes --workspace "$CMUX_WORKSPACE_ID"
# 2. close the unused/irrelevant right pane(s) by closing their surfaces
cmux list-pane-surfaces --pane pane:NN
cmux close-surface --surface surface:XX # repeat per surface in that pane
# 3. THEN open the markdown fresh — it creates its own clean right pane
cmux markdown open /abs/path/file.md --direction right --focus false
```
## Hard Rules
- **Never `move-surface` a markdown viewer.** It renders blank afterward. This is the core bug this skill exists for.
- Open it correctly the first time (Option A), OR close the conflicting right pane(s) and open a fresh right pane from scratch (Option B).
- Only close panes that are unused or irrelevant — never close a pane the user is working in.
- Always anchor to `$CMUX_WORKSPACE_ID`; never assume the visually focused workspace.
- Pass `--focus false` so you don't steal the user's focus.
- You can't screenshot/read a markdown surface to verify it. If unsure it rendered, ask the user.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,68 @@
---
name: pi-custom-model
description: "Register custom Pi Agent model slugs so saved OpenRouter variants resolve correctly."
category: operations
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [pi-agent, models, openrouter]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
# Pi custom / variant model
## When to Use
Pi's saved default only loads if the exact `provider/id` exists in its model registry. Pi ships a static bundled list per provider — so OpenRouter **routing-shortcut variants** (`:nitro` = sort by throughput, `:floor` = cheapest, `:exacto` = quality tool-use) and any brand-new slug are NOT in it. When the default doesn't resolve, Pi silently falls through to its built-in per-provider default (for openrouter that's `moonshotai/kimi-k2.6`) — looking like Pi "reset" your model. Fix = register the slug as a custom model so `find(provider, id)` matches.
## Files (global)
- `~/.pi/agent/settings.json``defaultProvider`, `defaultModel`, `defaultThinkingLevel`
- `~/.pi/agent/models.json` — custom models, keyed by provider
- `~/.pi/agent/auth.json` — provider credentials (check the provider key exists)
## Steps
1. **Confirm the slug is real** before adding it (e.g. check the OpenRouter model/variant exists). A typo'd id also silently falls back.
2. **Confirm auth.** The provider must have a key in `auth.json` (or an env var like `OPENROUTER_API_KEY`). No auth → the model is registered but unavailable → still falls back.
3. **Add the model to `models.json`** under `providers.<provider>.models`. For a **built-in provider** (openrouter, anthropic, etc.) you only supply metadata — `api`, `baseUrl`, and auth are inherited from the bundled defaults. Example:
```json
{
"providers": {
"openrouter": {
"models": [
{
"id": "z-ai/glm-5.2:nitro",
"name": "Z.ai: GLM 5.2 (nitro)",
"reasoning": true,
"thinkingLevelMap": { "xhigh": "xhigh" },
"input": ["text"],
"cost": { "input": 0.95, "output": 3, "cacheRead": 0.18, "cacheWrite": 0 },
"contextWindow": 1048576,
"maxTokens": 32768,
"compat": { "supportsDeveloperRole": false, "thinkingFormat": "openrouter" }
}
]
}
}
}
```
Copy `cost`/`contextWindow`/`compat` from the base model (the variant shares them) — find the bundled entry in `<pi-pkg>/node_modules/@earendil-works/pi-ai/dist/providers/<provider>.models.js`. Don't hardcode generic 128k/16k if the real model is bigger.
4. **Set the default** in `settings.json`: `defaultProvider` + `defaultModel` = the exact id. Leave `defaultThinkingLevel` as the user has it.
5. **Verify:** `pi --list-models | grep <id>` shows it, and JSON parses. Optionally smoke-test: `pi --provider <p> --model "<id>" "which model are you?"`.
## Quirks
- **Exact match only.** `find()` is exact `provider`+`id` — no fuzzy/colon-stripping for the *saved default* path. The slug in `settings.json` and `models.json` must be byte-identical.
- **Silent fallback.** Pi prints no error when the default doesn't resolve; it just shows a different model in the footer. That's the tell.
- **Don't edit `settings.json` alone.** Setting `defaultModel` to an unregistered slug does nothing — `models.json` is the actual fix.
- **`enabledModels`** (optional) pins the model picker so Ctrl+P cycling can't drift back: `"enabledModels": ["<provider>/<id>:<thinking>"]`.
- **Project override.** A repo's `.pi/settings.json` overrides global. If a default reverts only inside one project, check that file first.
- Restart Pi fully — the registry loads at startup.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,74 @@
---
name: pi-web-search
description: "Give Pi Agents a safe web-search and fetch workflow using the installed pi-web-access package."
category: research
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [web-search, pi-agent, research]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Web Search
## When to Use
- Use when a Pi Agent task needs current web information, page fetches, PDFs, YouTube, or GitHub content.
- Use when Pi should use its own web-access package instead of another agent browser tool.
The `pi-web-access` package is installed globally. Zero-config via Exa MCP (no API key), with fallback Exa → Perplexity → Gemini.
## CRITICAL: always pass `workflow: "none"`
Every `web_search` call MUST include `workflow: "none"`. This skips the interactive browser curator popup (the user does not want it opening). No exceptions — single query or batched `queries`, always set `workflow: "none"`.
```
web_search({ queries: ["query 1", "query 2"], workflow: "none" })
```
## Tools
- `web_search` — search the web; returns synthesized answers with citations. Can be called many times per turn. **Always pass `workflow: "none"`.**
- `code_search` — zero-key Exa code-context. Use for library/API/code lookups instead of generic `web_search`.
- `fetch_content` — fetch URL(s) → markdown; handles PDFs, YouTube, GitHub.
- `get_search_content` — big pages (>30k chars) are truncated in responses but stored in full; call this to pull the rest on demand so they don't blow context.
## fetch_content specifics
- **GitHub URLs are cloned, not scraped** — you get real files + a local path to explore with `read`/`bash` (private repos need the `gh` CLI). Use this for dev work.
- **PDFs** → auto-extracted to markdown in `~/Downloads/`, readable in sections (text-only, no OCR).
- **YouTube/video** → full raw transcripts + frame extraction. Needs a `GEMINI_API_KEY` (not zero-config); frame extraction also needs `ffmpeg`/`yt-dlp`.
## Routing — match the user's phrasing
Always use the `web_search` tool. These counts are HARD MINIMUMS — count your queries before answering and do not stop short:
- **"web search"** → **at least 2** queries, varied keywords/angles, then synthesize.
- **"extensive web research"** → **at least 4** queries, totally different keywords and angles.
- **"deep research"** → **at least 8** queries, totally different keywords and angles, run across 23 successive batches (refine angles after each batch), to learn as much as possible about the topic.
A single batched `web_search` call counts each query in `queries[]` toward the total. If your first batch is under the minimum, fire another batch before synthesizing.
## Fallback / alternative: DeepAPI web search
If the Exa → Perplexity → Gemini chain fails, or you need ranked results with URLs:
```bash
test -n "$DEEPAPI_API_KEY" || { echo "DEEPAPI_API_KEY is not set"; exit 1; }
curl -s --max-time 60 "https://deepapi.co/v1/search/web" \
-H "Authorization: Bearer $DEEPAPI_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"query": "your search terms", "maxResults": 5, "maxCostUsd": "0.05"}'
```
Results are in `.output` (title, url, snippet per item). Query under 500 chars. Full details: `deepapi` skill.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,61 @@
---
name: push-skill-to-github
description: "Commit and push skill changes to the configured skills repository after review and validation."
category: development
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [skills, git, publishing]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Push Skills to GitHub
## When to Use
- Use when skill changes are ready to commit and push to the configured skills repo.
- Use when the user asks to save or publish skill updates after validation.
For committing any skill change to the user's private skills repo, git root **`~/.agents`** (this is also the canonical skill folder; `.claude` and `.pi/agent/skills` symlink to `~/.agents/skills`). Pushes here auto-publish a sanitized public mirror to `davidondrej/skills` — never push directly to that public repo.
Use this after creating or editing a skill. If the skill is distributed to all agents, do that first (`distribute-skill-to-all-agents`), then run this to push the canonical copy.
## Steps
**Not in cmux?** (no `$CMUX_WORKSPACE_ID`): skip the cmux pane steps — just run the git commands from step 2 directly in any available terminal, then verify the push output.
1. **Open a fresh cmux pane** in the current workspace, no focus steal:
```bash
cmux new-pane --type terminal --direction right --workspace "$CMUX_WORKSPACE_ID" --focus false
cmux list-panes --workspace "$CMUX_WORKSPACE_ID" # note the NEW pane + its surface ref
```
2. **Stage, commit, push** in `~/.agents` (send to the new pane's surface):
```bash
cmux send --surface surface:NEW 'cd ~/.agents && git add -A && git commit -m "<concise message>" && git push'
cmux send-key --surface surface:NEW enter
```
3. **Verify** the push landed:
```bash
sleep 2
cmux read-screen --surface surface:NEW | tail -15 # expect "main -> main"
```
4. **Close the pane** once confirmed:
```bash
cmux close-surface --surface surface:NEW
cmux list-panes --workspace "$CMUX_WORKSPACE_ID" # confirm the pane is gone
```
## Notes
- Always run git from `~/.agents` (the repo root), not `~/.agents/skills`.
- Write a concise, specific commit message describing the skill change.
- Only push to GitHub when the user asks. Don't push speculatively.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,35 @@
---
name: read-all-adrs
description: "Read every ADR in a project before summarizing architectural context or decisions."
category: productivity
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [adr, documentation, architecture]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
<!-- TODO(David): write the strong wording here -->
## When to Use
- Use when the user explicitly asks to load ADR context.
- Use when architectural decisions must be understood before changing or judging a project.
Read EVERY single ADR `.md` file in this project's `docs/adr/` folder, start to
finish.
Do not skim. Read each ADR completely before summarizing.
Read every single ADR file, for this project, in full.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,63 @@
---
name: research-prompt
description: "Turn vague research needs into one precise deep-research prompt with context and output criteria."
category: research
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [research, prompting, briefs]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# Research Prompt
## When to Use
- Use when the user wants a deep-research brief or researcher prompt.
- Use when a vague research question needs to become one precise self-contained paragraph.
Goal: turn a vague research need into ONE self-contained paragraph that a researcher with zero prior knowledge of the project can act on with zero back-and-forth.
## Rules
- **One paragraph.** No headers, no bullet list in the deliverable.
- **Prompt the job, not the topic.** Give search handles (timeframe, ranking, source type, decision logic) — not just a subject.
- **Assume zero prior knowledge.** Write for a researcher who has never heard of the project. Open by explaining, in plain English, what the project/product is, why it exists, and the current situation — so they understand what's going on, what we need, and why we need it.
- **Lead with the goal + decision.** Right after that explainer, state the single question the research must answer and the decision/use it informs.
- **Embed all context.** Names, dates, product, prior known facts, constraints. The researcher must not need to ask anything or guess.
- **Number the sub-questions inline** (1, 2, 3…) so coverage is explicit. Keep to 36. One mission per prompt — don't cram unrelated questions.
- **State constraints.** What to include, what to avoid (e.g. "only non-Chinese competitors", "no marketing fluff").
- **Source hierarchy.** Prefer primary sources (official docs, GitHub, papers, filings, changelogs); forums/X/Reddit are weak signal only, never factual proof.
- **Contradiction handling.** If sources conflict, separate confirmed facts / inference / unresolved uncertainty — don't force fake consensus. Flag low-confidence claims for verification.
- **Completion bar (define "done").** Don't stop at the first plausible answer. Corroborate each key claim with multiple independent primary sources where they exist; where sources are scarce, say so explicitly instead of padding. Keep going until every numbered sub-question is covered to this bar.
- **Gap round before finishing.** Require a final self-critique pass: list gaps, contradictions, and any single-source claims, then run another round of searches to close them — repeat until clean.
- **Constrain output hard, method loosely.** Be strict on the deliverable; leave the search path flexible so the researcher can explore.
- **Demand a fixed output per finding:** source link + specific claim + one-line "why it matters / why a viewer should care".
- Verifiable, citable facts only. No opinions.
- **Last sentence:** instruct them to output everything into a single detailed markdown file.
## Process
1. Pull context from the relevant project files / conversation (dates, names, known facts, audience, end use), and write a 12 sentence plain-English explainer of what the project is and why it exists for a reader who knows nothing.
2. Identify the ONE question the research answers.
3. Draft 36 numbered sub-questions that fully cover it.
4. Add include/avoid constraints + the per-finding output format.
5. Compress to one clean paragraph. Cut filler.
## Template
> [For a reader with zero prior knowledge: in 12 plain-English sentences, what the project/product is, why it exists, and the current situation.] Research [TOPIC + key identifying facts] to answer one question: [THE QUESTION] — for [DECISION / END USE]. Find: (1) …; (2) …; (3) …; (4) …. [Constraints: include X, avoid Y.] Prefer primary sources; treat forums/social as weak signal only; if sources conflict, separate fact from inference and flag what needs verification. Don't stop at the first plausible answer: corroborate each key claim with multiple independent primary sources where they exist (and say so explicitly where they don't), continuing until every numbered question is covered to that bar. Before finishing, do a self-critique pass — list gaps, contradictions, and any single-source claims, then run another round of searches to close them, repeating until clean. For each point, give the source link, the specific claim, and a one-line "why it matters". No marketing fluff — verifiable, citable facts only. Output everything into a single detailed markdown file.
## Executing the prompt
To run the finished prompt with an AI researcher, execute it via DeepAPI `POST /v1/research/deep` — follow the `deep-research` skill.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,120 @@
---
name: run-deep-swe
description: "Run reproducible DeepSWE coding-agent benchmark evaluations through OpenRouter and mini-swe-agent."
category: agent-evaluation
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [benchmark, deepswe, openrouter, evaluation]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
# Run DeepSWE via OpenRouter
## When to Use
- Use when the user wants to benchmark a model on DeepSWE or mini-swe-agent tasks.
- Use when you need a reproducible coding-agent evaluation plan and output artifacts.
DeepSWE (deepswe.datacurve.ai) is a 113-task Harbor-compatible coding-agent benchmark. It runs via **Pier** (Harbor fork) driving **mini-swe-agent** (model-agnostic). Any model reachable through OpenRouter can be scored.
## Prerequisites — state-check first
```bash
which uv git docker || echo "MISSING: install uv, git, docker"
docker info >/dev/null 2>&1 || echo "MISSING: Docker daemon not running (Pier's default sandbox)"
echo "OPENROUTER_API_KEY set? ${OPENROUTER_API_KEY:+YES}"
```
**Docker must be running** — Pier sandboxes each task in Docker by default (`--env modal` for cloud instead).
`OPENROUTER_API_KEY` must already be present in the environment. If it is unset,
ask the user to configure their preferred secret-management path; do not read
shell startup files, print secrets, or invent a key.
## Setup
```bash
git clone https://github.com/datacurve-ai/deep-swe && cd deep-swe
uv tool install datacurve-pier # PyPI (preferred)
# or: uv tool install git+https://github.com/datacurve-ai/pier
# pier bundles mini-swe-agent as the --agent driver
```
Run all `pier` commands from inside `deep-swe/`, using relative `-p tasks/...`.
## OpenRouter wiring (the part the docs don't spell out)
mini-swe-agent has a native OpenRouter model class. Both routes below use `OPENROUTER_API_KEY` and the OpenRouter slug (`vendor/model`, e.g. `minimax/minimax-m3`):
**Route A — native OpenRouter class (preferred, hits openrouter.ai/api/v1 directly):**
```bash
pier run -p deep-swe/tasks --agent mini-swe-agent \
--model minimax/minimax-m3 --model-class openrouter
```
**Route B — LiteLLM provider prefix (fallback; same key):**
```bash
pier run -p deep-swe/tasks --agent mini-swe-agent \
--model openrouter/minimax/minimax-m3
```
Notes:
- Slug = the exact OpenRouter slug. Verify it at openrouter.ai/models before running.
- Free/zero-cost models: OpenRouter cost tracking can error. Set `export MSWEA_COST_TRACKING=ignore_errors`.
- Flag spelling can vary by version — confirm with `pier run --help` and `mini --help`.
## Smoke test FIRST (1 task — do this before any full run)
Always validate end-to-end wiring on a single task before spending tokens on the corpus:
```bash
pier run -p deep-swe/tasks/<task-id> --agent mini-swe-agent \
--model minimax/minimax-m3 --model-class openrouter
# list available task ids:
ls deep-swe/tasks
```
Pass criteria: run completes, model returns actions (not auth/format errors), a score/trajectory is emitted. If it 401s → key wrong. If "provider not provided"/"model not mapped" → fix slug or switch route.
## Subset run (deterministic sample)
```bash
pier run -p deep-swe/tasks --agent mini-swe-agent \
--model minimax/minimax-m3 --model-class openrouter \
--n-tasks 10 --sample-seed 0
```
## Full 113-task corpus (costs tokens + time — confirm with user first)
```bash
pier run -p deep-swe/tasks --agent mini-swe-agent \
--model minimax/minimax-m3 --model-class openrouter
# add `--env modal` to run in parallel Modal sandboxes (needs Modal configured)
```
## Output & leaderboard
- Trials land in `jobs/<run>/<trial_id>/`. Inspect with `pier view jobs/<run>`, `pier analyze jobs/<run>`, or `pier critique run jobs/<run>`.
- Report: the exact command used, pass/fail, score, and any blockers.
- Submit results for the official leaderboard to: **<email-address>**
## Failure modes
| Symptom | Cause | Fix |
|---|---|---|
| HTTP 401 | bad/missing key | re-export `OPENROUTER_API_KEY` |
| "LLM Provider NOT provided" | missing slug prefix | use Route B `openrouter/...` or Route A with `--model-class openrouter` |
| "model isn't mapped"/cost error | unknown cost for model | `export MSWEA_COST_TRACKING=ignore_errors` |
| unknown flag | version drift | check `pier run --help` |
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,50 @@
---
name: setup-help
description: "Walk a user through setup or installation one step at a time with the remaining steps visible."
category: productivity
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [setup, onboarding, installation]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
# setup-help
## When to Use
- Use when the user asks to set up, install, configure, or get something working step by step.
- Use when the setup has multiple steps and benefits from one-at-a-time guidance.
Guide the user through any setup, one step at a time, in plain English.
## Response format (every single response)
1. **Current step** — ONE atomic action. A single click, field, or command — not a checklist. 12 lines max. If it needs sub-steps, it's too big: split it and push the rest into "Still remaining". Plain English.
2. A `----` divider.
3. **Still remaining** — a numbered list of the setup steps left after this one. Max 8 items, ever.
Repeat this format for every response until setup is done.
## Rules
- Before the first step, build a complete canonical checklist from the user's outline, repo/docs, current screen, and any discovered prerequisites.
- The **Still remaining** list must never exceed 8 items — more is overwhelming. Track ALL unfinished checklist items internally; if more than 8 remain, show the nearest steps individually and merge the later ones into broader phase-level items so the list stays at 8 or fewer. Never silently drop a required step from internal tracking.
- If a new required step is discovered mid-setup, add it to **Still remaining** immediately in the correct order.
- Before every response, audit the current step plus **Still remaining** against the canonical checklist. If any unfinished step is missing, fix the list before replying.
- Only give instructions for the current step. Do not jump ahead.
- Keep it concise. Short sentences. No filler.
- After the user finishes a step, move the next "remaining" item up to "Current step".
- Update the "Still remaining" list each time as steps get done.
- When nothing remains, say setup is complete instead of showing the list.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,28 @@
---
name: short
description: "Rewrite the previous response more briefly while preserving the substance."
category: writing
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [writing, editing, concise]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
disable-model-invocation: true
---
rewrite your last response to be simpler & shorter. do not do anything else.
## When to Use
- Use when the user asks for a shorter, simpler, or TLDR version of the previous response.
- Use when the current answer should be compressed without changing the substance.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,79 @@
---
name: taisly-social-media-posting
description: "Use Taisly Agent Kit to prepare and publish approved short-form video posts across TikTok, Instagram Reels, YouTube Shorts, X, and Facebook."
category: marketing
risk: critical
source: community
source_repo: taisly/agent
source_type: community
date_added: "2026-07-07"
author: taisly
tags: [social-media, video, publishing, mcp, cli, sdk, tiktok, instagram, youtube-shorts, x, facebook]
tools: [codex, claude]
license: "MIT"
license_source: "https://github.com/taisly/agent/blob/main/LICENSE"
---
# Taisly Social Media Posting
## Overview
Taisly Agent Kit provides an MCP server, CLI, SDK, and agent docs for publishing
approved short-form videos to TikTok, Instagram Reels, YouTube Shorts, X, and
Facebook. Use this skill to plan a posting workflow around Taisly, verify that
the user has the required account access, and keep publishing actions behind an
explicit confirmation gate.
## When to Use
- Use when the user wants an agent-assisted workflow for publishing short-form
videos with Taisly.
- Use when the user mentions `taisly/agent`, the Taisly MCP server, Taisly CLI,
or the Taisly SDK.
- Use when coordinating final approval, caption metadata, target platforms, and
posting status for social video distribution.
## Workflow
1. Confirm the exact target platforms and video asset paths or URLs.
2. Confirm that the user has already connected the relevant social accounts in
Taisly or has provided the intended MCP/CLI setup path.
3. Draft or review captions, hashtags, titles, descriptions, and platform
metadata before any publishing command is run.
4. Present a final posting summary with platforms, media, captions, visibility,
and timing.
5. Wait for explicit user approval before invoking any Taisly command, MCP tool,
SDK call, or other state-changing publishing action.
## Examples
```text
Use Taisly to prepare this product demo for TikTok, Reels, Shorts, X, and Facebook.
Review the caption and metadata first; do not publish until I approve.
```
```text
Set up a Taisly MCP publishing workflow for approved video assets in ./campaign.
```
## Safety Notes
- Treat publish, schedule, delete, account-linking, and metadata update actions
as state-changing operations requiring explicit user approval.
- Never request, print, or store platform passwords, OAuth secrets, API keys, or
session tokens. Use the user's existing Taisly/MCP/CLI authentication flow.
- If the requested action could violate platform policies, brand review, legal
constraints, or creator permissions, pause and ask for confirmation.
## Limitations
- Platform availability, media requirements, and API behavior depend on the
upstream Taisly Agent Kit and connected platform accounts.
- This skill does not replace human review for legal, brand, copyright, or
platform-compliance decisions.
- Verify the current Taisly setup instructions from `taisly/agent` before
installing or running tools in a new environment.
## Source
- GitHub: [taisly/agent](https://github.com/taisly/agent)
@@ -0,0 +1,72 @@
---
name: vps-server-management
description: "Manage authorized VPS hosts and server-side agents through cautious SSH and operations workflows."
category: operations
risk: critical
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [vps, ssh, server-management]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# VPS Server Management
## When to Use
- Use when the user asks to operate an authorized VPS or agent running on a remote host.
- Use when SSH, deployment, restart, status, or log inspection is needed with explicit permission.
Source of truth: `library/infrastructure.md` (read it for the latest — IPs/expirations change).
## Servers (Hostinger VPS) — 3 total
| Hostname | IP | OS | Purpose | Expires |
|---|---|---|---|---|
| openclaw-server | <IP> | Ubuntu 24.04 (Dokploy) | OpenClaw — personal instance | <expiry> |
| n8n-server | <IP> | Ubuntu 24.04 (n8n) | All n8n workflow automations (primary) | <expiry> |
| hermes-server | <IP> | Ubuntu 24.04 | Hermes Agent — Discord gateway (Vilnius, LT) | <expiry> |
SSH as `root@<IP>`.
## Access levels (never share higher than needed)
1. **App login** — e.g. `app.example.hstgr.cloud`. Build/edit workflows, no server access. Safest to share.
2. **VPS SSH**`root@<IP>`. Docker, files, system config. Trusted technical people only.
3. **Hostinger hPanel**`hpanel.hostinger.com`. Billing, reboot, OS reinstall. Exposes SSH creds + browser terminal, so it grants server access too. The user only.
## Managing a VPS via an agent
For multi-step or exploratory work, **SSH into the box first and launch the agent ON the VPS** (e.g. `codex --yolo`), then talk to that local-on-server agent — it has full filesystem/process context and avoids fragile SSH round-trips. For short command sequences (update, config change, restart), driving an existing SSH session directly (e.g. via a cmux pane) is fine.
When checking on a remote/on-box agent, send the user one concise status line each time: what it is doing and whether it is on track.
Claude Code cmux note: after Claude finishes, it may prefill a predicted next user message; that draft is Claude, not the user speaking.
## Agents on servers
- **OpenClaw** → openclaw-server (managed via Dokploy).
- **Hermes** → hermes-server (Discord gateway). Setup/config docs in `library/hermes/`.
- **n8n** → n8n-server.
## Hermes ops (on hermes-server)
```bash
hermes --version # shows version + commits behind
hermes update # auto-snapshots, updates deps, rebuilds web UI, restarts gateway itself
hermes gateway status|restart
journalctl --user -u hermes-gateway --since '5 min ago' --no-pager # gateway logs (systemd USER service)
```
- **Default model** lives in `~/.hermes/config.yaml` under `model.provider` + `model.default` — NOT in `.env`. Change via `hermes model` (interactive) or edit the yaml directly, then `hermes gateway restart` to propagate to gateways.
- npm `EBADENGINE` warnings during update (deps want Node >=24, box runs v22) are non-blocking — do not "fix" them.
- Deeper docs (Discord/Slack/WhatsApp setup, file structure, vision config): `library/hermes/`.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
@@ -0,0 +1,120 @@
---
name: youtube-transcript
description: "Fetch YouTube transcripts through DeepAPI or local fallback tooling and save clean text output."
category: research
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [youtube, transcripts, research]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---
# YouTube Transcript (via DeepAPI, yt-dlp fallback)
## When to Use
- Use when the user asks for a YouTube transcript, captions, subtitles, or spoken-content extraction.
- Use when DeepAPI or a local fallback can fetch the transcript safely.
Fetch a YouTube video's transcript and save a clean raw `.txt` file. Primary path is DeepAPI `POST /v1/scrape/youtube/transcript`. It runs server-side, so it avoids the local-IP bot flagging that plagues yt-dlp.
## Save location
- If the user is in a real project/working dir → save there.
- Otherwise (no dir given, or cwd makes no sense) → save to `~/Downloads`.
- **Always name the file `Channel_Title` with spaces replaced by `_`** (e.g. `David_Ondrej_title_of_video.txt`). If metadata is unavailable, fall back to the video ID.
## Primary path — DeepAPI
`DEEPAPI_API_KEY` must already be present in the environment. Do not read shell
startup files or print secrets:
```bash
test -n "$DEEPAPI_API_KEY" || { echo "DEEPAPI_API_KEY is not set"; exit 1; }
BASE=${DEEPAPI_API_BASE_URL:-https://deepapi.co}
```
Run the scrape (keep the Idempotency-Key; retries must reuse the SAME one):
```bash
IDK=$(uuidgen)
curl -s --max-time 120 "$BASE/v1/scrape/youtube/transcript" \
-H "Authorization: Bearer $DEEPAPI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDK" \
-d '{"url": "VIDEO_URL", "maxCostUsd": "0.05", "waitForFinishSecs": 60}' \
> /tmp/yt_transcript.json
```
- Non-English videos: add `"language": "de"` (etc.) to the body.
- `status: running` → wait `next.afterSecs`, then `curl "$BASE$(jq -r '.next.path' /tmp/yt_transcript.json)" -H "Authorization: Bearer $KEY"` until `succeeded` or `failed`.
Extract the text and save it:
```bash
jq -r '.status' /tmp/yt_transcript.json # succeeded | running | failed
jq -r '.output[0].text' /tmp/yt_transcript.json > "$OUT/$NAME.txt"
jq -r '.debitMicrousd' /tmp/yt_transcript.json # cost (50000 = $0.05)
```
`.output[0].segments` also has timed segments (`startSecs`, `durationSecs`, `text`) if the user wants timestamps. Empty `output` = video has no captions; report it, don't retry.
For the `Channel_Title` filename, get metadata with a quick `yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL"`; if that fails, use the video ID.
## When to fall back to yt-dlp
- `DEEPAPI_API_KEY` missing from the environment.
- HTTP 402 `insufficient_credits` (tell the user to top up at deepapi.co/credits first; fall back only if they're unavailable).
- DeepAPI request `failed` twice.
Tell the user whenever you fall back — a fallback means the product missed a real use case.
## Fallback path — yt-dlp (local)
```bash
OUT="$(pwd)" # or ~/Downloads if cwd makes no sense
META=$(yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL")
NAME=$(echo "$META" | tr '| ' '__' | tr -cd '[:alnum:]_.-') # "Channel_Title", spaces -> _, strip unsafe chars
yt-dlp --skip-download --write-subs --write-auto-subs \
--sub-langs "en.*" --sub-format json3 \
-o "$OUT/$NAME.%(ext)s" "URL"
```
- Fall back `channel``uploader``uploader_id` if `channel` is null.
- `--skip-download` = captions only. `--write-subs` + `--write-auto-subs` = manual first, auto as fallback.
- **Always use `json3`, never VTT/SRT** — auto VTT repeats every line twice (rolling captions).
Flatten json3 → raw text:
```bash
python3 - "$OUT" <<'PY'
import json, html, re, glob, sys, pathlib
f = glob.glob(sys.argv[1] + "/*.json3")
if not f: sys.exit("no json3 file")
data = json.load(open(f[0], encoding="utf-8"))
parts = ["".join(s.get("utf8","") for s in e.get("segs") or []) for e in data.get("events", [])]
txt = re.sub(r"\s+", " ", html.unescape(" ".join(p.strip() for p in parts if p.strip()))).strip()
out = pathlib.Path(f[0]).with_suffix(".txt")
out.write_text(txt, encoding="utf-8"); print(out)
PY
```
### yt-dlp failure handling
- Non-English / unknown language: run `yt-dlp --list-subs "URL"` first, then set `--sub-langs`.
- Newer yt-dlp may need `deno` on PATH for YouTube extraction.
- On first failure: run `yt-dlp -U` once, retry once, then stop.
- **429 / "Sign in to confirm you're not a bot"** = IP flagged. STOP — do NOT retry in a loop (makes it worse).
- Never fall back to downloading audio for Whisper unless the user explicitly asks.
## Output
Report the saved path; print the text if short. If DeepAPI was used, also report the cost in dollars.
## Limitations
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.