@xiaotianxt/skills 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EXCLUDED.md +42 -0
- package/LICENSE +21 -0
- package/README.md +165 -0
- package/SECURITY.md +23 -0
- package/SOURCES.md +45 -0
- package/bin/skills.mjs +241 -0
- package/package.json +38 -0
- package/skills/1password/SKILL.md +94 -0
- package/skills/1password/agents/openai.yaml +4 -0
- package/skills/1password/references/item-management.md +80 -0
- package/skills/1password/references/op-cli.md +107 -0
- package/skills/apple-calendar-event/SKILL.md +81 -0
- package/skills/apple-calendar-event/agents/openai.yaml +4 -0
- package/skills/apple-calendar-event/scripts/calendar_audit.py +201 -0
- package/skills/apple-calendar-event/scripts/calendar_event.py +164 -0
- package/skills/bro-browser/SKILL.md +118 -0
- package/skills/bro-browser/agents/openai.yaml +4 -0
- package/skills/bro-browser/references/tool-map.md +102 -0
- package/skills/bro-browser/references/workflows.md +146 -0
- package/skills/bro-browser/scripts/bro-call.mjs +189 -0
- package/skills/calendar/SKILL.md +182 -0
- package/skills/calendar/agents/openai.yaml +4 -0
- package/skills/calendar/references/operations.md +255 -0
- package/skills/calendar/scripts/calendar_list_review.py +157 -0
- package/skills/calendar/scripts/event_dedupe_preview.py +155 -0
- package/skills/canvas/SKILL.md +70 -0
- package/skills/canvas/agents/openai.yaml +4 -0
- package/skills/canvas/references/canvas-api.md +76 -0
- package/skills/course-exam-review-planner/SKILL.md +127 -0
- package/skills/cx/SKILL.md +25 -0
- package/skills/gh-fix-ci/LICENSE.txt +201 -0
- package/skills/gh-fix-ci/SKILL.md +81 -0
- package/skills/gh-fix-ci/agents/openai.yaml +6 -0
- package/skills/gh-fix-ci/assets/github-small.svg +3 -0
- package/skills/gh-fix-ci/assets/github.png +0 -0
- package/skills/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
- package/skills/gh-review-workflow/SKILL.md +61 -0
- package/skills/gh-review-workflow/agents/openai.yaml +4 -0
- package/skills/gh-review-workflow/references/workflow.md +48 -0
- package/skills/gh-review-workflow/scripts/fetch_review_state.py +222 -0
- package/skills/gh-review-workflow/scripts/resolve_review_threads.py +83 -0
- package/skills/github/SKILL.md +74 -0
- package/skills/github/agents/openai.yaml +6 -0
- package/skills/github/assets/github-small.svg +3 -0
- package/skills/github/assets/github.png +0 -0
- package/skills/gws-calendar/SKILL.md +126 -0
- package/skills/gws-calendar-agenda/SKILL.md +52 -0
- package/skills/gws-calendar-insert/SKILL.md +66 -0
- package/skills/gws-docs/SKILL.md +48 -0
- package/skills/gws-docs-write/SKILL.md +49 -0
- package/skills/gws-drive/SKILL.md +137 -0
- package/skills/gws-drive-upload/SKILL.md +52 -0
- package/skills/gws-gmail/SKILL.md +62 -0
- package/skills/gws-gmail-forward/SKILL.md +55 -0
- package/skills/gws-gmail-reply/SKILL.md +58 -0
- package/skills/gws-gmail-reply-all/SKILL.md +62 -0
- package/skills/gws-gmail-send/SKILL.md +57 -0
- package/skills/gws-gmail-triage/SKILL.md +50 -0
- package/skills/gws-gmail-watch/SKILL.md +58 -0
- package/skills/gws-shared/SKILL.md +27 -0
- package/skills/helium-browser-mcp/SKILL.md +137 -0
- package/skills/helium-browser-mcp/agents/openai.yaml +4 -0
- package/skills/helium-browser-mcp/scripts/obmcp.mjs +92 -0
- package/skills/helium-browser-mcp/scripts/openbrowsermcp-stdio-proxy.mjs +170 -0
- package/skills/learn/SKILL.md +122 -0
- package/skills/learn/agents/openai.yaml +7 -0
- package/skills/learn/assets/AGENTS.template.md +33 -0
- package/skills/learn/assets/errorlog.template.typ +61 -0
- package/skills/learn/assets/reading-sequence.template.md +23 -0
- package/skills/learn/assets/source-index.template.md +17 -0
- package/skills/learn/assets/tasklog.template.typ +57 -0
- package/skills/learn/assets/workbook.template.typ +60 -0
- package/skills/learn/references/learning-science.md +103 -0
- package/skills/learn/scripts/init_learning_workspace.py +70 -0
- package/skills/macos-messages/SKILL.md +258 -0
- package/skills/memory/SKILL.md +33 -0
- package/skills/memory/codex.md +186 -0
- package/skills/memory/opencode.md +164 -0
- package/skills/mimestreamctl/SKILL.md +170 -0
- package/skills/mimestreamctl/agents/openai.yaml +4 -0
- package/skills/mimestreamctl/scripts/mimestreamctl +33 -0
- package/skills/mon/SKILL.md +51 -0
- package/skills/mon/scripts/mon_spend_review.py +458 -0
- package/skills/ocr/SKILL.md +136 -0
- package/skills/ocr/agents/openai.yaml +4 -0
- package/skills/ocr/references/local-ocr-best-practices.md +297 -0
- package/skills/ocr/references/mineru-api.md +159 -0
- package/skills/ocr/scripts/ocr-router +22 -0
- package/skills/ocr/scripts/ocr_router.py +741 -0
- package/skills/panopto-mp4-bulk-download/SKILL.md +57 -0
- package/skills/panopto-mp4-bulk-download/agents/openai.yaml +4 -0
- package/skills/panopto-mp4-bulk-download/references/url-patterns.md +26 -0
- package/skills/panopto-mp4-bulk-download/scripts/panopto_bulk_mp4.sh +213 -0
- package/skills/rust-systems-style/SKILL.md +109 -0
- package/skills/rust-systems-style/agents/openai.yaml +4 -0
- package/skills/rust-systems-style/references/rust-review-checklist.md +77 -0
- package/skills/rust-systems-style/references/style-sources.md +68 -0
- package/skills/ship-ai-native-cli/SKILL.md +76 -0
- package/skills/ship-ai-native-cli/agents/openai.yaml +4 -0
- package/skills/ship-ai-native-cli/references/case-notes.md +83 -0
- package/skills/ship-ai-native-cli/references/product-method.md +82 -0
- package/skills/ship-ai-native-cli/references/release-checklist.md +147 -0
- package/skills/ship-ai-native-cli/references/rust-cli-shape.md +111 -0
- package/skills/telegram-mtproto-session/SKILL.md +125 -0
- package/skills/telegram-mtproto-session/agents/openai.yaml +4 -0
- package/skills/telegram-mtproto-session/scripts/telegram_session.py +687 -0
- package/skills/tg/SKILL.md +173 -0
- package/skills/things3-manager/SKILL.md +116 -0
- package/skills/things3-manager/scripts/things +42 -0
- package/skills/things3-manager/scripts/things_cli.py +514 -0
- package/skills/web-artifacts-builder/LICENSE.txt +202 -0
- package/skills/web-artifacts-builder/SKILL.md +74 -0
- package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +379 -0
- package/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/skills/yeet/LICENSE.txt +201 -0
- package/skills/yeet/SKILL.md +71 -0
- package/skills/yeet/agents/openai.yaml +6 -0
- package/skills/yeet/assets/yeet-small.svg +3 -0
- package/skills/yeet/assets/yeet.png +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: panopto-mp4-bulk-download
|
|
3
|
+
description: Extract real downloadable mp4 URLs from Panopto and similar HLS lecture players, then batch-download all lectures with manifests and retry logic. Use when users ask to download many class videos from a logged-in Panopto folder, to automate IDM-style URL discovery, or to derive fragmented.mp4 links from Viewer pages.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Panopto MP4 Bulk Download
|
|
7
|
+
|
|
8
|
+
## Use This Workflow
|
|
9
|
+
|
|
10
|
+
1. Ensure the user is already logged into Panopto in `agent-browser`.
|
|
11
|
+
2. Use a headed persistent session (`~/.agent-browser-session`).
|
|
12
|
+
3. Pass the folder list URL to the bundled script.
|
|
13
|
+
|
|
14
|
+
## Run The Bundled Script
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
scripts/panopto_bulk_mp4.sh "<panopto-folder-list-url>" "<output-dir>" "<manifest-dir>"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
scripts/panopto_bulk_mp4.sh \
|
|
24
|
+
"https://scs.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?...#folderID=%22...%22" \
|
|
25
|
+
"downloads/panopto_mp4" \
|
|
26
|
+
"downloads/panopto_manifests"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## What The Script Does
|
|
30
|
+
|
|
31
|
+
1. Open the folder list page in `agent-browser`.
|
|
32
|
+
2. Extract all lecture `Viewer.aspx?id=...` links.
|
|
33
|
+
3. Open each lecture page and click Play.
|
|
34
|
+
4. Read browser `performance` entries to capture media URLs.
|
|
35
|
+
5. Prefer `/fragmented.mp4`; if absent, derive it from `/index.m3u8`.
|
|
36
|
+
6. Download all videos with `curl -L` retries.
|
|
37
|
+
7. Write manifests and failure reports.
|
|
38
|
+
|
|
39
|
+
## Required Behavior During Manual Automation
|
|
40
|
+
|
|
41
|
+
1. For every `agent-browser open`, always use `--headed --session <name>`.
|
|
42
|
+
2. If `open` fails, immediately run:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
agent-browser --session <name> close
|
|
46
|
+
agent-browser --headed --session <name> open <url>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Outputs
|
|
50
|
+
|
|
51
|
+
- `lecture_mp4_manifest.tsv`: lecture metadata and extracted mp4 URLs
|
|
52
|
+
- `extract_failed.txt`: lecture pages where URL extraction failed
|
|
53
|
+
- `download_failed.txt`: downloads that failed after retries
|
|
54
|
+
|
|
55
|
+
## References
|
|
56
|
+
|
|
57
|
+
- URL patterns and quick JS snippets: `references/url-patterns.md`
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# URL Patterns
|
|
2
|
+
|
|
3
|
+
## Panopto viewer page
|
|
4
|
+
|
|
5
|
+
- `https://<tenant>/Panopto/Pages/Viewer.aspx?id=<delivery-id>`
|
|
6
|
+
|
|
7
|
+
## Common media URLs discovered at runtime
|
|
8
|
+
|
|
9
|
+
- Master playlist:
|
|
10
|
+
- `https://...cloudfront.net/sessions/<session-id>/<delivery-id>-<stream-guid>.hls/master.m3u8?...`
|
|
11
|
+
- Rendition playlist:
|
|
12
|
+
- `https://...cloudfront.net/sessions/<session-id>/<delivery-id>-<stream-guid>.hls/<bitrate>/index.m3u8`
|
|
13
|
+
- Direct MP4 segment file (preferred for direct download):
|
|
14
|
+
- `https://...cloudfront.net/sessions/<session-id>/<delivery-id>-<stream-guid>.hls/<bitrate>/fragmented.mp4`
|
|
15
|
+
|
|
16
|
+
## Runtime extraction snippet (in browser context)
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
const names = performance.getEntriesByType('resource').map(e => e.name);
|
|
20
|
+
const mp4 = [...new Set(names.filter(u => /\/fragmented\.mp4(\?|$)/i.test(u)))];
|
|
21
|
+
const m3u8 = [...new Set(names.filter(u => /\/index\.m3u8(\?|$)/i.test(u)))];
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If no direct mp4 is found but `index.m3u8` exists, derive:
|
|
25
|
+
|
|
26
|
+
- `.../index.m3u8` -> `.../fragmented.mp4`
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
scripts/panopto_bulk_mp4.sh "<panopto-folder-list-url>" [output-dir] [manifest-dir]
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
scripts/panopto_bulk_mp4.sh \
|
|
11
|
+
"https://scs.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?...#folderID=%22...%22" \
|
|
12
|
+
downloads/panopto_mp4 \
|
|
13
|
+
downloads/panopto_manifests
|
|
14
|
+
USAGE
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if ! command -v agent-browser >/dev/null 2>&1; then
|
|
18
|
+
echo "agent-browser is required but not installed." >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
22
|
+
echo "jq is required but not installed." >&2
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
if ! command -v curl >/dev/null 2>&1; then
|
|
26
|
+
echo "curl is required but not installed." >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
FOLDER_URL="${1:-}"
|
|
31
|
+
OUT_DIR="${2:-downloads/panopto_mp4}"
|
|
32
|
+
MANIFEST_DIR="${3:-downloads/panopto_manifests}"
|
|
33
|
+
|
|
34
|
+
if [[ -z "$FOLDER_URL" ]]; then
|
|
35
|
+
usage
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
SESSION_FILE="${SESSION_FILE:-$HOME/.agent-browser-session}"
|
|
40
|
+
DEFAULT_SESSION="visual"
|
|
41
|
+
if [[ ! -f "$SESSION_FILE" ]]; then
|
|
42
|
+
printf '%s\n' "$DEFAULT_SESSION" > "$SESSION_FILE"
|
|
43
|
+
fi
|
|
44
|
+
SESSION="$(tr -d '[:space:]' < "$SESSION_FILE")"
|
|
45
|
+
if [[ -z "$SESSION" ]]; then
|
|
46
|
+
SESSION="$DEFAULT_SESSION"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
mkdir -p "$OUT_DIR" "$MANIFEST_DIR"
|
|
50
|
+
|
|
51
|
+
LECTURES_RAW="$MANIFEST_DIR/lectures_raw.json"
|
|
52
|
+
LECTURES_JSON="$MANIFEST_DIR/lectures.json"
|
|
53
|
+
MANIFEST_TSV="$MANIFEST_DIR/lecture_mp4_manifest.tsv"
|
|
54
|
+
EXTRACT_FAILS="$MANIFEST_DIR/extract_failed.txt"
|
|
55
|
+
DOWNLOAD_FAILS="$MANIFEST_DIR/download_failed.txt"
|
|
56
|
+
|
|
57
|
+
open_page() {
|
|
58
|
+
local url="$1"
|
|
59
|
+
|
|
60
|
+
if agent-browser --headed --session "$SESSION" open "$url" >/dev/null 2>&1; then
|
|
61
|
+
return 0
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Required fallback when open fails.
|
|
65
|
+
agent-browser --session "$SESSION" close >/dev/null 2>&1 || true
|
|
66
|
+
agent-browser --headed --session "$SESSION" open "$url" >/dev/null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
extract_mp4_url() {
|
|
70
|
+
local raw="" parsed=""
|
|
71
|
+
|
|
72
|
+
agent-browser --session "$SESSION" eval '(()=>{const sels=["button[aria-label=\"Play\"]","button[title=\"Play\"]","button.vjs-play-control","button[aria-label*=\"Play\"]"];for(const s of sels){const b=document.querySelector(s);if(b){b.click();return "clicked";}}return "no-play-button";})()' >/dev/null 2>&1 || true
|
|
73
|
+
agent-browser --session "$SESSION" wait 4500 >/dev/null || true
|
|
74
|
+
|
|
75
|
+
raw="$(agent-browser --session "$SESSION" eval --stdin <<'EVALEOF'
|
|
76
|
+
(() => {
|
|
77
|
+
const names = performance.getEntriesByType('resource').map(e => e.name);
|
|
78
|
+
const mp4 = [...new Set(names.filter(u => /\/fragmented\.mp4(\?|$)/i.test(u)))];
|
|
79
|
+
if (mp4.length) return mp4[0];
|
|
80
|
+
|
|
81
|
+
const m3u8 = [...new Set(names.filter(u => /\/index\.m3u8(\?|$)/i.test(u)))];
|
|
82
|
+
if (m3u8.length) return m3u8[0].replace(/\/index\.m3u8(\?.*)?$/i, '/fragmented.mp4');
|
|
83
|
+
|
|
84
|
+
return "";
|
|
85
|
+
})()
|
|
86
|
+
EVALEOF
|
|
87
|
+
)" || true
|
|
88
|
+
|
|
89
|
+
parsed="$(printf '%s' "$raw" | jq -r . 2>/dev/null || true)"
|
|
90
|
+
if [[ "$parsed" == "null" ]]; then
|
|
91
|
+
parsed=""
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
printf '%s' "$parsed"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
echo "Using session: $SESSION"
|
|
98
|
+
echo "Folder URL: $FOLDER_URL"
|
|
99
|
+
|
|
100
|
+
open_page "$FOLDER_URL"
|
|
101
|
+
agent-browser --session "$SESSION" wait 4000 >/dev/null || true
|
|
102
|
+
|
|
103
|
+
agent-browser --session "$SESSION" eval --stdin <<'EVALEOF' > "$LECTURES_RAW"
|
|
104
|
+
(() => {
|
|
105
|
+
const rows = [...document.querySelectorAll('a.detail-title[href*="Viewer.aspx?id="]')]
|
|
106
|
+
.map(a => ({
|
|
107
|
+
title: (a.textContent || '').trim().replace(/\s+/g, ' '),
|
|
108
|
+
viewer: a.href,
|
|
109
|
+
id: (a.href.match(/[?&]id=([0-9a-f-]+)/i) || [])[1] || null
|
|
110
|
+
}))
|
|
111
|
+
.filter(x => /^Lecture\s+\d+/i.test(x.title));
|
|
112
|
+
|
|
113
|
+
const uniq = [];
|
|
114
|
+
const seen = new Set();
|
|
115
|
+
for (const row of rows) {
|
|
116
|
+
if (!row.id || seen.has(row.id)) continue;
|
|
117
|
+
seen.add(row.id);
|
|
118
|
+
uniq.push(row);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
uniq.sort((a, b) => {
|
|
122
|
+
const na = parseInt((a.title.match(/^Lecture\s+(\d+)/i) || [])[1] || '0', 10);
|
|
123
|
+
const nb = parseInt((b.title.match(/^Lecture\s+(\d+)/i) || [])[1] || '0', 10);
|
|
124
|
+
return na - nb;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return JSON.stringify(uniq, null, 2);
|
|
128
|
+
})()
|
|
129
|
+
EVALEOF
|
|
130
|
+
|
|
131
|
+
jq -r . "$LECTURES_RAW" > "$LECTURES_JSON"
|
|
132
|
+
TOTAL="$(jq 'length' "$LECTURES_JSON")"
|
|
133
|
+
|
|
134
|
+
if [[ "$TOTAL" -eq 0 ]]; then
|
|
135
|
+
echo "No lecture rows found." >&2
|
|
136
|
+
exit 2
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
printf 'index\ttitle\tid\tviewer\tmp4\tfile\n' > "$MANIFEST_TSV"
|
|
140
|
+
: > "$EXTRACT_FAILS"
|
|
141
|
+
: > "$DOWNLOAD_FAILS"
|
|
142
|
+
|
|
143
|
+
for ((i=0; i<TOTAL; i++)); do
|
|
144
|
+
title="$(jq -r ".[$i].title" "$LECTURES_JSON")"
|
|
145
|
+
viewer="$(jq -r ".[$i].viewer" "$LECTURES_JSON")"
|
|
146
|
+
id="$(jq -r ".[$i].id" "$LECTURES_JSON")"
|
|
147
|
+
|
|
148
|
+
printf '[%d/%d] Extracting: %s\n' "$((i+1))" "$TOTAL" "$title"
|
|
149
|
+
|
|
150
|
+
open_page "$viewer"
|
|
151
|
+
agent-browser --session "$SESSION" wait 3500 >/dev/null || true
|
|
152
|
+
|
|
153
|
+
mp4_url="$(extract_mp4_url)"
|
|
154
|
+
if [[ -z "$mp4_url" ]]; then
|
|
155
|
+
agent-browser --session "$SESSION" wait 3000 >/dev/null || true
|
|
156
|
+
mp4_url="$(extract_mp4_url)"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
safe_title="$(printf '%s' "$title" | sed 's#[/:*?"<>|]#_#g; s/[[:space:]]\+/ /g')"
|
|
160
|
+
out_file="$OUT_DIR/${safe_title}.mp4"
|
|
161
|
+
|
|
162
|
+
if [[ -z "$mp4_url" ]]; then
|
|
163
|
+
printf '%s\t%s\t%s\n' "$id" "$title" "$viewer" >> "$EXTRACT_FAILS"
|
|
164
|
+
printf '[%d/%d] FAIL extract: %s\n' "$((i+1))" "$TOTAL" "$title"
|
|
165
|
+
continue
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
printf '%s\t%s\t%s\t%s\t%s\t%s\n' \
|
|
169
|
+
"$((i+1))" "$title" "$id" "$viewer" "$mp4_url" "$out_file" >> "$MANIFEST_TSV"
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
FOUND="$(($(wc -l < "$MANIFEST_TSV") - 1))"
|
|
173
|
+
echo "Extraction complete: $FOUND/$TOTAL URLs found"
|
|
174
|
+
|
|
175
|
+
if [[ "$FOUND" -eq 0 ]]; then
|
|
176
|
+
echo "No mp4 URLs extracted." >&2
|
|
177
|
+
exit 3
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
ok=0
|
|
181
|
+
fail=0
|
|
182
|
+
while IFS=$'\t' read -r idx title id viewer mp4_url out_file; do
|
|
183
|
+
if [[ "$idx" == "index" ]]; then
|
|
184
|
+
continue
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
if [[ -s "$out_file" ]]; then
|
|
188
|
+
printf '[%s/%s] SKIP existing: %s\n' "$idx" "$FOUND" "$out_file"
|
|
189
|
+
ok=$((ok + 1))
|
|
190
|
+
continue
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
mkdir -p "$(dirname "$out_file")"
|
|
194
|
+
printf '[%s/%s] Downloading: %s\n' "$idx" "$FOUND" "$title"
|
|
195
|
+
|
|
196
|
+
if curl -L --retry 4 --retry-delay 2 --connect-timeout 20 --max-time 0 -o "$out_file" "$mp4_url"; then
|
|
197
|
+
ok=$((ok + 1))
|
|
198
|
+
else
|
|
199
|
+
rm -f "$out_file"
|
|
200
|
+
printf '%s\t%s\t%s\n' "$title" "$mp4_url" "$out_file" >> "$DOWNLOAD_FAILS"
|
|
201
|
+
fail=$((fail + 1))
|
|
202
|
+
fi
|
|
203
|
+
done < "$MANIFEST_TSV"
|
|
204
|
+
|
|
205
|
+
echo "Done. Success=$ok Failed=$fail"
|
|
206
|
+
echo "Output: $OUT_DIR"
|
|
207
|
+
echo "Manifest: $MANIFEST_TSV"
|
|
208
|
+
echo "Extract fails: $EXTRACT_FAILS"
|
|
209
|
+
echo "Download fails: $DOWNLOAD_FAILS"
|
|
210
|
+
|
|
211
|
+
if [[ "$fail" -gt 0 ]]; then
|
|
212
|
+
exit 4
|
|
213
|
+
fi
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-systems-style
|
|
3
|
+
description: "Use when Codex is writing, editing, reviewing, or designing Rust systems code, Rust CLIs, async runtimes, FFI wrappers, unsafe abstractions, security-sensitive crates, local-first developer tools, or code style guidance for this user's Rust projects. Also use when a non-Rust engineering task would benefit from the same discipline: small APIs, explicit invariants, reviewable failure behavior, and conservative dependency/security choices."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rust Systems Style
|
|
7
|
+
|
|
8
|
+
Use this skill as an engineering governor, not a formatting checklist. The aim is code that can be read under pressure, reviewed locally, and trusted at the boundary where types, operating systems, networks, files, processes, and humans fail.
|
|
9
|
+
|
|
10
|
+
This is not a product-shipping workflow. When creating a new CLI product, use
|
|
11
|
+
`ship-ai-native-cli` for product scope and release shape, then apply this skill
|
|
12
|
+
continuously to the Rust and systems-code decisions.
|
|
13
|
+
|
|
14
|
+
## Operating Posture
|
|
15
|
+
|
|
16
|
+
Before editing, ask what must remain true after this change:
|
|
17
|
+
|
|
18
|
+
- Which invariant is being protected, moved, or newly introduced?
|
|
19
|
+
- Which failure is environmental, user-caused, adversarial, or impossible by construction?
|
|
20
|
+
- Which behavior is mechanism, and which behavior is policy?
|
|
21
|
+
- Which API surface will future callers have to live with?
|
|
22
|
+
- Which parts of the change are mechanical, and which parts change meaning?
|
|
23
|
+
|
|
24
|
+
Prefer the smallest change that makes these answers more local and easier to audit.
|
|
25
|
+
|
|
26
|
+
## Style Hierarchy
|
|
27
|
+
|
|
28
|
+
Follow local project style first, then this skill, then the primary sources in [style-sources.md](references/style-sources.md). Use `rustfmt` defaults unless the repository already has a different checked-in configuration.
|
|
29
|
+
|
|
30
|
+
When sources conflict, choose the rule that improves reviewability for the current repository. In this user's Rust CLI/tool projects, prefer:
|
|
31
|
+
|
|
32
|
+
- `rustfmt` formatting and explicit import grouping if the project already groups imports.
|
|
33
|
+
- Small modules with clear ownership over broad utility files.
|
|
34
|
+
- Mechanism separated from policy, especially around CLI behavior, retries, caching, logging, and FFI.
|
|
35
|
+
- Safe public APIs over exposing raw pointers, handles, unchecked states, or caller-managed invariants.
|
|
36
|
+
- Dependency restraint and local-first behavior when code touches private user data.
|
|
37
|
+
- Semantic boundaries over cosmetic boundaries: extract modules around domain ownership, invariants, and failure behavior rather than file size alone.
|
|
38
|
+
- Neutral internal vocabulary for sensitive local-first tools: confine upstream schema names, provider names, and raw protocol terminology to narrow adapter/dictionary layers when those names create privacy, security, or product-surface risk.
|
|
39
|
+
|
|
40
|
+
## Rust Rules
|
|
41
|
+
|
|
42
|
+
Design APIs so callers can do the right thing without remembering hidden rules:
|
|
43
|
+
|
|
44
|
+
- Use concrete domain types and newtypes when `bool`, `usize`, `String`, or `Option<T>` would hide meaning.
|
|
45
|
+
- Prefer `Result` for recoverable failure. Do not turn environmental failure into panic.
|
|
46
|
+
- Avoid `unwrap` and `expect` in production paths unless a local invariant makes failure impossible; leave a short comment for that invariant.
|
|
47
|
+
- Prefer parse/construct-once APIs that make invalid states unrepresentable over `validate` methods on already-invalid objects.
|
|
48
|
+
- Keep function arguments readable. Around six parameters is a design prompt for an options struct or a smaller responsibility.
|
|
49
|
+
- Put conversions on the most specific involved type. Use `From`, `TryFrom`, `AsRef`, and `AsMut` when they match the semantics.
|
|
50
|
+
- Keep public dependencies, features, re-exports, and configuration knobs small. Add a knob only when a caller genuinely needs policy control.
|
|
51
|
+
- Prefer exhaustive matches for closed enums. Use catch-all patterns only for intentionally open or `#[non_exhaustive]` types.
|
|
52
|
+
- Treat ignored results as a review event. Bind them with a type or name when discarding is intentional.
|
|
53
|
+
- Avoid storing derived state when a named method can compute the value from canonical fields. If the derived value is policy, name the policy explicitly.
|
|
54
|
+
- Keep debug tools out of the default shipped surface. Gate diagnostic binaries, verbose probes, and risky helpers behind explicit features or separate commands, and keep those features covered by CI.
|
|
55
|
+
|
|
56
|
+
For deeper Rust review, read [rust-review-checklist.md](references/rust-review-checklist.md).
|
|
57
|
+
|
|
58
|
+
## Layout And Path Types
|
|
59
|
+
|
|
60
|
+
For filesystem layout structs, store canonical roots or externally supplied
|
|
61
|
+
paths, not every derived child path. Prefer named methods such as `slots_dir()`,
|
|
62
|
+
`state_file()`, or `cache_path()` for paths computed from roots.
|
|
63
|
+
|
|
64
|
+
Treat repeated fixture updates, broad struct literal churn, or adding a new field
|
|
65
|
+
to many unrelated tests as a design warning. Before continuing, ask whether the
|
|
66
|
+
new value is canonical state, policy, or merely derived layout. Derived layout
|
|
67
|
+
belongs behind methods on the owning path type.
|
|
68
|
+
|
|
69
|
+
A path/layout type should keep topology local: callers may ask for named paths,
|
|
70
|
+
but should not need to know how the directory tree is assembled.
|
|
71
|
+
|
|
72
|
+
## Unsafe Rules
|
|
73
|
+
|
|
74
|
+
Unsafe code is a proof obligation. Write it so a reviewer can check the proof without reconstructing the whole program.
|
|
75
|
+
|
|
76
|
+
- Avoid `unsafe` unless it is needed for FFI/platform calls, a carefully designed abstraction, or measured performance.
|
|
77
|
+
- Keep unsafe operations localized. Prefer a small unsafe core behind a safe API that restores invariants before returning.
|
|
78
|
+
- Enable or honor `unsafe_op_in_unsafe_fn`; unsafe functions still need explicit unsafe blocks around unsafe operations.
|
|
79
|
+
- Put `// SAFETY:` immediately before every unsafe block or unsafe impl. Explain why each precondition is met, not merely that it is safe.
|
|
80
|
+
- Document every unsafe function or trait with a `# Safety` section explaining the caller or implementor contract.
|
|
81
|
+
- For performance-motivated unsafe, require a benchmark or a precise reason why safe code is unacceptable.
|
|
82
|
+
- Audit the whole module when changing code near unsafe, because safe-looking edits can break an unsafe invariant at a distance.
|
|
83
|
+
|
|
84
|
+
## Tests And Verification
|
|
85
|
+
|
|
86
|
+
Scale verification to the blast radius:
|
|
87
|
+
|
|
88
|
+
- Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` when the project supports them.
|
|
89
|
+
- Prefer `--all-features` in CI when optional features contain shipped, debug, or diagnostic code that should not bitrot.
|
|
90
|
+
- Add focused tests for new behavior, regression fixes, parsing boundaries, and user-visible CLI errors.
|
|
91
|
+
- For async/concurrency primitives, consider deterministic concurrency tests such as loom if the project already uses it.
|
|
92
|
+
- For unsafe or low-level parsing, consider Miri, fuzzing, property tests, or adversarial tests when practical.
|
|
93
|
+
- Keep tests readable top-to-bottom. Prefer Arrange-Act-Assert, explicit inputs and expected outputs, and separate tests for separate behaviors.
|
|
94
|
+
|
|
95
|
+
## Review Stance
|
|
96
|
+
|
|
97
|
+
When reviewing or editing, lead with bugs and risk:
|
|
98
|
+
|
|
99
|
+
- Hidden policy in low-level code.
|
|
100
|
+
- Silent fallback, ignored flags, swallowed errors, or logs that obscure what happened.
|
|
101
|
+
- Unbounded retries, timeouts without enforcement, or operations that can block destructors/drop paths.
|
|
102
|
+
- Public APIs that expose implementation details or force callers into unsafe usage.
|
|
103
|
+
- New dependencies whose maintenance, transitive code, unsafe usage, or license cost is not justified.
|
|
104
|
+
- Refactors mixed with behavior changes in a way that makes review harder.
|
|
105
|
+
- Source vocabulary leaks: names from private schemas, vendors, protocols, or internal file layouts spreading beyond the narrow layer that has to speak them.
|
|
106
|
+
- Default build and release surfaces that include exploratory tools, secret-printing diagnostics, or other code paths not intended for normal users.
|
|
107
|
+
- CI and release warnings with dated deadlines. Treat them as maintenance debt before the deadline turns into a broken release path.
|
|
108
|
+
|
|
109
|
+
Do not beautify code for its own sake. Improve code when the change makes ownership, invariants, failure, or review boundaries clearer.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Rust Review Checklist
|
|
2
|
+
|
|
3
|
+
Load this when doing a serious Rust implementation or review. It is intentionally phrased as questions because the right answer depends on the local codebase.
|
|
4
|
+
|
|
5
|
+
## Boundaries
|
|
6
|
+
|
|
7
|
+
- Does each module own one coherent concept?
|
|
8
|
+
- Is CLI or request handling limited to parsing, orchestration, presentation, and exit behavior?
|
|
9
|
+
- Are domain rules kept near the domain types that define them?
|
|
10
|
+
- Is policy separated from mechanism, especially in cache, retry, logging, networking, and FFI code?
|
|
11
|
+
- Are mechanical moves separated from behavior changes where review would benefit?
|
|
12
|
+
|
|
13
|
+
## API Shape
|
|
14
|
+
|
|
15
|
+
- Can callers discover the happy path from types and names?
|
|
16
|
+
- Does the function belong as a method on one of its arguments?
|
|
17
|
+
- Do arguments proceed from specific domain value to broader context?
|
|
18
|
+
- Would an options struct make call sites clearer?
|
|
19
|
+
- Do `bool`, `Option<T>`, integer, or string parameters deserve a domain enum/newtype?
|
|
20
|
+
- Are conversions expressed with standard traits where that is idiomatic?
|
|
21
|
+
- Are public structs protected against future field changes?
|
|
22
|
+
- Are enums intentionally exhaustive or intentionally open?
|
|
23
|
+
- Are re-exports limited to paved paths users actually need?
|
|
24
|
+
|
|
25
|
+
## Errors And Panics
|
|
26
|
+
|
|
27
|
+
- Is every recoverable environmental failure returned as `Result`?
|
|
28
|
+
- Is each error meaningful at the layer where it is emitted?
|
|
29
|
+
- Are errors wrapped with enough context without leaking sensitive data?
|
|
30
|
+
- Are panics limited to invariant violations, tests, or impossible states?
|
|
31
|
+
- If `unwrap` or `expect` remains in production code, is the invariant local and obvious?
|
|
32
|
+
- Are timeouts, cancellation, interruption, and partial writes handled where relevant?
|
|
33
|
+
- Are stdout, stderr, logs, and exit codes assigned consistently for CLI users and agents?
|
|
34
|
+
|
|
35
|
+
## Unsafe And FFI
|
|
36
|
+
|
|
37
|
+
- Is `unsafe` necessary, and is the reason documented?
|
|
38
|
+
- Is unsafe contained behind a safe abstraction that restores invariants?
|
|
39
|
+
- Does every `unsafe` block or `unsafe impl` have an adjacent `// SAFETY:` proof?
|
|
40
|
+
- Does every unsafe function or trait have a `# Safety` contract?
|
|
41
|
+
- Are raw pointers, FDs, handles, ownership transfer, aliasing, alignment, initialization, lifetimes, and thread-safety all accounted for?
|
|
42
|
+
- Are `Send`/`Sync` impls treated as global promises rather than local conveniences?
|
|
43
|
+
- Is FFI wrapped in a minimal, idiomatic Rust API?
|
|
44
|
+
- Were nearby safe changes reviewed for effects on unsafe invariants?
|
|
45
|
+
|
|
46
|
+
## Concurrency And Async
|
|
47
|
+
|
|
48
|
+
- Are shared states explicit about ownership and synchronization?
|
|
49
|
+
- Are cancellation and drop behavior understood?
|
|
50
|
+
- Can a lock be held across `.await` or a blocking call?
|
|
51
|
+
- Are retries bounded and observable?
|
|
52
|
+
- Does logging help diagnose races or timing without overwhelming production logs?
|
|
53
|
+
- Does the project need deterministic concurrency tests, loom, Miri, or fuzzing for this change?
|
|
54
|
+
|
|
55
|
+
## Tests
|
|
56
|
+
|
|
57
|
+
- Does each test name behavior and expected outcome?
|
|
58
|
+
- Can a reviewer read the test top-to-bottom without chasing critical helper behavior?
|
|
59
|
+
- Are edge cases chosen because they guard an invariant?
|
|
60
|
+
- Is a regression test tied to the bug's actual failure mode?
|
|
61
|
+
- Are public APIs covered at the level users consume them?
|
|
62
|
+
- Are examples and doctests succinct and correct when docs are part of the surface?
|
|
63
|
+
|
|
64
|
+
## Dependencies And Supply Chain
|
|
65
|
+
|
|
66
|
+
- Is the dependency necessary enough to justify its transitive code and maintenance cost?
|
|
67
|
+
- Does it introduce unsafe, native build steps, network behavior, crypto, or secret handling?
|
|
68
|
+
- Does the license fit the project?
|
|
69
|
+
- Can the standard library or an existing dependency solve the problem cleanly?
|
|
70
|
+
- Does adding a feature flag create a support matrix the project is ready to test?
|
|
71
|
+
|
|
72
|
+
## Final Pass
|
|
73
|
+
|
|
74
|
+
- Does the code reveal the invariant where it matters?
|
|
75
|
+
- Does it fail in a way the caller or operator can act on?
|
|
76
|
+
- Is the smallest risky region also the most heavily documented and tested?
|
|
77
|
+
- Would a future reviewer need less working memory after this change than before?
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Style Sources
|
|
2
|
+
|
|
3
|
+
This reference compresses the source documents behind the skill. Load it when you need to justify a rule, resolve a style conflict, or explain the taste behind a Rust systems-programming decision.
|
|
4
|
+
|
|
5
|
+
## Primary Sources
|
|
6
|
+
|
|
7
|
+
- Rust Style Guide: `rustfmt` defaults, 4-space indentation, 100-column line width, block indent over visual indent, trailing commas for multiline lists, line comments over block comments, doc comments before attributes.
|
|
8
|
+
- https://doc.rust-lang.org/style-guide/
|
|
9
|
+
- Rust API Guidelines: naming, conversions, common traits, error types, documentation, predictability, type safety, future-proofing, dependency/license expectations.
|
|
10
|
+
- https://rust-lang.github.io/api-guidelines/checklist.html
|
|
11
|
+
- Standard Library safety comments policy: every unsafe block needs `// SAFETY:`; unsafe functions need caller contracts in `# Safety`; `unsafe_op_in_unsafe_fn` makes unsafe operations locally reviewable.
|
|
12
|
+
- https://std-dev-guide.rust-lang.org/policy/safety-comments.html
|
|
13
|
+
- Rust for Linux coding guidelines: use rustfmt defaults, keep comments/doc comments Markdown-like, distinguish implementation comments from API docs, document panics and safety, prefer `expect` over `allow` for temporary lint suppressions when appropriate.
|
|
14
|
+
- https://docs.kernel.org/rust/coding-guidelines.html
|
|
15
|
+
- crosvm coding style: prefer mechanism over policy, security over reuse/speed, single-responsibility functions, avoid large argument lists and rightward drift, minimize unsafe, write standard safety statements, make unit tests readable.
|
|
16
|
+
- https://crosvm.dev/book/contributing/coding_style.html
|
|
17
|
+
- Firecracker contribution standards: separate logical changes, tests and style must pass, public functions need docs, unsafe is heavily discouraged, performance unsafe needs evidence, avoid `unwrap`/`expect` in production paths.
|
|
18
|
+
- https://github.com/firecracker-microvm/firecracker/blob/main/CONTRIBUTING.md
|
|
19
|
+
- Wasmtime coding guidelines: rustfmt in CI, warnings as errors, selective Clippy, all-target Clippy, MSRV awareness, dependency and safety discipline in a runtime/sandbox project.
|
|
20
|
+
- https://docs.wasmtime.dev/contributing-coding-guidelines.html
|
|
21
|
+
- Fuchsia Rust Rubric and Netstack Rust Patterns: reviewable code with less working memory, explicit ignored results, careful imports, exhaustive matches where possible, useful log severity, detailed unsafe justification.
|
|
22
|
+
- https://fuchsia.dev/fuchsia-src/development/api/rust
|
|
23
|
+
- https://fuchsia.dev/fuchsia-src/contribute/contributing-to-netstack/rust-patterns
|
|
24
|
+
- Chromium Rust style, API design, and unsafe policy: follow Rust style/API guidelines, APIs must be usable and minimize misuse, safe API around FFI, unsafe changes need specialized review, dependencies need audit attention.
|
|
25
|
+
- https://chromium.googlesource.com/chromium/src/+/main/styleguide/rust/rust.md
|
|
26
|
+
- https://chromium.googlesource.com/chromium/src/+/main/docs/rust/api_design.md
|
|
27
|
+
- https://chromium.googlesource.com/chromium/src/+/refs/tags/135.0.7018.2/docs/rust-unsafe.md
|
|
28
|
+
- rustls contributing guide: clean commit history, top-down module ordering, type-local methods, parse-don't-validate, error handling over panics, safe defaults, small mandatory API, separate mechanism and policy.
|
|
29
|
+
- https://github.com/rustls/rustls/blob/main/CONTRIBUTING.md
|
|
30
|
+
- Tokio contributing guide: feature-aware build/test commands, docs.rs-equivalent docs, integration/doc/fuzz tests, Miri and loom for relevant low-level async changes, logical commits.
|
|
31
|
+
- https://github.com/tokio-rs/tokio/blob/master/docs/contributing/pull-requests.md
|
|
32
|
+
- Android Rust docs: Rust is used for native OS components; value expressive types, mandatory error handling, explicit integer conversions, initialization, platform lint sets, and clippy in Android builds.
|
|
33
|
+
- https://source.android.com/docs/setup/build/rust/building-rust-modules/overview
|
|
34
|
+
- https://source.android.com/docs/setup/build/rust/building-rust-modules/android-rust-modules
|
|
35
|
+
- PingCAP/TiKV style guide: Rustfmt/Clippy, Rust conventions even near FFI/protobuf boundaries, careful modules/data structures/traits/error/performance guidance, benchmark-backed unsafe performance choices.
|
|
36
|
+
- https://pingcap.github.io/style-guide/rust/
|
|
37
|
+
- https://pingcap.github.io/style-guide/rust/unsafe.html
|
|
38
|
+
- Ferrocene Safety Manual, handling unsafety: localize unsafety, keep unsafe modules single-purpose, use assertions/preconditions/postconditions/invariants, review the whole module, test unsafe code and clients.
|
|
39
|
+
- https://public-docs.ferrocene.dev/main/safety-manual/rustc/unsafety.html
|
|
40
|
+
|
|
41
|
+
## Compressed Taste
|
|
42
|
+
|
|
43
|
+
The strongest documents converge on one idea: style is a way of lowering audit cost.
|
|
44
|
+
|
|
45
|
+
- Formatting exists to remove argument and conserve attention.
|
|
46
|
+
- Names should reveal domain meaning, not implementation convenience.
|
|
47
|
+
- APIs should make illegal states hard to express and dangerous states visibly named.
|
|
48
|
+
- Failure should be explicit at the boundary where it can be handled.
|
|
49
|
+
- Unsafe code should read like a proof with a small trusted base.
|
|
50
|
+
- Tests should be executable explanations of behavior, not only coverage counters.
|
|
51
|
+
- Dependencies are part of the codebase's risk surface.
|
|
52
|
+
- Local style matters because rhythm helps readers notice semantic anomalies.
|
|
53
|
+
|
|
54
|
+
## Conflict Resolution
|
|
55
|
+
|
|
56
|
+
Use this order when documents disagree:
|
|
57
|
+
|
|
58
|
+
1. Repository style and existing automated checks.
|
|
59
|
+
2. Safety/security/reviewability.
|
|
60
|
+
3. Public API compatibility.
|
|
61
|
+
4. Rust ecosystem conventions.
|
|
62
|
+
5. Personal preference.
|
|
63
|
+
|
|
64
|
+
Examples:
|
|
65
|
+
|
|
66
|
+
- crosvm prefers one imported item per `use`; Fuchsia groups imports by crate/direct child module. Follow the repository's established import style and keep provenance obvious.
|
|
67
|
+
- Some projects avoid Clippy's default set as too noisy; others require `-D warnings`. Run the project's configured command first. Add stricter Clippy only when it is already expected or the user asks for governance cleanup.
|
|
68
|
+
- Some documents prefer exhaustive matches, while open extensible types need catch-all handling. Match exhaustively for closed local enums; use catch-all for `#[non_exhaustive]` or protocol types designed to evolve.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ship-ai-native-cli
|
|
3
|
+
description: Use when Codex should turn a local pain point, repeated workflow, API wrapper, or automation idea into a small shippable AI-native CLI product, especially a Rust CLI with GitHub repository, CI, release automation, Homebrew formula, install command, README, architecture docs, and optional Codex skill integration. Trigger for requests like "make this into a tool", "create a ~/dev project like tg/cx/mon", "ship a CLI product", "wrap this API for agents", "add Homebrew/GitHub release", or "abstract this workflow into a reusable developer product".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Ship AI-Native CLI
|
|
7
|
+
|
|
8
|
+
Use this skill to convert a concrete workflow into a small product, not a pile
|
|
9
|
+
of scripts. The pattern is distilled from `~/dev/tg`, `~/dev/cx`, `~/dev/mon`,
|
|
10
|
+
their release history, and the Codex sessions that shaped them.
|
|
11
|
+
|
|
12
|
+
This is a product-workflow skill. When the product is Rust or systems-facing,
|
|
13
|
+
use `rust-systems-style` as the engineering governor rather than expanding Rust
|
|
14
|
+
style rules here.
|
|
15
|
+
|
|
16
|
+
## Operating Rule
|
|
17
|
+
|
|
18
|
+
Before coding, identify the product boundary:
|
|
19
|
+
|
|
20
|
+
- **User job**: the thing the user wants done in one command.
|
|
21
|
+
- **Primary commands**: the smallest stable surface that satisfies that job.
|
|
22
|
+
- **Agent contract**: JSON output, deterministic errors, no secret leakage.
|
|
23
|
+
- **Non-goals**: domain-specific workflows that should live outside the generic tool.
|
|
24
|
+
- **Ship target**: local install, GitHub repo, release asset, Homebrew formula.
|
|
25
|
+
|
|
26
|
+
If the user asks for a `tg`/`cx`/`mon`-style product, default to a Rust CLI with
|
|
27
|
+
the release shape in [rust-cli-shape.md](references/rust-cli-shape.md).
|
|
28
|
+
|
|
29
|
+
## Workflow
|
|
30
|
+
|
|
31
|
+
1. **Ground the product**
|
|
32
|
+
- Inspect existing project/workflow/logs before naming abstractions.
|
|
33
|
+
- Write a one-sentence product frame and a short command taxonomy.
|
|
34
|
+
- Keep the first slice narrow enough to test with real data today.
|
|
35
|
+
|
|
36
|
+
2. **Build the vertical slice**
|
|
37
|
+
- Start with `clap` commands, local config/session paths, and one useful data command.
|
|
38
|
+
- Prefer direct structured APIs over browser automation or ad hoc parsing.
|
|
39
|
+
- Add `doctor` for diagnostics and `install` for local adoption.
|
|
40
|
+
- Make `--json` available for commands agents will consume.
|
|
41
|
+
|
|
42
|
+
3. **Design failure behavior**
|
|
43
|
+
- Treat auth, permissions, rate limits, missing local files, and changed upstream APIs as product features.
|
|
44
|
+
- Fail loudly with actionable errors; do not retry blindly.
|
|
45
|
+
- Reuse valid sessions/tokens before hitting login or expensive endpoints.
|
|
46
|
+
|
|
47
|
+
4. **Package while building**
|
|
48
|
+
- Keep `README.md`, `docs/architecture.md`, `SKILL.md`, `Makefile`, `scripts/install.sh`,
|
|
49
|
+
CI, and release workflow current as part of the implementation.
|
|
50
|
+
- Avoid docs that describe internals in the user-facing skill unless users need them.
|
|
51
|
+
- Use release artifacts in Homebrew so users do not install Rust just to use the tool.
|
|
52
|
+
|
|
53
|
+
5. **Verify with reality**
|
|
54
|
+
- Run `cargo fmt --all -- --check`, `cargo check`, `cargo test`, release build, and CLI help.
|
|
55
|
+
- Smoke-test against the real local app/API/data source when possible.
|
|
56
|
+
- If the test exposes a product boundary mistake, fix the product, not only the bug.
|
|
57
|
+
|
|
58
|
+
6. **Ship deliberately**
|
|
59
|
+
- Commit scoped changes.
|
|
60
|
+
- Push the repo.
|
|
61
|
+
- Run the release script, wait for GitHub Actions, update the Homebrew tap, and run `brew test`.
|
|
62
|
+
- Verify the installed binary, not only `target/debug`.
|
|
63
|
+
|
|
64
|
+
## References
|
|
65
|
+
|
|
66
|
+
- Read [product-method.md](references/product-method.md) when framing a new tool or recovering from scope creep.
|
|
67
|
+
- Read [rust-cli-shape.md](references/rust-cli-shape.md) when creating or refactoring the project files.
|
|
68
|
+
- Read [release-checklist.md](references/release-checklist.md) before publishing GitHub/Homebrew releases.
|
|
69
|
+
- Read [case-notes.md](references/case-notes.md) when comparing against `tg`, `cx`, and `mon`.
|
|
70
|
+
|
|
71
|
+
## Guardrails
|
|
72
|
+
|
|
73
|
+
- Do not embed one-off user workflows into a general-purpose tool. Put them in a separate folder, script, or downstream skill.
|
|
74
|
+
- Do not expose tokens, local databases, chat logs, or account data in docs, logs, commits, or final messages.
|
|
75
|
+
- Do not overfit the CLI to the first conversation. The tool should satisfy a class of future agent/user jobs.
|
|
76
|
+
- Do not call a project shipped until the installed binary and release path have been exercised.
|