Shows all files read and URLs fetched this session (deduplicated, sorted), plus uncommitted git changes. /read-tracker to open.

A collection of reusable skills for Claude Code, Anthropic's CLI for Claude.
create-skillA meta-skill that teaches Claude Code how to create new skills. It provides:
advent-cookiecutterGenerates a starter C++ file for a new Advent of Code problem, pre-loaded with type aliases, optional 2D/3D coordinate structs, and an input parsing template inferred from an example input file. Accepts an output path, an example input file, and an optional coordinate specifier (p2, pd2, pdpd2, p3, pd3, pdpd3).
cpp-cookiecutterSets up a standard C++ project repo structure with src/, test/, and bin/ directories, plus a root CMakeLists.txt, src/CMakeLists.txt, and test/CMakeLists.txt with FetchContent GTest integration. Requires a project name argument.
python-cookiecutterSets up a standard Python package development repo structure with bin/, etc/, notebooks/, source/ (Python source), src/ (C++ source), and test/ directories, plus a templated setup.py and pyproject.toml for local dev and pybind11 C++ bindings. Requires a package name argument.
format-cppFormats C++ code according to 20 specific style rules covering whitespace, braces, preprocessor directives, namespaces, types, formatting, and semantic transformations. Includes a namespace aliases reference and formatting examples.
plant-planCopies a plan file from ~/.claude/plans/ into the local repo's docs/plans/ directory. Accepts optional arguments to select a specific plan by name pattern or rename the output file.
marimo-notebookWrites and edits marimo reactive Python notebooks with correct cell structure, setup cells, reactivity patterns, and Typer CLI argument support. Includes reference guides for Polars, Altair, NumPy, SciPy, PyTorch, SQL, and marimo UI components.
optimize-pythonReviews Python code and applies performance optimizations drawn from a 23-pattern reference covering data structures, loops, strings, memory, and profiling. Safe mechanical changes are applied directly; structural changes are reported as suggestions.
refactor-pythonScans a Python codebase for duplicate or near-duplicate logic, then extracts repeated patterns into typed utility classes in a shared module. Groups helpers by the type they operate on (strings, numbers, dates, collections, etc.).
refactor-cppScans a C++ codebase for duplicate or near-duplicate logic across .cpp and .h files, then extracts them into reusable utility functions in a utils/ directory. Template functions are placed in .h headers only; non-template utilities get a .h declaration and a .cpp definition. Groups helpers by operand type (strings, numbers, containers, etc.) and outputs a structured refactor report.
jupyter-to-marimoConverts a Jupyter notebook (.ipynb) to a marimo notebook (.py) by running marimo convert, then auditing and fixing the output for magic commands, IPython display calls, anti-patterns, import consolidation into the setup cell, and missing PEP 723 metadata. Validates the result with marimo check and leaves # REVIEW: comments for patterns that cannot be automatically resolved.
mermaid-diagram-guideReference guide for Mermaid diagram syntax covering all major diagram types used in software engineering: flowchart, sequence, class, ER, state, Gantt, requirement, C4, ZenUML, mindmap, architecture, kanban, block, packet, treemap, and treeview. Auto-validates diagrams via a PostToolUse hook (mmdc) when @mermaid-js/mermaid-cli is installed.
marimo-anywidgetCreates custom interactive widgets in marimo notebooks using anywidget, combining Python traitlets state with vanilla JavaScript ESM front-ends. Covers the full widget lifecycle: Python AnyWidget subclass, JS render/initialize functions, CSS scoping, mo.ui.anywidget() integration, and reactive downstream cells.
async-pythonConverts one or more named Python functions from synchronous to asynchronous using asyncio. Locates the functions in the repo, builds a call graph and inter-function communication map, then applies async/await syntax and replaces sync I/O libraries with async equivalents (requests → aiohttp, pika → aio-pika, boto3 → aiobotocore, kafka-python → aiokafka, queue.Queue → asyncio.Queue). Flags helper functions and threading-boundary queues for manual review.
agent-memorySets up an agent memory project structure and manages the four agent memory files (adr.md, config.md, bug.md, issue.md). Handles both scaffolding (creating docs/memory/, docs/plan/, memory files, and .claude/CLAUDE.md) and memory operations (adding ADRs, logging bug fixes, tracking open issues, updating config). Enforces table schemas, blocks recording secrets or credentials, and handles the full issue-to-bug promotion lifecycle.
agent-memory-v2Sets up and manages diagram-driven project memory in docs/memory/. Scaffolds directories (docs/memory/, docs/plans/) and five memory files (kanban.md, architecture.md, adr.md, config.md, bug.md), and writes .claude/CLAUDE.md to guide future sessions. Supports three paths: scaffold setup, memory operations (kanban CRUD, ADR/config/bug writes), and diagram-driven development (syncing source code from edited Mermaid diagrams). Accepts command-style invocations (create-item, progress, complete) for quick kanban management. Depends on mermaid-diagram-guide for diagram syntax.
create-hookInteractive wizard that creates and installs Claude Code hooks in settings.json. Guides the user through lifecycle event selection (PreToolUse, PostToolUse, Stop, SessionStart, etc.), hook type (command, prompt, agent, or http), optional matcher regex, and installation target (global, project, or project-local). Generates or writes helper scripts for complex commands and verifies the written configuration.
curateAcquires a skill from a local directory or GitHub URL into this repo's skills/, or merges features from an external skill version into an existing local skill. Analyzes the source for security concerns, preferential bias, and destructive operations before writing anything. Resolves flagged issues interactively. Optimizes acquired skills to meet create-skill quality standards and creates the .claude/skills/ symlink.
commit-pushCommits all current changes and pushes to the remote origin on the current branch. Stages everything, generates a context-aware commit message by analyzing the diff and recent commit style, creates the commit, and pushes. Stops cleanly if there are no changes.
commit-push-prCreates a new branch named after the changes, stages all current changes, commits them, and pushes to upstream (falls back to origin if absent). Derives both the branch name and commit message from the staged diff and recent commit log.
pullSyncs the local main branch with the default remote. Switches to main first (warning about and discarding uncommitted changes if needed), runs git pull, and resolves merge conflicts by reverting local changes in favor of remote. Reports branch, sync status, and recent commits when done.
update-readmeUpdates a project README.md with a description, build instructions, test instructions, and a Mermaid architecture diagram. Emphasizes interfaces, protocols, and extension points in the diagram — not concrete implementations.
current-timeRetrieves the current date and time in a configured timezone. Can be invoked directly or used internally by other skills that require timestamps. With a timezone argument, validates and persists the new default timezone.
revertReverts all git changes in the working directory: staged changes, unstaged modifications, and new untracked files. Shows a summary of what will be lost and asks for confirmation before running git reset --hard HEAD and git clean -fd. Does not touch ignored files.
skill-statRecords skill usage statistics and issue reports into .claude/skill-stats.md. Increments the Uses count for a skill name and optionally logs an issue report that increments the Issues count and appends a row to the Issue Reports table.
advent-hackerSolves open-ended coding problems (e.g. Advent of Code) in Python. Reads problem descriptions, writes Python solutions, and runs them against input files.
skills/
├── advent-cookiecutter/
│ ├── SKILL.md
│ └── references/
│ ├── parsing-templates.md
│ └── struct-templates.md
├── agent-memory/
│ └── SKILL.md
├── agent-memory-v2/
│ ├── SKILL.md
│ └── references/
│ ├── claude-md-content.md
│ ├── diagram-driven-dev.md
│ ├── initial-content.md
│ └── memory-schemas.md
├── async-python/
│ ├── SKILL.md
│ └── references/
│ ├── asyncio-patterns.md
│ ├── concurrency-patterns.md
│ └── library-conversions.md
├── commit-push/
│ └── SKILL.md
├── commit-push-pr/
│ └── SKILL.md
├── create-hook/
│ ├── SKILL.md
│ └── references/
│ └── events-reference.md
├── curate/
│ ├── SKILL.md
│ └── references/
│ ├── github-url-formats.md
│ └── security-flags.md
├── cpp-cookiecutter/
│ └── SKILL.md
├── create-skill/
│ ├── SKILL.md
│ └── references/
│ ├── checklist.md
│ ├── hooks-best-practices.md
│ └── patterns.md
├── current-time/
│ └── SKILL.md
├── format-cpp/
│ ├── SKILL.md
│ └── references/
│ ├── examples.md
│ └── namespace-aliases.md
├── plant-plan/
│ └── SKILL.md
├── jupyter-to-marimo/
│ ├── SKILL.md
│ └── references/
│ └── CONVERSION-PATTERNS.md
├── marimo-anywidget/
│ ├── SKILL.md
│ └── references/
│ └── JS-PATTERNS.md
├── marimo-notebook/
│ ├── SKILL.md
│ └── references/
│ ├── ALTAIR.md
│ ├── NUMPY.md
│ ├── POLARS.md
│ ├── PYTEST.md
│ ├── PYTORCH.md
│ ├── SCIPY.md
│ ├── SQL.md
│ ├── TOP-LEVEL-IMPORTS.md
│ ├── TYPER.md
│ └── UI.md
├── mermaid-diagram-guide/
│ ├── SKILL.md
│ └── references/
│ ├── architecture.md
│ ├── block-diagram.md
│ ├── c4-diagram.md
│ ├── class-diagram.md
│ ├── er-diagram.md
│ ├── flowchart.md
│ ├── gantt.md
│ ├── kanban.md
│ ├── mindmap.md
│ ├── packet.md
│ ├── requirement-diagram.md
│ ├── sequence-diagram.md
│ ├── state-diagram.md
│ ├── treemap.md
│ ├── treeview.md
│ └── zenuml.md
├── optimize-python/
│ ├── SKILL.md
│ └── references/
│ └── optimization-patterns.md
├── pull/
│ └── SKILL.md
├── python-cookiecutter/
│ └── SKILL.md
├── refactor-cpp/
│ ├── SKILL.md
│ └── references/
│ └── refactor-patterns.md
├── refactor-python/
│ ├── SKILL.md
│ └── references/
│ └── refactor-patterns.md
├── revert/
│ └── SKILL.md
├── skill-stat/
│ └── SKILL.md
└── update-readme/
└── SKILL.md
agents/
└── advent-hacker.md
Clone this repo and point Claude Code at it. Then invoke any skill by name.
git clone https://github.com/armandli/get-skilled.git
cd get-skilled
claude
Example commands:
/create-skill — scaffold a new skill/advent-cookiecutter day01.cpp input.txt pd2 — generate a C++ AoC starter/agent-memory — set up agent memory structure, or add an ADR, log a bug fix, or resolve an open issue/agent-memory-v2 — set up diagram-driven project memory; /agent-memory-v2 create-item "fix login bug" "details", progress, or complete for kanban ops/create-hook — interactive wizard to create and install a Claude Code hook/curate https://github.com/user/repo/tree/main/skills/my-skill — acquire a skill from GitHub; /curate my-skill <source> to merge features/mermaid-diagram-guide — look up Mermaid syntax; /mermaid-diagram-guide sequence for a specific diagram type/async-python fetch_data process_results — convert named functions to async/commit-push — stage, commit, and push current changes/commit-push-pr — create a branch, commit, and push to upstream/cpp-cookiecutter myproject — scaffold a C++ project with CMake and GTest/current-time — get current date/time; /current-time America/New_York to set timezone/format-cpp src/main.cpp — format C++ files/plant-plan — copy the most recent plan from ~/.claude/plans/ into docs/plans//jupyter-to-marimo notebook.ipynb — convert a Jupyter notebook to marimo/marimo-anywidget slider "a range slider synced to Python" — create a custom marimo widget/marimo-notebook analysis.py — create or edit a marimo notebook/optimize-python src/ — apply Python performance optimizations/pull — sync local main branch with remote/revert — discard all staged and unstaged changes in the working directory/python-cookiecutter mypackage — scaffold a Python package with pybind11 support/refactor-cpp src/ — extract duplicate C++ logic into shared utilities/refactor-python src/ — extract duplicate Python logic into utilities/skill-stat agent-memory — record a skill usage stat/update-readme — generate or refresh the project READMEUse the create-skill skill itself to generate new skills, or manually add a directory under skills/ following the conventions documented in skills/create-skill/SKILL.md.
hooks/register.js 190 lines1// read-tracker mod
2// Tracks every file Read and URL WebFetch in this session.
3// Deduplicates, sorts alphabetically, and displays in a pane.
4// Also shows uncommitted git changes (M/D/??), polled every 10 seconds.
5// Run /read-tracker to open the pane.
6
7let filesReadSet = new Set()
8let urlsFetchedSet = new Set()
9let uncommittedChanges = []
10let sessionCwd = ''
11
12// --- Pure helpers (no $ needed) ---
13
14function displayPath(fp, cwd) {
15 if (!fp) return ''
16 const normalized = fp.replace(/\\/g, '/')
17 const base = (cwd || '').replace(/\\/g, '/').replace(/\/$/, '')
18 if (base && normalized.startsWith(base + '/')) {
19 return normalized.slice(base.length + 1)
20 }
21 return normalized
22}
23
24function sortedFrom(set) {
25 return Array.from(set).sort(function(a, b) { return a.localeCompare(b) })
26}
27
28function parseGitStatus(stdout) {
29 return stdout
30 .split('\n')
31 .filter(function(l) { return l.trim().length > 0 })
32 .map(function(l) {
33 return { status: l.substring(0, 2), path: l.substring(3).trim() }
34 })
35 .filter(function(f) { return f.path.length > 0 })
36 .sort(function(a, b) { return a.path.localeCompare(b.path) })
37}
38
39function statusColor(statusStr) {
40 if (statusStr.includes('D')) return 'red'
41 if (statusStr.trim() === '??') return 'green'
42 return 'yellow'
43}
44
45// Builds one labelled section of the pane.
46// items: array of Ink element nodes (Box/Text results).
47function buildSection(Box, Text, sectionKey, heading, items, cols) {
48 const divLen = Math.min(cols, heading.length)
49 const body = items.length > 0
50 ? items
51 : [Text({ key: 'empty', dimColor: true, children: ['(none)'] })]
52 return Box({
53 key: sectionKey,
54 flexDirection: 'column',
55 children: [
56 Text({ key: 'h', bold: true, color: 'cyan', children: [heading] }),
57 Text({ key: 'd', dimColor: true, children: ['─'.repeat(divLen)] }),
58 ].concat(body),
59 })
60}
61
62// Builds the complete pane tree from current module state.
63function buildPane(Box, Text, cols) {
64 const files = sortedFrom(filesReadSet)
65 const urls = sortedFrom(urlsFetchedSet)
66 const changes = uncommittedChanges
67
68 const fileItems = files.map(function(fp, i) {
69 return Text({
70 key: 'f' + i,
71 wrap: 'truncate-end',
72 children: [displayPath(fp, sessionCwd)],
73 })
74 })
75
76 const urlItems = urls.map(function(url, i) {
77 return Text({
78 key: 'u' + i,
79 dimColor: true,
80 wrap: 'truncate-end',
81 children: [url],
82 })
83 })
84
85 const gitItems = changes.map(function(c, i) {
86 return Box({
87 key: 'g' + i,
88 flexDirection: 'row',
89 columnGap: 1,
90 children: [
91 Text({ key: 's', color: statusColor(c.status), children: [c.status] }),
92 Text({ key: 'p', wrap: 'truncate-end', children: [c.path] }),
93 ],
94 })
95 })
96
97 return Box({
98 flexDirection: 'column',
99 children: [
100 buildSection(Box, Text, 'files', 'FILES READ (' + files.length + ')', fileItems, cols),
101 Text({ key: 'sp1', children: [' '] }),
102 buildSection(Box, Text, 'urls', 'URLS FETCHED (' + urls.length + ')', urlItems, cols),
103 Text({ key: 'sp2', children: [' '] }),
104 buildSection(Box, Text, 'git', 'UNCOMMITTED (' + changes.length + ')', gitItems, cols),
105 ],
106 })
107}
108
109// --- mods API helpers (top-level to allow receiving $) ---
110
111async function loadGitStatus($) {
112 try {
113 const r = await $.process.run(['git', 'status', '--porcelain'])
114 uncommittedChanges = parseGitStatus(r.stdout || '')
115 } catch {
116 uncommittedChanges = []
117 }
118}
119
120// --- Mod entry point ---
121
122export function register(on) {
123
124 on('session.start', async ($, e, next) => {
125 sessionCwd = await $.session.cwd()
126 // Reset read sets on each reload so state reflects the current session load
127 filesReadSet = new Set()
128 urlsFetchedSet = new Set()
129 await loadGitStatus($)
130 await $.command.register({
131 name: 'read-tracker',
132 description: 'Show files read, URLs fetched, and uncommitted changes',
133 immediate: true,
134 })
135 // Background: refresh git status every 10 seconds
136 $.clock.every(10000, async () => {
137 await loadGitStatus($)
138 $.ui.invalidate('ui.render')
139 })
140 return next(e)
141 })
142
143 // Open the pane (informational — no focus taken from prompt)
144 on('command.run', { command: 'read-tracker' }, async ($) => {
145 await $.ui.open({
146 id: 'read-tracker',
147 title: 'Read Tracker',
148 closeOnEscape: true,
149 })
150 return {}
151 })
152
153 // Track successful file reads
154 on('tool.call', { tool: 'Read' }, async ($, e, next) => {
155 const result = await next(e)
156 if (result && !result.deny && !result.isError && e.file_path) {
157 filesReadSet.add(e.file_path)
158 $.ui.invalidate('ui.render')
159 }
160 return result
161 })
162
163 // Track successful URL fetches
164 on('tool.call', { tool: 'WebFetch' }, async ($, e, next) => {
165 const result = await next(e)
166 if (result && !result.deny && !result.isError && e.url) {
167 urlsFetchedSet.add(e.url)
168 $.ui.invalidate('ui.render')
169 }
170 return result
171 })
172
173 // Refresh git status after any file write/edit so the pane stays current
174 on('tool.call', { tool: ['Write', 'Edit', 'MultiEdit'] }, async ($, e, next) => {
175 const result = await next(e)
176 if (result && !result.deny && !result.isError) {
177 await loadGitStatus($)
178 $.ui.invalidate('ui.render')
179 }
180 return result
181 })
182
183 // Draw the pane
184 on('ui.render', { component: 'Pane' }, async ($, e, next) => {
185 if (e.requestId !== 'read-tracker') return next(e)
186 const { Box, Text } = $.ui.resolve(e)
187 return buildPane(Box, Text, e.props.bodyColumns || 60)
188 })
189}
190