memo
Use when the user asks to remember or recall repository-specific notes across sessions by saving and searching markdown memory files in the user home directory.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when the user asks to remember or recall repository-specific notes across sessions by saving and searching markdown memory files in the user home directory.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Stages changes, commits with a well-written message, sign the commit using SSH key.
Pushes commits to the remote and creates a pull request with a clear title and comprehensive body. Use this skill when asked to push and open a PR for the current changes.
Reads unresolved code review comments from a GitHub pull request and fixes them. Use this skill when asked to fix, address, or resolve PR review comments, or when given a GitHub pull request URL with a request to fix the feedback.
| name | memo |
| description | Use when the user asks to remember or recall repository-specific notes across sessions by saving and searching markdown memory files in the user home directory. |
Persist and recall repo-scoped notes across sessions.
Save memory files under the memo directory:
~/.copilot/memo/[DATE]-[ID]-[repo-owner]-[repo-name]-[name].md
[DATE] uses YYYY-MM-DD. The current repository determines [repo-owner] and [repo-name].
Using ~/.copilot/memo keeps memos in a stable location that exists both locally
and in Codespaces.
Each memory file must be markdown with YAML frontmatter that includes:
memo_id: unix timestamp (date +%s)summary: searchable context summary (1-3 sentences, not just a title)status: wip or donecreated_at: ISO8601 timestampupdated_at: ISO8601 timestampThe memo content belongs in the markdown body, not in frontmatter.
Use this mode when the user says things like:
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
if [ -z "$repo_root" ]; then
echo "Run inside a git repository."
exit 1
fi
remote_url="$(git -C "$repo_root" config --get remote.origin.url || true)"
if [ -z "$remote_url" ]; then
echo "Could not resolve remote.origin.url."
exit 1
fi
repo_path="$(printf '%s\n' "$remote_url" | awk -F'[:/]' '{repo=$NF; sub(/\.git$/, "", repo); print $(NF-1) "/" repo}')"
repo_owner="${repo_path%/*}"
repo_name="${repo_path#*/}"
if [ -z "$repo_owner" ] || [ -z "$repo_name" ]; then
echo "Could not parse repo owner/name."
exit 1
fi
timestamp="$(date '+%Y-%m-%dT%H:%M:%S%z')"
date_prefix="$(date +%Y-%m-%d)"
memo_id="$(LC_ALL=C tr -dc 'a-z0-9' </dev/urandom | head -c 8; echo)"
Use the user input or context to create a short, descriptive name for the memo. If no name is provided, generate one based on the topic or content.
memo_dir="$HOME/.copilot/memo"
mkdir -p "$memo_dir"
file_path="${memo_dir}/${date_prefix}-${memo_id}-${repo_owner}-${repo_name}-${name}.md"
cat >"$file_path" <<EOF
---
memo_id: "$memo_id"
summary: "TODO: add a 1-3 sentence summary"
status: "wip"
created_at: "$timestamp"
updated_at: "$timestamp"
---
# Memo note
TODO: add memo details.
EOF
echo "$file_path"
Replace summary placeholder and memo body.
Find an existing file for the topic and edit it in place (preserve memo_id and created_at, update updated_at).
Use this mode when the user says things like:
remote_url="$(git -C "$repo_root" config --get remote.origin.url || true)"
if [ -z "$remote_url" ]; then
echo "Could not resolve remote.origin.url."
exit 1
fi
repo_path="$(printf '%s\n' "$remote_url" | awk -F'[:/]' '{repo=$NF; sub(/\.git$/, "", repo); print $(NF-1) "/" repo}')"
repo_owner="${repo_path%/*}"
repo_name="${repo_path#*/}"
if [ -z "$repo_owner" ] || [ -z "$repo_name" ]; then
echo "Could not parse repo owner/name."
exit 1
fi
memo_dir="$HOME/.copilot/memo"
shopt -s nullglob
files=( "$memo_dir"/*-"$repo_owner"-"$repo_name"-*.md )
shopt -u nullglob
if [ "${#files[@]}" -eq 0 ]; then
echo "No memo files found for ${repo_owner}/${repo_name} in $memo_dir"
exit 1
fi
results_file="$(mktemp)"
summary_index_file="$(mktemp)"
trap 'rm -f "$results_file" "$summary_index_file"' EXIT
for file in "${files[@]}"; do
memo_id_line="$(grep -m1 "^memo_id:" "$file")"
summary_line="$(grep -m1 "^summary:" "$file")"
printf "%s|%s|%s\n" "$file" "$memo_id_line" "$summary_line" >>"$summary_index_file"
done
id_hit="$(grep -iF -- "memo_id: \"$query\"" "$summary_index_file" | head -n 1 || true)"
if [ -n "$id_hit" ]; then
file="$(echo "$id_hit" | cut -d"|" -f1)"
line="$(echo "$id_hit" | cut -d"|" -f2)"
echo "$file|id|$line" >>"$results_file"
else
summary_hit="$(grep -iF -- "$query" "$summary_index_file" | head -n 1 || true)"
if [ -n "$summary_hit" ]; then
file="$(echo "$summary_hit" | cut -d"|" -f1)"
line="$(echo "$summary_hit" | cut -d"|" -f3)"
echo "$file|summary|$line" >>"$results_file"
else
likely_file="$(rg -i -l -F -- "$query" "${files[@]}" | head -n 1 || true)"
if [ -n "$likely_file" ]; then
content_line="$(rg -i -n -F -- "$query" "$likely_file" | head -n 1 || true)"
if [ -n "$content_line" ]; then
echo "$likely_file|content|$content_line" >>"$results_file"
fi
fi
fi
fi
[ -s "$results_file" ] || { echo "No memo match for query: $query"; exit 1; }
top_row="$(head -n 1 "$results_file")"
top_path="$(echo "$top_row" | cut -d"|" -f1)"
reason="$(echo "$top_row" | cut -d"|" -f2)"
line="$(echo "$top_row" | cut -d"|" -f3-)"
echo "TOP_MATCH=$top_path"
echo "MATCH_COUNT=1"
echo "CANDIDATES:"
printf "1. [%s] %s :: %s\n" "$reason" "$top_path" "$line"
Default behavior: return top 1 best match, then ask if more are needed.
Use this mode when the user says things like:
Locate the memo file (reuse the recall match logic above), then set its status to done and refresh updated_at. Preserve memo_id and created_at.
updated_at="$(date '+%Y-%m-%dT%H:%M:%S%z')"
sed -i '' \
-e 's/^status:.*/status: "done"/' \
-e "s/^updated_at:.*/updated_at: \"$updated_at\"/" \
"$top_path"
echo "Marked done: $top_path"
summary as a compact paragraph with enough detail to disambiguate related notes.