https://github.com/jpoindexter/skill-triggers
Declarative event-fired triggers for agent skills — compile a triggers: frontmatter field in any SKILL.md into Vanta and Claude Code hooks.
https://github.com/jpoindexter/skill-triggers
agent-skills ai-agents automation claude-code hooks prompt-engineering skills vanta
Last synced: 16 days ago
JSON representation
Declarative event-fired triggers for agent skills — compile a triggers: frontmatter field in any SKILL.md into Vanta and Claude Code hooks.
- Host: GitHub
- URL: https://github.com/jpoindexter/skill-triggers
- Owner: jpoindexter
- License: mit
- Created: 2026-06-22T21:20:54.000Z (27 days ago)
- Default Branch: main
- Last Pushed: 2026-06-22T22:20:19.000Z (27 days ago)
- Last Synced: 2026-06-23T00:09:55.256Z (27 days ago)
- Topics: agent-skills, ai-agents, automation, claude-code, hooks, prompt-engineering, skills, vanta
- Language: TypeScript
- Size: 30.3 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# skill-triggers
**Declarative event-fired triggers for agent skills.** Most agent "skills" (a `SKILL.md`
file of reusable know-how) only fire by *relevance* — the agent recalls them when a task
looks related. `skill-triggers` lets a skill declare it should fire on a specific **harness
event** (before a push, after repeated tool errors, on a prompt) by adding one frontmatter
field, then compiles that into hooks for **[Vanta](https://github.com/jpoindexter/Vanta)**
and **Claude Code**.
```yaml
---
name: ship-preflight
description: Run the test suite before a push
triggers: [{"event":"PreToolUse","match":"git_push"}]
---
```
## The `triggers:` convention
A single-line JSON array on a `triggers:` key. Each entry:
| Field | Meaning |
|---|---|
| `event` | Harness event (e.g. `PreToolUse`, `PostToolUse`, `Stop`, `UserPromptSubmit`) |
| `match` | (optional) regex on the tool name — `PreToolUse`/`PostToolUse` |
| `when` | (optional) compact condition; `"errors>=N"` fires on a tool error |
| `action` | (optional) `"block"` makes a `PreToolUse` trigger a hard gate; default is advisory |
| `note` | (optional) override the surfaced recall note |
Single-line keeps it parseable by the flat frontmatter readers both harnesses use.
## Firing model — safe by design
A trigger never *runs* the skill body or anything irreversible. It compiles to a hook that
runs `vanta skills trigger-emit `, which only **surfaces a recall note** so the
agent applies the know-how itself:
- **`Stop`** → prints `{"additionalContext": "…recall skill X…"}` to stdout (model-facing injection).
- **`PreToolUse`** → a heads-up to the user (advisory). With `action:"block"` it can hard-gate the tool.
- **`UserPromptSubmit` / others** → prints the note to stdout (Claude Code injects it as context).
## Which events inject context
| Harness | Real context injection on |
|---|---|
| **Vanta** | `Stop` (`additionalContext`); `PreToolUse` can block/advise; `PostToolUse` on error |
| **Claude Code** | `PreToolUse`, `UserPromptSubmit`, `Stop`, and tool errors (a `PostToolUse`+error trigger → `PostToolUseFailure`) — all via `hookSpecificOutput.additionalContext` |
The compiler degrades unsupported events to advisory rather than failing.
### Cross-harness tool names
Claude Code's tool names differ from Vanta's (a git push is a `Bash` call, not a `git_push`
tool). The compiler maps `match` accordingly — `git_push` → matcher `Bash` + the emitter
confirms the command contains `git push` before firing — so a `PreToolUse` trigger behaves the
same in both harnesses, with no every-call noise. (`write_file`→`Write|Edit`, `read_file`→`Read`, …;
unknown names pass through unchanged.)
## Use it
```bash
# Print the Vanta hooks.json fragment for a skill
npx skill-triggers compile ./my-skill --target vanta
# Merge it into ~/.vanta/hooks.json (idempotent; preserves hand-written hooks)
npx skill-triggers compile ./my-skill --target vanta --write
# Or target Claude Code's ~/.claude/settings.json (Stop + UserPromptSubmit)
npx skill-triggers compile ./my-skill --target claude --write
```
Re-running is idempotent: generated entries are namespaced by the `skills trigger-emit`
command marker, so they're cleanly replaced and your hand-written hooks are never touched.
## Library
```ts
import { parseSkill, compileToVanta, compileToClaude, mergeVanta } from "skill-triggers";
const skill = parseSkill(readFileSync("SKILL.md", "utf8"));
const hooks = compileToVanta(skill); // → [{ event, hook }]
const merged = mergeVanta(existingHooksJson, hooks);
```
## Status
v0.1 — the convention + reference compiler + CLI, with cross-harness event mapping for Vanta and
Claude Code: `PreToolUse` (tool-name-mapped), `Stop`, `UserPromptSubmit`, and tool errors
(`PostToolUse`+error → `PostToolUseFailure`). The compiler is the reference implementation of the
`triggers:` convention; Vanta ships a native integration of the same logic. Roadmap: an
`agent`-mode firing option (run a skill as a worker) and an npm release Vanta consumes directly.
## License
MIT