Skip to main content

shiplog

Recap of everything shipped since the last run - cross-repo PRs, security fixes, star deltas, and X traction, synthesized into a digest article and a ready-to-post shiplog in your voice.

Aller à l'installation

Informations de source

Dépôt
aeonfun/aeon
Dernière activité de la source
17 août 2026 à 22:02
Langue détectée de SKILL.md
anglais
Étoiles
738
Forks
265

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
shiplog
description
Recap of everything shipped since the last run - cross-repo PRs, security fixes, star deltas, and X traction, synthesized into a digest article and a ready-to-post shiplog in your voice.
metadata
{"title":"Shiplog","category":"core","var":"","requires":["XAI_API_KEY?","GH_GLOBAL?"],"tags":["content","social"]}
> **${var}** — Optional, space-separated flags: > - `since:YYYY-MM-DD` — override the window start (default: when this skill last ran). > - `days:N` — window = last N days. > - `dry-run` — render to stdout; write no article, no state, no notify. > - `owner/repo` — narrow GitHub coverage to that one repo. > - any other word — focus/theme filter (a product name or keyword). > > Empty = everything shipped since the last run, across all configured repos. Produce two artifacts: 1. **Digest** — a themed, human-readable recap of everything that shipped + traction (the article). 2. **Shiplog post** — a tight, bulleted, ready-to-post version in the operator's voice, every project @-tagged (the notification). This is **cadence-agnostic**: the window is always "since the last run" (`memory/state/shiplog-last.json`), so the `aeon.yml` schedule alone decides whether this is a daily, weekly, or on-demand recap. One skill, any frequency. Read `STRATEGY.md`, `memory/MEMORY.md`, and the last 7 days of `memory/logs/` for context. Read `soul/SOUL.md` + `soul/STYLE.md` before writing any output — the shiplog post must sound like the operator, not a changelog bot. **If `soul/` is empty, use a clear, direct, neutral voice** (drop the signature flourishes below). ## Config — all derived, nothing hardcoded ``` operator = gh api user --jq .login # the authenticated operator (PR-author search) product_handles = memory/products.md `handles:` lines (@x) # product X accounts to read flagship_repos = memory/products.md `repos:` tagged (public) # the star / north-star story watched_repos = memory/watched-repos.md, else products.md repos: # everything shipped across ecosystem_scouts= memory/products.md `scouts:` line (optional) # recap accounts to scan for features star_state = memory/state/shiplog-stars.json # snapshot for week-over-week star deltas ``` If neither `watched-repos.md` nor `products.md` yields a repo, exit `SHIPLOG_NO_REPOS` (notify + log, no article). Sections whose config is absent (X handles, scouts) are **skipped gracefully**, not failed. ## Steps ### 1. Compute the window — "since last run" ```bash STATE="memory/state/shiplog-last.json" NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ) TODAY=$(date -u +%Y-%m-%d) LAST="" [ -f "$STATE" ] && LAST=$(jq -r '.last_run_at // empty' "$STATE" 2>/dev/null) SINCE="${LAST:-$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)}" SINCE_DATE="${SINCE%%T*}" ``` - `since:YYYY-MM-DD` in `${var}` → `SINCE` = that date at `T00:00:00Z`; `days:N` → N days ago. These override the state file. - Use `$SINCE` for ALL time filtering — never substitute "since Monday" or other drift-prone shortcuts. The window is `[$SINCE, $NOW)`; state the span (`$SINCE_DATE → $TODAY`) in the output. - **Idempotency is the state file** (step 8 advances it each run, so windows never overlap). No once-per-day lock — a back-to-back re-run just yields an empty window → `SHIPLOG_NOTHING_NEW`. Write the digest to `output/articles/shiplog-${TODAY}.md`; if that name exists and there's genuinely new activity since the last run, use `output/articles/shiplog-${TODAY}-2.md` rather than clobbering. ### 2. GitHub activity (the bytes) Cross-repo PR/commit visibility needs the global token — the built-in `GITHUB_TOKEN` only sees this repo. Prefer `GH_GLOBAL` when set: ```bash GHT="${GH_GLOBAL:-$GITHUB_TOKEN}" # gh reads GH_TOKEN from env; falls back to the repo-scoped token OPERATOR=$(GH_TOKEN="$GHT" gh api user --jq .login 2>/dev/null) ``` Track success/failure per source in a `sources` map; on a single endpoint failure log `fail` and continue — never abort the whole skill. **a) Operator PRs across all repos in the window** (grouped by repo + totals): ```bash GH_TOKEN="$GHT" gh search prs --author "$OPERATOR" --created ">=$SINCE_DATE" \ --json number,title,repository,state,createdAt,url --limit 100 \ --jq 'group_by(.repository.nameWithOwner)[] | {repo: .[0].repository.nameWithOwner, count: length, prs: [.[] | {date: .createdAt[0:10], state, number, title}]}' ``` If 100 rows come back, note the result may be truncated. **b) Flagship headline numbers** — for each `flagship_repos` entry, count commits + merged PRs in the window (the numbers the audience cares about): ```bash for REPO in $FLAGSHIP_REPOS; do GH_TOKEN="$GHT" gh api "repos/${REPO}/commits" -X GET -f since="$SINCE" \ --jq "\"$REPO commits: \" + ([.[] | .sha] | length | tostring)" 2>/dev/null GH_TOKEN="$GHT" gh api "repos/${REPO}/pulls" -X GET -f state=closed -f sort=updated -f direction=desc \ --jq "\"$REPO merged PRs: \" + ([.[] | select(.merged_at != null and .merged_at > \"$SINCE\")] | length | tostring)" 2>/dev/null done ``` **c) The security flex** — PRs the operator landed in repos they do NOT own (the "a project merged a fix from us" candidates). Filter the Step-2a result to external repos whose title matches a security keyword (`security|ssrf|cve|credential|sandbox|escape|injection|vuln|redos|xss|toctou|path traversal|prototype pollution|deserial`). Merged ones are the marquee story — if it's a named org (not a random fork), that's a headline bullet. **d) Star delta** (north-star metric — flagships only, they're public): ```bash mkdir -p memory/state for REPO in $FLAGSHIP_REPOS; do GH_TOKEN="$GHT" gh api "repos/${REPO}" --jq '.stargazers_count' # current total for $REPO done ``` Read the prior snapshot `memory/state/shiplog-stars.json` (if present): `delta = current_total − last_total` per repo. After computing, overwrite the snapshot with `{ "<repo>": {"count": N, "date": "${TODAY}"}, ... }`. If no prior snapshot exists, report totals only and note "no baseline yet — deltas start next run." Do NOT fabricate a delta. ### 3. X activity (direct X.AI curl — primary) `XAI_API_KEY` is **injected into this skill's environment** (declared in `requires:`) and is the primary way to read X. **For each X source below the primary fetch is a direct `curl` to `https://api.x.ai/v1/responses` with `Authorization: Bearer {XAI_API_KEY}`**, using Grok's `x_search` tool. There is no network sandbox blocking this — just make the calls. **Check the key and give the call room first:** ```bash [ -n "$XAI_API_KEY" ] && echo KEY_PRESENT || echo KEY_UNSET ``` `x_search` runs a live X search and typically takes 30–120s. When you invoke the Bash tool for any curl below, **set the tool's `timeout` to at least 180000 (180s)**; each curl carries `--max-time 150` so it fails cleanly instead of hanging. **A slow curl is not a missing key — never treat a timeout as key-unavailable.** If `KEY_PRESENT` (it will be), Path A is required for every X source. There are two X sources here — the **operator** handle (`$OPERATOR_HANDLE`, the operator's own X account from `memory/products.md`) and the **product/project** accounts (`$PRODUCT_HANDLES`). Fetch each independently into its own tmp file so one failing source can't clobber or sink another. **Path A — X.AI API (primary).** *Operator posts* (`SRC=operator`): ```bash jq -n --arg h "$OPERATOR_HANDLE" --arg sd "$SINCE_DATE" --arg td "$TODAY" '{model:"grok-4.6", input:[{role:"user", content:("Search X for posts by @" + $h + " between " + $sd + " and " + $td + ". Return each post with full text, date, type (original|reply|RT — an RT text starts with \"RT @\"), exact engagement counts (likes, retweets, replies; 0 if unknown), and the direct link https://x.com/" + $h + "/status/ID. Return chronological.")}], tools:[{type:"x_search"}]}' > /tmp/xai-shiplog-operator-payload.json HTTP=$(./secretcurl -s -o /tmp/xai-shiplog-operator.json -w '%{http_code}' --max-time 150 -X POST "https://api.x.ai/v1/responses" \ -H "Content-Type: application/json" -H "Authorization: Bearer {XAI_API_KEY}" -d @/tmp/xai-shiplog-operator-payload.json) echo "xai http=$HTTP bytes=$(wc -c </tmp/xai-shiplog-operator.json)" ``` *Product/project accounts* (`SRC=projects`): ```bash jq -n --arg sd "$SINCE_DATE" --arg td "$TODAY" --arg ph "$PRODUCT_HANDLES" '{model:"grok-4.6", input:[{role:"user", content:("Search X for posts between " + $sd + " and " + $td + " from these accounts: " + $ph + ". Focus on launches, announcements, and any brag about a security fix merged into another project. For each: @handle, full text, date, exact engagement counts (likes, retweets, replies; 0 if unknown), and the direct link https://x.com/handle/status/ID. Skip retweets of others.")}], tools:[{type:"x_search"}]}' > /tmp/xai-shiplog-projects-payload.json HTTP=$(./secretcurl -s -o /tmp/xai-shiplog-projects.json -w '%{http_code}' --max-time 150 -X POST "https://api.x.ai/v1/responses" \ -H "Content-Type: application/json" -H "Authorization: Bearer {XAI_API_KEY}" -d @/tmp/xai-shiplog-projects-payload.json) echo "xai http=$HTTP bytes=$(wc -c </tmp/xai-shiplog-projects.json)" ``` For each source, on `HTTP=200` with a non-empty body, parse that source's file with the standard extractor and mark `x_source=api`: ```bash jq -r '.output[] | select(.type == "message") | .content[] | select(.type == "output_text") | .text' /tmp/xai-shiplog-<SRC>.json ``` From the **operator** text, separate **original posts** from **RTs** (RT text starts with `RT @`) — RTs are amplification, not ships. From the **projects** text, note the bangers (sort by likes/views) — one or two feed the digest's narrative section. **On a real failure, skip that source — never fabricate posts.** If a source's curl returns non-200, an empty/unparseable body, or times out, record the **true reason** for that source and continue with whatever other sources succeeded. Reason codes: `key-unset` (only if the check above printed `KEY_UNSET`), `http-<code>` (non-2xx), `empty` (200 but no posts parsed), `timeout` (exceeded `--max-time`). Never write "XAI_API_KEY unavailable" when the key was set. **Path B — WebFetch last resort (per source, optional).** Only if a source's Path A failed for one of the real reasons above: WebFetch that source's public `https://x.com/<handle>` profile(s) — no auth — and mark that source `x_source=webfetch` (lower quality; prefer posts inside the window). If every X source fails both paths, set `x_source=none` and write the GitHub-only shiplog (note the gap) — **never abort**. ### 4. Ecosystem + traction sweep (best-effort — skip gracefully) - **Ecosystem mentions** — only if `ecosystem_scouts` (`scouts:`) is configured. Fetch with the same **Path A** X.AI curl as Step 3, into its own tmp file (`SRC=ecosystem`): ```bash jq -n --arg sd "$SINCE_DATE" --arg td "$TODAY" --arg es "$ECOSYSTEM_SCOUTS" --arg ph "$PRODUCT_HANDLES" '{model:"grok-4.6", input:[{role:"user", content:("Search X between " + $sd + " and " + $td + " for posts from these recap/scout accounts: " + $es + " that mention any of these products: " + $ph + ". Return each mention with @handle, follower_count, full text, date, and the direct link https://x.com/handle/status/ID — recaps, rankings, partner shares.")}], tools:[{type:"x_search"}]}' > /tmp/xai-shiplog-ecosystem-payload.json HTTP=$(./secretcurl -s -o /tmp/xai-shiplog-ecosystem.json -w '%{http_code}' --max-time 150 -X POST "https://api.x.ai/v1/responses" \ -H "Content-Type: application/json" -H "Authorization: Bearer {XAI_API_KEY}" -d @/tmp/xai-shiplog-ecosystem-payload.json) echo "xai http=$HTTP bytes=$(wc -c </tmp/xai-shiplog-ecosystem.json)" ``` On `HTTP=200` + non-empty, parse `/tmp/xai-shiplog-ecosystem.json` with the standard extractor. On a real curl failure (`http-<code>` / `empty` / `timeout`, or `key-unset`) skip this source with the true reason — **never fabricate a mention**. Confirm any handle is real before @-mentioning (a wrong tag in a public post is worse than none). Capture follower counts for the flex ("featured by @X (Nk)"). Skip entirely if no `scouts:` configured. - **Product traction** (OpenRouter / x402 / analytics) — only if a source is configured for the product. If you have an app/server id, WebFetch its page; otherwise say "no product-traction sources wired yet" and move on. Keep any number exactly as measured — don't round 79 → ~80.
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub