Bugfix: SSL fallback for Python installs without a CA bundle.
- python.org macOS Python builds ship with an empty certificate store until
Install Certificates.commandis run. When such a build ownspython3on PATH, every data.gov.il request failed withCERTIFICATE_VERIFY_FAILED, and the daily snapshot hook swallowed the error — history silently stopped accumulating. - New shared
scripts/ssl_fallback.pyused bysnapshot.pyandquery_flights.py: when the interpreter's default trust store is usable (including capath-based stores that report zero cached CAs), requests keep stdlib default behavior untouched; otherwise the first working CA bundle is used —certifiif importable, then OS bundles for macOS/BSD, Debian/Ubuntu, RHEL/Fedora, and openSUSE. Missing or corrupt bundles fall through to the next candidate, the resolved context is cached per process, and if nothing is usable a one-line actionable hint goes to stderr. No new hard dependencies. - The SessionStart snapshot hook now logs to
~/.natbag/snapshot.log(size-capped) instead of/dev/null, so the next failure class leaves a trace instead of silently stopping history accumulation. - Native manifests (Codex/Grok/Cursor) regenerated via
scripts/sync-native-manifests.py.
The marketplace now ships first-class manifests for Claude Code, Codex, Grok, and Cursor:
- Claude Code:
.claude-plugin/marketplace.jsonand per-plugin.claude-plugin/plugin.json. - Codex:
.agents/plugins/marketplace.jsonand per-plugin.codex-plugin/plugin.json. - Grok:
.grok-plugin/marketplace.jsonand per-plugin.grok-plugin/plugin.json. - Cursor:
.cursor-plugin/marketplace.jsonand per-plugin.cursor-plugin/plugin.json.
scripts/sync-native-manifests.py discovers new Claude marketplace entries automatically, infers presentation metadata, generates the three additional catalogs, wraps command-only plugins as Codex skills, and offers --check for CI-style drift detection. copy v2.4.0 adds generated Agent Skill forms of its eight commands, coacher v0.3.0 adds a portable skill plus Cursor always-on rule, natbag v1.2.2 refreshes its daily snapshot from the invocation workflow when hooks are unavailable, and find-session v1.2.1 fixes strict YAML parsing for its argument hint.
The repository and root marketplace were renamed from omri-cc-stuff to omri-marketplace to reflect support for multiple AI coding agents. Use omriariav/omri-marketplace for new installs; existing GitHub links redirect to the new repository. Individual plugin names and versions were unchanged by the rename.
For Claude Code and Codex, this is an identity migration: a plugin installed as x@omri-cc-stuff is distinct from x@omri-marketplace. Existing users should migrate in this order:
- Register
omriariav/omri-marketplacewith the relevant plugin manager. - Reinstall each existing plugin under its new
plugin@omri-marketplaceID. - Verify the new installation and preserve the previous enabled/disabled state.
- Remove the corresponding
plugin@omri-cc-stuffregistrations, keeping plugin data where the manager supports it. - Remove the obsolete
omri-cc-stuffmarketplace source.
See the README for Claude Code, Codex, and Grok registration commands.
New feature: /find-session now searches Codex transcripts alongside Claude Code sessions.
- Codex sessions (
~/.codex/sessions/<Y>/<M>/<D>/rollout-<ts>-<uuid>.jsonl) are scanned in the same pass as Claude Code sessions. Results from both sources are interleaved by recency, each tagged with its source and the correct resume command (codex resume <uuid>vsclaude --resume <uuid>). - New flags:
--source claude|codex|both(defaultboth, with shorthand--claude/--codex/--both) to scope by source, and--include-subagentsto include Codex subagent sessions (guardian auto-review judges and spawned children) that are otherwise excluded as non-resumable noise. - Codex previews show the first genuine user message — injected
role: userboilerplate (# AGENTS.md,<environment_context>,<skill>,<turn_aborted>,<<ccr:) is filtered from both the preview and keyword matching. Codex has no/rename, so Codex results are always preview-based. - Current-project scope resolves Codex sessions by the
cwdrecorded in each transcript'ssession_meta, skipping non-matching files after a single line read (the default path stays ~1s). Cross-project--allkeyword search uses aripgrep/greppre-filter over Codex transcripts (graceful fallback to a full scan when neither tool is present). --jsonoutput gains asourcefield and a per-resultresume_cmd.- Claude Code session parsing is unchanged (verified against the prior release).
New plugin — added to the marketplace by migrating omriariav/natbag-skill in via git subtree (full commit history preserved).
- Ben Gurion Airport (TLV) live flight data, destination weather, and historical delay analysis.
/natbagshows departures, arrivals, specific flights, status, destination weather, and accumulated on-time/delay history. - New entry in the root
marketplace.json(source: ./plugins/natbag). The marketplace's first plugin with hooks (SessionStart snapshot + PreToolUse freshness guard); both use${CLAUDE_PLUGIN_ROOT}and resolve correctly under the monorepo layout. - Runtime history accrues in
~/.natbag/flights.db(install-independent), so existing data carries over untouched. - Dropped the imported repo's redundant nested
.claude-plugin/marketplace.json(the monorepo reads only the root manifest). - The standalone
omriariav/natbag-skillrepo is now deprecated and points here. If you had it installed, uninstall it to avoid double-firing the SessionStart hook.
Moved into the marketplace as a local plugin — was previously listed in marketplace.json as an external url source pointing at omriariav/claude-coacher; now vendored locally via git subtree (history preserved).
marketplace.jsonentry flipped from the git URL tosource: ./plugins/coacher. No behavior change: still injects the SessionStart collaborator frame and provides/coacher:status,/coacher:audit,/coacher:reset,/coacher:rant.- Dropped the imported repo's redundant nested
.claude-plugin/marketplace.json. - The standalone
omriariav/claude-coacherrepo is now deprecated and points here. If you had it installed from there, reinstall ascoacher@omri-marketplaceto avoid double-firing the SessionStart hook.
Marketplace housekeeping: the root
plugin.jsonno longer carries aversionfield — versioning is strictly per-plugin (Claude Code keys installs on each plugin's own version, namespaced by marketplace; the root version drove nothing).
New feature: fleet-level skill-cleaner signals on every config audit.
- Companion to
skill-reviewer v1.1.0. Where/skill-reviewersurfaces skill-cleaner signals per-skill,/claude-reviewernow surfaces them fleet-wide across the audited scope. Every/claude-reviewer [project]or/claude-reviewer --globalinvocation now includes a## Skill Fleet Auditsection in its report with:- Fleet budget — total always-loaded description tokens across all skills in scope vs cap (default
2%of200,000-tok context =4,000tok). Pressure:OK/WARN/OVER. - Description trim candidates — every skill with description ≥ heavy threshold (default 120 tok), sorted by token cost.
- Duplicates — every skill name that appears in multiple roots, with keep-priority
plugin > personal > repo. - Unused candidates — opt-in via
--with-logs. Conservative path-only scan of~/.claude/projects/*.jsonlfor any skill in scope. Candidate signal only.
- Fleet budget — total always-loaded description tokens across all skills in scope vs cap (default
- New script:
scripts/fleet_audit.py. Flags:--global,--root(repeatable),--with-logs,--months,--context-tokens,--budget-percent,--heavy-threshold,--json. - Read-only — the script informs; per-skill trims flow through
/skill-reviewer --fix <skill>. argument-hintexposes--with-logs;SKILL.mdadds Phase 4 Step 1 documenting the integration;references/report-template.mdadds the## Skill Fleet Auditsection between Inventory and Scores (in both project-mode and global-mode templates).- Same fixes applied as
cleaner_checks.pyfromskill-reviewer v1.1.0: tolerant YAML block-scalar parsing,os.walkdirectory pruning, realpath-deduped scanning.
New feature: every per-skill review now surfaces skill-cleaner signals.
- Adapts the skill-cleaner methodology by @steipete for Claude Code as per-skill checks, not a separate audit mode. Every
/skill-reviewer <skill>invocation now includes a "Skill Cleanliness Signals" section in its report with:- Description budget — token cost for the target skill (
ceil(utf8_bytes/4)) vs cap (default2%of a200,000-token context). FlagsCANDIDATE for trimabove the heavy threshold (default 120 tok). - Duplicates — scans all skill roots for other copies of the same skill name; suggests which to keep via
plugin > personal > repopriority. - Usage evidence — opt-in via
--with-logs. Conservative path-only scan of~/.claude/projects/*.jsonlfor transcript paths likeskills/<name>/SKILL.md. Candidate signal only.
- Description budget — token cost for the target skill (
- New script:
scripts/cleaner_checks.py. Flags:--root(repeatable),--with-logs,--months,--context-tokens,--budget-percent,--heavy-threshold,--json. - Read-only — the script informs; fixes still flow through
/skill-reviewer --fix <skill>. argument-hintexposes--with-logs;SKILL.mdadds the integration step as Phase 5, Step 1;references/report-template.mdadds the section between Inventory and Scores.- Fleet-level audits (totals across all skills, all-duplicates-at-once, all-unused) will land separately as an addition to
/claude-reviewer, whose scope already covers the whole.claude/setup.
Maintenance — no behavior change.
/x:readand/x:tweetcommand files collapsed into thin pointers to their respectiveskills/<name>/SKILL.md. The skills are now the single source of truth for both commands; the previously duplicated workflow prose (which had to be hand-synced on every change, e.g. the v2.1.1 URL-counting fix) is gone. Commands instruct the model to resolvescripts/...paths relative to the skill directory.
Maintenance — no behavior change.
- Trimmed the
SKILL.mdfrontmatterdescription(tightened the opening line and compressed the NOT-for clauses) to cut always-loaded prompt-budget cost. All trigger phrases preserved.
Maintenance.
- Trimmed the
SKILL.mdfrontmatterdescription(dropped the inline dimension list — documentation, not a trigger) to reduce always-loaded prompt-budget cost. - Fixed broken YAML in the
SKILL.mdfrontmatter:argument-hintwas unquoted and began with[, which a strict YAML parser reads as a flow sequence and rejects. Now single-quoted (matching the sibling reviewer skills). Surfaced by Codex review of this PR.
Maintenance — no behavior change.
- Trimmed the
SKILL.mdfrontmatterdescription(dropped the rubric-stats clause) to reduce always-loaded prompt-budget cost. Trigger phrases unchanged.
Maintenance — no behavior change.
- Removed an orphaned legacy unified-router command (
.claude/commands/copy.md) that sat in a non-loading location and duplicated the eight split/copy:*commands. No effect on the active command surface.
Docs/example only — no pipeline changes.
- Bundled example swapped to a general math showcase:
examples/math-demo.md(quadratic formula, Euler's identity, finite + geometric series, the derivative limit, the Gaussian integral, Pythagoras). Replaces the ML-specificlaplace-smoothing.mdsample so the demo reads as broadly recognizable math. SKILL.mdandREADME.mdupdated to point at the new sample.
New plugin. /gdoc-math converts a Markdown file containing LaTeX math into a native Google Doc whose equations are real, editable equation objects — solving the gap that /copy:gdocs (Paste from Markdown) and Google's own "Export to Docs" can't: both leave $...$ / $$...$$ as literal text.
markdown+LaTeX →[pandoc]→ .docx (OMML) →[gws drive upload + convert --to docs]→ Google Doc
└─ intermediate .docx auto-trashed
pandoc renders LaTeX into Office MathML; Google Drive imports OMML as native, editable equations. Verified by round-tripping the converted Doc back to .docx — equations return as m:oMath objects with zero embedded images.
- Inline (
$…$), display ($$…$$), and\(…\)/\[…\]math. - Input modes: a
.mdfile path, inline content, or the last math-bearing content in the conversation. --name(Doc title),--folder(target Drive folder),--keep-docx(debug).- Optional
default_folder_idinconfig.json; empty by default (My Drive root), never required. - Ships a runnable sample at
examples/laplace-smoothing.md.
pandoc—brew install pandocpython3— parsesgwsoutput (default on macOS)gws(Google Workspace CLI), authenticated for Drive —go install github.com/omriariav/workspace-cli/cmd/gws@latest, thengws auth login
- Simple fractions/subscripts/Greek round-trip cleanly; complex LaTeX (stacked fractions, matrices, large operators) can lose fidelity on Google's import and may need a touch-up.
- Kept standalone (not folded into
copy) on purpose: it writes to Google Drive over the network with external dependencies — a different contract fromcopy's instant, offline, clipboard-only commands.
/copy:slack now produces a native Slack table on paste when the resolved content is just a table.
- Native Slack table paste (table-only path) — When the content is a bare table,
/copy:slackputs a Google-Sheets-flavored payload on the macOS pasteboard:public.utf8-plain-textcarries TSV, andpublic.htmlcarries a<table>wrapped with<google-sheets-html-origin>anddata-sheets-root="1". Slack's composer recognizes that exact shape and converts the paste into a real native table block — same render as a bot posting via the Block KittableAPI. - New
## Native Table Pastesection incommands/slack.mdwith the full TSV + HTML + JXANSPasteboardrecipe (plainpbcopyis not enough for this path).
- Router (
/copy slack): step 4 of the workflow now branches Slack into table-only (JXA path) vs mixed/prose (pbcopy); the destination rules and the example explicitly call out the same branch so a model following either prompt can't fall back to plain text and silently break native rendering. - Mixed/prose Slack guidance (bold, links, QuickChart) is now scoped to the mixed path. Adding any prose or chart URL to the table-only path would convert the paste into mixed content and Slack would drop the native render — the docs spell this out.
Slack's composer recognizes the Sheets-flavored clipboard only when the paste is a table. Add prose around the table and Slack falls back to plain text. For prose + native table together, the realistic options are:
- Two pastes (prose first, table-only second), or
- Use a Slack MCP / webhook that posts via
chat.postMessagewith a Block Kittableblock.
End users still cannot construct a native table block in the composer manually — that's a Slack platform constraint, not a plugin gap.
Breaking change: plugin renamed tweet → x. Command /tweet is now /x:tweet. Update any scripts or muscle memory.
/x:read— Fetch a tweet by URL or ID via X API v2 (GET /2/tweets/:id) and load it into the conversation as markdown (author, timestamp, public metrics, replied-to / quoted tweets, media). Reuses/x:tweetKeychain credentials. Metered by X at ~$0.005 / post read.- Plugin description updated to cover both posting and reading.
- Plugin directory
plugins/tweet/→plugins/x/. plugins/x/.claude-plugin/plugin.jsonnamefield is nowx.marketplace.jsonplugin entry renamed and now lists both./skills/tweetand./skills/read.
If you had the old tweet plugin installed, Claude Code's plugin cache still points at plugins/tweet/ and /plugin update will fail with Plugin source not found at .../plugins/tweet. The directory and entry name both moved, so this is a fresh install, not an upgrade.
To migrate:
/plugin→ selecttweet→ Uninstall/plugin→ installxfrom this marketplace- Restart Claude Code so the new commands register
Keychain credentials live under service x-api and are untouched — /x:tweet will pick them up immediately. Just update muscle memory: /tweet → /x:tweet, and you get /x:read for free.
Voice learning and skill structure improvements.
- Voice learning: Reads
LEARNINGS.jsonbefore drafting to match your established voice, appends observations after each posted tweet config.jsonfor operational defaults (char target, thread style)references/directory with extracted char-counting rules and drafting guidelines
- Scoped
allowed-toolstoBash(python3*), Bash(bash scripts/*)for security - Expanded description with negative trigger cases
- Trimmed SKILL.md from 134 to 92 lines via progressive disclosure
- Removed duplicate credential setup and verbose script output sections
Bugfix: /copy:slack now emits Markdown [text](url) links instead of Slack's <url|text> Block Kit syntax.
- Slack: Links use Markdown
[text](url)— renders as a hyperlink in the composer when "Format messages with markup" is enabled in Slack preferences. The previous<url|text>form is API/mrkdwnsyntax and renders literally in the composer. Raw URLs remain a safe fallback (Slack auto-unfurls them). (#6) - Router (
/copy slack) updated to match.
Bugfix: resolve format inconsistencies between router and subcommands.
- Jira: Router had stale wiki markup (
||header||,*bold*); now matchesjira.mdMarkdown syntax - Gmail:
gmail.mdincorrectly usedpbcopy; now usestextutil→ RTF →osascriptfor rich text paste - Router: Added
richformatandcleartextto argument list, examples, and clipboard rules - Router: Renamed
/copy email→/copy gmailfor consistency with actual command name
/copy:md- Copy as standard Markdown (tables, headers, bold, links, code blocks)
Breaking Change: Restructured /copy command into separate format-specific commands.
/copy:slack- Format for Slack/copy:gchat- Format for Google Chat/copy:gmail- Format for Gmail/email (HTML)/copy:gdocs- Format for Google Docs (Markdown)/copy:jira- Format for Jira Cloud (Markdown)/copy:cleartext- Plain text/copy:richformat- Rich Text Format (RTF)
- Plugin renamed from
copy-commandtocopyfor cleaner namespacing - Each format is now a separate command (
/copy:slackinstead of/copy slack) - Jira format updated to use Markdown (Jira Cloud) instead of wiki markup
- All commands accept optional
[what to copy]argument
Old: /copy slack the table
New: /copy:slack the table
Initial releases with single /copy command and various structural experiments.
- v1.3.0 - Skills-based structure attempt
- v1.2.0 - GitHub sync fixes
- v1.0.0 - Initial plugin release