This skill should be used when registering hooks, creating custom hooks for module APIs, debugging hook execution, handling async in hooks, or preventing memory leaks from unclean hook removal. Covers Hooks.on/once/call/callAll, lifecycle order, and common pitfalls.
View on GitHubImproperSubset/hh-agentics
fvtt-dev
fvtt-dev/skills/fvtt-hooks/SKILL.md
January 21, 2026
Select agents to install to:
npx add-skill https://github.com/ImproperSubset/hh-agentics/blob/main/fvtt-dev/skills/fvtt-hooks/SKILL.md -a claude-code --skill fvtt-hooksInstallation paths:
.claude/skills/fvtt-hooks/# Foundry VTT Hooks
**Domain:** Foundry VTT Module/System Development
**Status:** Production-Ready
**Last Updated:** 2026-01-04
## Overview
Foundry VTT uses an event-driven architecture where hooks allow modules to intercept and respond to VTT workflows. Understanding hooks is fundamental to all Foundry development.
### When to Use This Skill
- Registering event handlers for document changes
- Creating module APIs that other packages can consume
- Debugging hook execution order
- Preventing memory leaks from orphaned hooks
- Understanding async limitations in hooks
### Core Concepts
| Method | Purpose | Cancellable | Persists |
|--------|---------|-------------|----------|
| `Hooks.on(name, fn)` | Register persistent listener | N/A | Yes |
| `Hooks.once(name, fn)` | Register one-time listener | N/A | No |
| `Hooks.call(name, ...args)` | Trigger hook (stoppable) | Yes | N/A |
| `Hooks.callAll(name, ...args)` | Trigger hook (all run) | No | N/A |
| `Hooks.off(name, id)` | Unregister by ID | N/A | N/A |
## Lifecycle Hooks (Execution Order)
These fire once per client connection, in this order:
```
init → i18nInit → setup → ready
```
| Hook | When | Use For |
|------|------|---------|
| `init` | Foundry initializing | Register sheets, settings, CONFIG |
| `i18nInit` | Translations loaded | Localization-dependent setup |
| `setup` | Before Documents/UI/Canvas | Pre-game state setup |
| `ready` | Game fully ready | World initialization, game data access |
```javascript
// Correct registration order
Hooks.once("init", () => {
// Register settings
game.settings.register("my-module", "mySetting", { /* ... */ });
// Register document sheets
DocumentSheetConfig.registerSheet(Actor, "my-module", MyActorSheet, {
makeDefault: true
});
});
Hooks.once("ready", () => {
// Safe to access game.actors, game.users, etc.
console.log(`${game.actors.size} actors in world`);
});
```
## Document Hooks
All document types follow this pattern:
| Hook | Trigger