Repository navigation
Releases: dortort/claude-plugins
Release list
taint-guard--v0.1.0
TaintGuard 0.1.0
The first release of TaintGuard, a Claude Code mod that remembers which sensitive or
untrusted sources entered a session and refuses risky tool calls once they have:
prevent sensitive context from reaching unsafe tools.
What ships:
- Session taint tracking. Sources add labels (
private,untrusted,secret) when a
matching tool call is attempted or succeeds; sinks refuse, ask about or audit tool calls
while their label condition holds. Every built-in and MCP tool call, including subagent
calls, is judged before it runs, on the taint from earlier calls. - Presets.
trifecta(default) asks before outbound tools once private and untrusted
content meet and refuses them once secrets are read;strictrefuses outbound and
file-changing tools once any label is present;noneleaves only your policy files.
MCP tools are classified by server family (mail, documents, chat, web) and verb, for
local servers and claude.ai connectors. Every tool on a web, browser or fetch server
(fetch,playwright,puppeteer,chrome, …) is anuntrustedsource and an
outbound tool. - Declarative policy files with a published JSON Schema, merged from managed, user
and project layers so that a repository can only tighten the rules. - Fail closed. A guard that throws or times out refuses on any possible match; an
invalid managed or user policy, or an unreadable managed setting, puts the session in
lockdown with every rule active. - Survives the session's lifecycle. The taint set survives reloads, is rebuilt from
history and a stored copy after/resume,/branchand restarts, and is written into
compacted conversations as a taint record. - Explains itself. A band above the prompt, a context line for Claude when taint grows
and on every prompt, deny text written as an instruction, an Allow once / Refuse
question foraskrules, and/taintguard(status,explain,tools,clear,
reload,audit). - Audit log. One JSONL file per session under
~/.claude/taint-guard/audit/, with a
keyed HMAC of each call's arguments. - Organization deployment. Managed
enabledlock, preset floor and managed policy
path, read from managed settings only; a deployment guide for
running it first in the chain throughprependPlugins.
Security fixes made in review before this release, and part of it:
- Built-in self-protection. A tainted session cannot have Claude rewrite TaintGuard's
policy files, Claude Code's settings files or the plugin and audit directories:
builtin:self-protectrefuses those writes while any label is held, in lockdown and
until a rebuild ends, in every mode. ItsBashcheck reads the command's text and is best
effort. - The managed floor holds. With managed settings that lock TaintGuard on or set a
preset, a user policy can no longer lowermode,userDeclassifyor
onUnknownHistory, so it cannot turn the managed rules into audit-only; the hooks module
now passes the floor to the policy loader, and the lock is honoured before
session.starthas loaded the policy. - Wider preset coverage. Web, browser and fetch MCP servers are sources and sinks;
trifectarefusesWebSearchonce secrets are read;Grepglobs over secret files, and
.git-credentials,gh/hosts.yml,.docker/config.jsonand.kube/config, add
secret. - Fail closed on padding. Argument text over 100,000 characters is not run through a
regex: it counts as matching in a source or a sink'sblockand as not matching in an
except. - Project regex limits. A project policy may not use alternation under an unbounded
quantifier, a regex over 256 characters, or more than 50 regexes, so a repository cannot
stall the guard. - Rebuild without gaps. Every label is held until the restart or resume rebuild
succeeds, a rebuild merges with taint added while it ran, and unreadable, cut or
uncounted subagent history counts as unknown history (assume-tainted). - Clearer prompts. A project policy's reason is marked
(repository policy)and does not
outrank a trusted sink's words; an ask shows destination fields first and the end of a
long command; preset tool patterns are named in plain words;/taintguard clearkeeps
labels that arrive while it asks to confirm.
Measured cost on ordinary work: the benign-task eval (120 replayed coding and mail-triage
tasks) meets the spec's amended target, which counts only misfires, asks or refusals
raised because a source labelled content that is not actually private, third-party or
secret. Under trifecta, 0.8% of tasks were interrupted by a misfire (target under 5%) and
0.8% failed because of one (target under 1%); the one misfire is a public test certificate,
since every *.pem read adds secret. The asks and refusals the preset exists to raise are
reported separately: designed gates interrupted 17.5% of tasks and stopped 1.7%. In all,
18.3% of tasks hit an ask or a refusal and 2.5% could not finish; under strict, 40.0%
could not finish, 39.2% by a designed gate. Under trifecta, TaintGuard asks before
replying to, forwarding or labelling mail and before Bash after reading mail, Slack or
Notion, and refuses Bash after .env or a *.pem has been read. To trade some of that
protection for less friction, a user policy can switch off a preset rule
({ "id": "preset:outbound-private", "enabled": false }) and add a narrower one, or use
preset: none with their own rules; neither is possible under a managed preset. The numbers
and the injection results are in evals/RESULTS.md.
Requirements: Claude Code 2.1.287 or later in the terminal, or the Desktop Code tab with
bundled Claude Code 2.1.286 or later. No Node.js, npm package or build step is needed at
runtime.
Install, once this release is promoted to the marketplace catalog:
claude plugin marketplace add dortort/claude-plugins
claude plugin install taint-guard@dortortOr load it from a checkout of the release tag:
git clone --branch taint-guard--v0.1.0 https://github.com/dortort/claude-plugins.git
claude --plugin-dir ./claude-plugins/plugins/taint-guardTo update later:
claude plugin marketplace update dortort
claude plugin update taint-guard@dortortRun /reload-plugins or restart Claude Code after updating. Organizations replace the
plugin directory in their managed marketplace instead; see the deployment guide.
Known limitations:
- It reasons about tools, not data: allowed tools such as
WriteorEditcan still move
data, and argument matching onBashcommands is easy to evade. - A background shell started before a source keeps running.
- A mod earlier in the chain can act before TaintGuard; other mods' own API calls are not
tool calls. Deploy it through managedprependPluginsto run first. - Allow once lets a sink through (audited);
askrules wait for a person, so use
denyrules for unattended sessions. - Rebuilds read at most the newest 4,096 history entries (the stored copy and
assume-taintedcover the rest), and a session compacted while TaintGuard was off has
no taint record. - Installed as a user mod where Claude Code's built-in guard loads (machines with managed
settings, Team and Enterprise logins), itsclassic.*andsession.compacthooks do not
run: no rebuild after/resumeor/branch, no/clearreset, no compaction record and
no background-task notes. Enforcement and restart rebuilds still work. - Taint is shared across subagents; per-agent taint, content-based sources and file taint
are planned for later versions. - No preset labels GitHub, Jira, Confluence, Zendesk or other issue trackers, and MCP tools
that write under verbs outside the spec's list (push_files,put_object) are not
outbound; add them in a policy file.
The full list is in the README's
security model and limitations.
Scheduler 0.4.1
Fixes scheduler installation through the dortort Claude Code marketplace.
- Aligns the plugin manifest and npm package at 0.4.1 so Claude reports the correct version.
- Includes npm-shrinkwrap.json so Claude installs runtime dependencies automatically.
- Checks version consistency during packing and publishing, validates the release tag, and tests the packed archive in a clean installation.
Update with claude plugin update scheduler@dortort, then reload plugins or restart Claude Code.
artifact-callbacks-channel--v0.1.1
Artifact Callbacks Channel 0.1.1
Clarifies the channel alternative's requirements and reports the installed plugin version in the MCP handshake.
- Reads the MCP server name and version from the plugin manifest so the reported versions stay aligned.
- Explains when to choose the channel instead of the mod, including its different event and reply behavior.
- Documents the lack of a confirm band and remote/SSH checks.
- Adds an independent release process and versioned release notes.
This remains a channels research-preview plugin. It requires Node.js 22.18+, Anthropic authentication, and channel access permitted by your organization. Publishing this release does not put it on Anthropic's channel allowlist. Unless your organization allowlists it, start an interactive session with the development flag:
claude plugin marketplace update dortort
claude plugin update artifact-callbacks-channel@dortort
claude --dangerously-load-development-channels plugin:artifact-callbacks-channel@dortortEnable only this variant or the mod in a session, never both. No npm publishing or build step is required.
artifact-callbacks--v0.1.1
Artifact Callbacks 0.1.1
Clarifies installation requirements and when to choose the mod or its channel alternative.
- Documents Claude Code 2.1.287+ in the terminal, or bundled Claude Code 2.1.286+ in Desktop's Code tab, and Node.js 22.18+.
- Explains the confirm band, per-click turns, reply streaming, and local-session requirements.
- Makes the choice between variants explicit: enable only one per session.
- Adds an independent release process and versioned release notes.
This release keeps the existing callback behavior. It needs no npm package or build step.
Update:
claude plugin marketplace update dortort
claude plugin update artifact-callbacks@dortortRun /reload-plugins or restart Claude Code after updating.
v0.4.0
What's New
Reliability: scheduled runs no longer aborted by the daily timezone sync (#5)
Scheduled tasks could intermittently fail right at launch — a sub-second exit-1 with empty logs and no session ever created — when the daily tz-sync job fired in the same slot (commonly 3am). Two independent hazards are now closed:
- Live task torn down mid-run.
syncre-registering a task didlaunchctl unload+loadon its plist, killing the job's process tree if it was already running.syncnow checks a newisTaskRunningpredicate and defers a live task to the next cycle instead of tearing down its registration. - Torn read of a shared shim.
syncrewrites the executor shims in place, and launchd couldexecone mid-write. Plists and shims are now written atomically (write-temp-then-rename), so a concurrent reader always sees a whole file.
Configurable state directory
- config: The scheduler state directory can now be overridden with the
CLAUDE_SCHEDULER_STATE_DIRenvironment variable, making it possible to isolate or relocate scheduler state.
Bug Fixes
- darwin: Timezone offset is now computed correctly across month and year boundaries (previously the day-of-month approximation could land in the wrong month/year at the edges).
- executor:
claudeinvocations are retried on transient macOS keychain auth failures, so a momentary "not logged in" hiccup no longer fails an otherwise-healthy run.
Under the hood
- E2E suite migrated to agentry with per-scenario state isolation for deterministic runs; added coverage for the sync skip-running path,
isTaskRunning, atomic writes, and executor auth-retry. Full suite: 353 tests green.
Full Changelog: v0.3.1...v0.4.0
v0.3.1
v0.3.0
What's New
macOS launchd timezone support
Tasks configured with a non-local timezone (e.g., timezone: "UTC") now fire at the correct time on macOS. Previously, launchd's StartCalendarInterval ignored the timezone field entirely, causing tasks to fire at the wrong hour.
How it works:
- At registration time,
CalendarIntervalvalues are converted from the target timezone to system-local time usingIntl.DateTimeFormat - A daily auto-sync launchd job (
com.claude-scheduler.tz-sync) is registered alongside any timezone-aware task, catching DST transitions automatically - The existing
synccommand recalculates timezone offsets on every run
Example: A task scheduled for 0 7 * * 1-5 with timezone: "UTC" on a system in America/Toronto (EDT, UTC-4) now correctly registers as Hour: 3 in the plist instead of Hour: 7.
Known limitation
Day-of-month schedules where the timezone offset crosses a day boundary use an approximate day (clamped to 1–28) with a logged warning. This is a fundamental limitation of launchd's CalendarInterval which has no native timezone support.
No changes to Linux
The Linux crontab scheduler is completely unaffected — it already handles timezones natively via the TZ= environment variable.
Full Changelog: v0.2.1...v0.3.0
v0.2.1
Bug fixes for lock handling, process lifecycle, and time display.
Fixes
- Correct SIGTERM handling: register before lock, write startTime before PID, abort on pre-spawn signal
- DST-safe "tomorrow" label and normalized midnight hour from
Intl.DateTimeFormat - Validate PID identity and preserve lock on unverified PID
- Send SIGTERM to executor PID only (not process group)
- Kill running processes when deleting a scheduled task
- Use pre-computed relativeTime instead of LLM date math in
list
Improvements
- Deterministic
relativeTimefield in humanize CLI output - Simplified lock module and renamed
formatRelativeTime
v0.2.0
@dortort/scheduler v0.2.0
Second release of the Claude Code scheduler plugin, focused on safer execution, one-time scheduling, task state synchronization, and project-scoped task loading.
Features
- One-time triggers - schedule a task to run once at a specific timestamp
- Enable/disable sync - keep config state and the native OS scheduler in sync
- Project-scoped tasks - load merged config via
projectPathfor project-local scheduling - Validation hardening - stricter cron, timestamp, and path validation in mutation flows
- Sensitive file protection - detect and block or warn on
.env, keys, and other sensitive files in worktree commit flows - Improved scheduler UX - add, update, and sync flows handle one-time schedules and enabled-state changes more reliably
Internal
- Trusted publishing - release automation now publishes to npm via GitHub Actions OIDC trusted publishing
See the README for the full command reference and usage details.
v0.1.0
@dortort/scheduler v0.1.0
First release of the Claude Code scheduler plugin.
Features
- Natural language scheduling - "every weekday at 9am", "daily at 5pm", "every Monday at 10am"
- Cron expressions - standard 5-field cron syntax with full validation
- One-time tasks - schedule a task to run once at a specific time
- Worktree isolation - run tasks in isolated git worktrees
- Execution history - JSONL-based history with filtering
- Log management - stdout/stderr capture with rotation
- Security built-in - env blocklist, sensitive file detection, shell escaping, trust boundaries
- Platform support - macOS (launchd) and Linux (crontab)
See the README for the full command reference and usage details.