{"id":48759597,"url":"https://github.com/martin-minghetti/skillcam","last_synced_at":"2026-04-20T03:05:46.811Z","repository":{"id":350981078,"uuid":"1209035888","full_name":"martin-minghetti/skillcam","owner":"martin-minghetti","description":"Turn successful AI agent runs into reusable markdown skills","archived":false,"fork":false,"pushed_at":"2026-04-18T03:00:03.000Z","size":451,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-18T03:34:43.840Z","etag":null,"topics":["agent-tooling","ai-agents","anthropic","claude-code","cli","codex-cli","developer-tools","llm-tools","markdown","openai","skills","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/martin-minghetti.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-13T03:07:47.000Z","updated_at":"2026-04-18T03:13:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/martin-minghetti/skillcam","commit_stats":null,"previous_names":["martin-minghetti/skillcam"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/martin-minghetti/skillcam","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martin-minghetti%2Fskillcam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martin-minghetti%2Fskillcam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martin-minghetti%2Fskillcam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martin-minghetti%2Fskillcam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/martin-minghetti","download_url":"https://codeload.github.com/martin-minghetti/skillcam/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martin-minghetti%2Fskillcam/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32031070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T00:18:06.643Z","status":"online","status_checked_at":"2026-04-20T02:00:06.527Z","response_time":94,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-tooling","ai-agents","anthropic","claude-code","cli","codex-cli","developer-tools","llm-tools","markdown","openai","skills","typescript"],"created_at":"2026-04-13T05:01:29.924Z","updated_at":"2026-04-20T03:05:46.805Z","avatar_url":"https://github.com/martin-minghetti.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/demo.gif\" alt=\"SkillCam demo\" width=\"700\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eSkillCam\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Turn successful AI agent runs into reusable markdown skills.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/skillcam\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/skillcam.svg\" alt=\"npm version\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/skillcam\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/skillcam.svg\" alt=\"npm downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/skillcam\"\u003e\u003cimg src=\"https://img.shields.io/badge/sigstore-provenance-9d4edd?logo=sigstore\u0026logoColor=white\" alt=\"Sigstore provenance\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n```bash\n$ skillcam distill --latest\n✓ Read session a1b2c3d4... (claude-code)\n✓ Found 12 messages, 47 tool calls\n✓ Quality judge (high): produced concrete artifact, pattern is reusable\n✓ Distilling with anthropic...\n✓ Wrote skill to ./skills/fix-broken-imports-after-rename-refactor.md\n```\n\nSame task next week, with vs. without the skill the agent now has on disk:\n\n|              | Without SkillCam       | With SkillCam              |\n|--------------|------------------------|----------------------------|\n| Time         | ~15 min                | ~3 min                     |\n| Input tokens | ~50k                   | ~8k                        |\n| What happens | Agent figures it out from scratch | Agent reads the skill, runs the steps |\n\nNumbers above are illustrative on a typical \"fix the auth tests\"-style task. Your mileage varies by session length and model.\n\n## Why\n\nYour AI coding agent solves something today. Tomorrow the same problem comes back and the agent starts from zero — same files read, same tools tried, same tokens spent. The session log already on disk in `~/.claude/projects/` or `~/.codex/sessions/` has the answer. SkillCam pulls it out into a `SKILL.md` your agent reads next time.\n\nOne command. No daemon. No config. Works without an LLM (template stub) or with one (real distill).\n\n```bash\nnpx skillcam distill --latest\n```\n\n## How It Works\n\nSkillCam reads an agent session from disk, extracts what worked, and writes a `SKILL.md` your agent can reuse next time.\n\n### The loop it creates\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/martin-minghetti/skillcam/main/docs/img/loop.svg\" alt=\"The loop: agent solves → session.jsonl → skillcam distill → SKILL.md → agent reuses\" width=\"900\"\u003e\n\u003c/p\u003e\n\nOne session becomes one skill. One skill turns the next run from a fresh discovery into a quick execution.\n\n### The pipeline\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/martin-minghetti/skillcam/main/docs/img/pipeline.svg\" alt=\"Pipeline: discover → parse → distill (LLM or template) → emit → SKILL.md\" width=\"600\"\u003e\n\u003c/p\u003e\n\n### Two-step quality pipeline (v0.3.0)\n\n1. **Quality judge** — a cheap Haiku call decides whether the session even contains a reusable pattern. Exploratory sessions, abandoned attempts, and tasks that produced no artifact short-circuit here with exit code `7`, before any Sonnet tokens are spent. Override with `--force-distill`.\n2. **Distill** — if the judge says yes, a Sonnet call emits a strict JSON payload (name, steps, decisions, `confidence`, `why_this_worked`, etc.). TypeScript validates the schema and renders the canonical `SKILL.md`. Frontmatter is never controlled by the LLM.\n\n### Two distill modes\n\n| Mode | When to use | What happens |\n|------|-------------|--------------|\n| **LLM mode** (default) | You want a real skill — polished, specific, actionable | Runs the two-step pipeline above. Produces clean \"when to use\", concrete steps without tool-call literals, path-anonymized, with `confidence` + `why_this_worked` signals. See [`demo/RESULTS.md`](demo/RESULTS.md) for side-by-side output against v0.2.x. |\n| **Template mode** (`--no-llm`) | No API key / no network / privacy-only debug | Writes a minimal stub that captures session metadata (files modified, tools used, first user message) and tells you to re-run with `--llm` for a real skill. Not a substitute for the real distillation. |\n\n### What each stage does\n\n- **Discover** — scans `~/.claude/projects/` and `~/.codex/sessions/` for `.jsonl` files. Each agent format has its own parser. Sessions are sorted by most recent first.\n- **Parse** — reads the raw JSONL into a typed shape: user/assistant messages, tool calls with inputs/outputs, files modified, token usage, project metadata.\n- **Judge** — (LLM mode only) Haiku call on session metadata decides `distillable: yes/no`. Kills the #1 cause of low-quality skills — sessions that never should have been distilled.\n- **Distill** — (LLM mode) Sonnet emits strict JSON; template mode writes a stub.\n- **Render** — JSON → SKILL.md in TypeScript. Schema-validated, frontmatter under our control, tags restricted to a closed taxonomy.\n- **Emit** — appends a structured event to `agents/_core/events.jsonl` with session metadata, skill path, token costs, judge verdict, and distill mode. This is the shared event contract that future agent-tooling in this ecosystem will read.\n\n## Security\n\nAgent sessions can carry secrets (API keys, tokens, file contents) and can be hostile if anything else writes to `~/.claude/projects` or `~/.codex/sessions`. SkillCam treats every session as untrusted input.\n\n- **In-prompt** — secret scanner (14 patterns, normalized against NFKC / zero-width / URL-encode / Unicode escape / homoglyphs / combining marks / recursive base64), output sanitizer that strips prompt-injection payloads from `SKILL.md` before write, terminal-injection guards on every session-derived field including error paths.\n- **On disk** — trust-root confinement on read, symlink rejection, atomic writes with `O_EXCL`, path-traversal guards on the LLM-controlled filename, 50 MB session cap + 100 KB skill cap.\n- **Supply chain** — published from CI via npm Trusted Publishing (OIDC) with Sigstore provenance, no long-lived tokens.\n\nThree adversarial audits are recorded in the project notes; the latest (v0.3.1) closed four findings in the v0.3.0 distiller rewrite. Threat model + reporting path in [`SECURITY.md`](SECURITY.md).\n\n## Installation\n\n```bash\n# Use directly (no install needed)\nnpx skillcam distill --latest\n\n# Or install globally\nnpm install -g skillcam\n```\n\n## CLI Reference\n\n### `skillcam list`\n\nList available agent sessions.\n\n```bash\nskillcam list                        # Show 10 most recent sessions\nskillcam list --agent claude-code    # Only Claude Code sessions\nskillcam list --agent codex          # Only Codex CLI sessions\nskillcam list --last 20              # Show 20 sessions\n```\n\n### `skillcam preview`\n\nPreview what a session did without distilling.\n\n```bash\nskillcam preview --latest            # Preview most recent session\nskillcam preview \u003csession-id\u003e        # Preview specific session\nskillcam preview --latest --agent codex\n```\n\n### `skillcam distill`\n\nDistill a session into a reusable SKILL.md.\n\n```bash\nskillcam distill --latest                              # Distill most recent session (LLM mode, default)\nskillcam distill \u003csession-id\u003e                          # Distill specific session\nskillcam distill --latest --provider openai --model gpt-4o  # Use GPT-4o for the main call\nskillcam distill --latest --judge-model claude-haiku-4-5-20251001   # Override judge model\nskillcam distill --latest --force-distill              # Skip the quality judge and distill anyway\nskillcam distill --latest --output ./my-skills/        # Custom output directory\nskillcam distill --latest --redact                     # Redact detected secrets before sending\nskillcam distill --latest --allow-secrets              # Send as-is even if secrets are detected\nskillcam distill --latest --no-llm                     # Template stub only (no API key, no real distill)\n```\n\n**Exit codes** (v0.3.1)\n\n| Code | Meaning |\n|------|---------|\n| `0` | Success — skill written to disk |\n| `2` | Secrets detected and policy is `abort` (use `--redact` or `--allow-secrets`) |\n| `7` | Quality judge refused — session not distillable (use `--force-distill` to override) |\n| `8` | LLM emitted an `abort` payload after the judge passed (session content broke the anti-literal rule) |\n\nBy default, `distill` scans the prompt for common secret patterns (API keys, tokens, private keys) and aborts if any are found. See [`SECURITY.md`](SECURITY.md).\n\n## Supported Agents\n\n| Agent | Status | Session Location |\n|-------|--------|------------------|\n| Claude Code | Supported | `~/.claude/projects/\u003cproject\u003e/\u003csession\u003e.jsonl` |\n| Codex CLI | Supported | `~/.codex/sessions/YYYY/MM/DD/\u003csession\u003e.jsonl` |\n| Gemini CLI | Planned | -- |\n\n## LLM Providers\n\n| Mode | Command | API Key Required |\n|------|---------|-----------------|\n| Template | `--no-llm` | No |\n| Anthropic | `--provider anthropic` | `ANTHROPIC_API_KEY` |\n| OpenAI | `--provider openai` | `OPENAI_API_KEY` |\n\nTemplate mode writes a stub only — it is not a substitute for the real distillation. Use LLM mode for anything you want an agent to reuse. If the LLM call fails, SkillCam falls back to the template stub so the command never crashes.\n\n## Output Format\n\nSkills are standard markdown with YAML frontmatter. This example is the actual output v0.3.0 produced from a session where an agent fixed failing auth tests (the full run is in [`demo/RESULTS.md`](demo/RESULTS.md)):\n\n```markdown\n---\nname: fix-broken-imports-after-rename-refactor\ndescription: Fix failing tests caused by stale import names after a function was renamed during refactoring.\nsource_session: fix-bug-0001\nsource_agent: claude-code\ncreated: 2026-04-20\ndistill_prompt_version: v2.2026-04-19\nconfidence: high\ntags:\n  - testing\n  - debugging\n  - refactor\n  - auth\n---\n\n# Fix Broken Imports After Rename Refactor\n\n## When to use\nWhen tests fail with ReferenceError or 'not exported' errors after a refactor. Use when the error points to a symbol that no longer exists in the source but tests still reference the old name.\n\n## Steps\n1. Run the full test suite to capture the exact error messages and failing test files\n2. Read the failing test file to identify which imported symbol is missing\n3. Read the corresponding source file to find the current exported name\n4. Fix the import in the test using an alias (e.g., `import { newName as oldName }`) to preserve test readability without touching source\n5. Re-run only the failing test suite to confirm the fix\n6. Run the full test suite to catch any regressions\n\n## Example\nUser ran `npm test` after auth refactor; 3 tests failed with ReferenceError on `validateToken`. Agent read the test, then the source, and found the function was renamed to `verifyToken`. Fixed the import alias in the test file. Full suite passed.\n\n## Key decisions\n- Fix the test import, not the source — the rename was intentional and the test was stale\n- Use an import alias (`import { verifyToken as validateToken }`) to minimize test churn\n- Always re-run the full suite after a targeted fix to rule out regressions\n- ReferenceError on an imported symbol almost always means a rename or deletion in source, not a logic bug\n\n## Why this worked\nReading both the test and the source before editing revealed the rename as the sole root cause, avoiding unnecessary source changes\n```\n\nFrontmatter fields:\n\n| Field | Meaning |\n|-------|---------|\n| `name` | Kebab-case descriptive name, sanitized in TS (not LLM-controlled). Max 64 chars. |\n| `description` | One-sentence summary of what the skill does. |\n| `source_session` | Session ID this skill was distilled from. |\n| `source_agent` | `claude-code` or `codex`. |\n| `created` | ISO date (YYYY-MM-DD). |\n| `distill_prompt_version` | Version tag of the prompt used. Lets you re-distill when the prompt evolves. |\n| `confidence` | `high` / `medium` / `low` — the LLM's own rating of output quality. Useful for filtering and reuse-scoring. |\n| `tags` | 2–4 tags from a closed taxonomy (`testing`, `debugging`, `api`, `database`, `security`, `auth`, `performance`, `deployment`, `refactor`, `typescript`, `react`, `next-js`, `supabase`, `build`, `tooling`, `ci`, `migrations`, `observability`). |\n\nSee [`examples/skills/`](examples/skills/) for curated reference skills and [`demo/RESULTS.md`](demo/RESULTS.md) for a side-by-side comparison of v0.2.x vs v0.3.0 output across five fixtures.\n\n## Works with Obsidian\n\nSkillCam is CLI-first and markdown-native — **Obsidian is not required**, but the output is designed to work well inside a vault.\n\n- **YAML frontmatter** is Obsidian-compatible: `name`, `description`, `tags`, `created` render in the Properties panel with no config.\n- **Skill files are plain markdown**. Drop them anywhere in your vault, link to them with wikilinks (`[[fix-auth-tests]]`), or pull them into a Dataview / Bases query by tag.\n- **No plugin to install**. The CLI writes markdown, Obsidian reads markdown. Same files work for agents, for humans, and for CI.\n\nTypical workflow:\n\n```bash\n# Distill the session straight into your vault\nskillcam distill --latest --output ~/Vault/skills/\n```\n\nAdd `skills/` to a folder note or to a Base view and your agent skills become searchable alongside your research and daily notes.\n\nIf you're an agent-tooling power user or vault-curator, please open an issue with workflows you'd want — a `--vault` flag that reads `$OBSIDIAN_VAULT` is on the roadmap.\n\n## Project Structure\n\nThe code is grouped by role. Each layer has one job.\n\n### Data flow\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/martin-minghetti/skillcam/main/docs/img/data-flow.svg\" alt=\"Data flow: CLI → Discovery → Parsers → Distiller → SKILL.md + Events log\" width=\"900\"\u003e\n\u003c/p\u003e\n\n### Files by layer\n\n| Layer | File | Purpose |\n|-------|------|---------|\n| **CLI** | `src/cli.ts` | Commander entry — `list`, `preview`, `distill` |\n| **Discovery** | `src/discovery.ts` | Finds session logs in `~/.claude/projects/` and `~/.codex/sessions/` |\n| **Parsers** | `src/parsers/claude-code.ts` | Parses Claude Code JSONL format |\n|  | `src/parsers/codex.ts` | Parses Codex CLI JSONL format |\n|  | `src/parsers/types.ts` | `ParsedSession` shared shape |\n| **Distiller** | `src/distiller.ts` | Orchestrates LLM vs template mode |\n|  | `src/distiller-prompt.ts` | Builds the LLM prompt (with billing cap) |\n| **Safety** | `src/secret-scan.ts` | Scanner — 14 patterns + bypass-class normalization |\n|  | `src/skill-schema.ts` | Output sanitizer — strips prompt-injection payloads from SKILL.md |\n|  | `src/path-safety.ts` | Filename sanitization + path-traversal guard |\n|  | `src/terminal-safety.ts` | Strips control chars from session fields before console output |\n|  | `src/limits.ts` | DoS / cost caps (session size, prompt messages, skill output) |\n| **Events** | `src/events/emit.ts` | Appends structured events to `events.jsonl` |\n|  | `src/events/types.ts` | `AgentEvent` schema |\n| **Update check** | `src/update-check.ts` | Once-per-day npm registry check, atomic + sandboxed |\n| **Examples** | `examples/skills/` | Real skills generated from sessions |\n| **Tests** | `tests/` | Vitest suite (169 tests across 17 files) |\n\n## Contributing\n\nPRs welcome. Please open an issue first to discuss what you'd like to change.\n\nSome areas where contributions would be useful:\n\n- **New agent parsers** -- Gemini CLI, Cursor, Windsurf, or other agents that produce session logs\n- **Better distillation prompts** -- improving the quality of LLM-generated skills\n- **Skill validation** -- linting or scoring generated skills for completeness\n- **CI integration** -- auto-distilling skills from successful CI runs\n\n### Development\n\n```bash\ngit clone https://github.com/martin-minghetti/skillcam.git\ncd skillcam\nnpm install\nnpm run dev -- list          # Run from source\nnpm test                     # Run tests\nnpm run build                # Compile TypeScript\n```\n\n## Community\n\n- [GitHub Issues](https://github.com/martin-minghetti/skillcam/issues) -- bugs, feature requests, questions\n- [GitHub Discussions](https://github.com/martin-minghetti/skillcam/discussions) -- ideas, show \u0026 tell, general talk\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartin-minghetti%2Fskillcam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartin-minghetti%2Fskillcam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartin-minghetti%2Fskillcam/lists"}