Developer API
The API is on the uppercase global BONDSMITH. Call it as BONDSMITH.api from a macro or the console.
const api = BONDSMITH.api;const rep = api.reputation.get('Actor.abc123', 'actor');The lowercase bondsmith is not a global and reads as undefined. The same object is also on game.modules.get('bondsmith').api.
Every method that writes stored data returns a Promise. Await a write before reading the value back.
A player’s write goes to the GM client, which decides what to keep. Individual relations, actor-to-faction relations and actor changelog entries are kept when the player owns the actor they are keyed to. Every other field is discarded. The player is warned that part of the write was dropped.
data.getData()returns the full Bondsmith data object.data.getSettings()returns the resolved settings object.data.getLimits()returns the configured reputation minimum and maximum.data.getTierForValue(value, entityContext)returns{ value, label, color }for the tier a numeric value falls into, ornullwhen no tier covers the value. The label is already localized. Pass{ faction }asentityContextto resolve against that faction’s own tier set rather than the global one.data.export()saves the full export payload to a JSON file.data.import()prompts for an export file and opens the import dialog.
data.getData() returns a copy, and mutating it leaves stored data untouched. There is no write-back for the whole object. Use the typed setters.
actors
Section titled “actors”actors.getTracked()returns the array of tracked actor UUIDs.actors.addTracked(uuid)adds an actor to tracking.actors.removeTracked(uuid)removes an actor from tracking.actors.getDisplayName(uuid)returns the actor’s display name override, falling back to the actor’s own name.actors.setDisplayName(uuid, name)sets the display name.actors.getAltTitle(uuid)returns the alternate title.actors.setAltTitle(uuid, title)sets the alternate title.actors.getWorth(uuid)returns the actor’s Worth score, or0when none is stored.actors.setWorth(uuid, worth)sets the actor’s Worth score and returns whether the value changed. A non-numeric value is stored as0. The change writes an entry to the actor’s change log.actors.getVisibleName(uuid)returns the name shown for the current user.actors.getPCs()returns the party’s player-character Actor documents. The list is gathered from the system’s primary party actor, each player’s assigned character, and the active party faction’s members.actors.isPC(uuid)returns whether an actor is a player character.actors.getImage(uuid)returns the actor image path.actors.getJournal(uuid)returns the linked journal record.actors.setJournal(uuid, journal)links a journal record to an actor.actors.materializeActorless(id, options)turns an actorless entry into a real actor. PasstargetUuidto link a world actor or import a compendium actor, or omit it to create a blank one. PasskeepDisplayto keep the entry’s name and image as display overrides.
A journal record is { entryUuid, pageUuids }. factions.setJournal and locations.setJournal take the same shape. Pass a falsy value to unlink, which fires bondsmith.journalUnlinked instead of bondsmith.journalLinked.
factions
Section titled “factions”factions.list()returns all factions.factions.get(id)returns one faction by id.factions.add(data)creates a faction and returns it.factions.update(id, changes)updates a faction.factions.remove(id)deletes a faction.factions.duplicate(id, options)duplicates a faction. The options are described under top-level helpers.factions.addMember(id, actorUuid)adds a member and returns whether the membership changed.factions.removeMember(id, actorUuid)removes a member and returns whether the membership changed.factions.addRank(id, rank)adds a rank and returns it.factions.removeRank(id, rankId)removes a rank.factions.setMemberRank(id, actorUuid, rankId)assigns a member to a rank.factions.setJournal(id, journal)links a journal record.factions.setRollTable(id, table)takes a RollTable document and snapshots its rows as the faction’s tiers. Pass a falsy value to clear the link. A table with no rows is rejected with a warning.factions.generateTierTable(id)builds a RollTable from the faction’s resolved tiers, files it in a Bondsmith folder, links it, and returns the table. It returnsnullwhen the faction resolves to no tiers.
locations
Section titled “locations”locations.list()returns all locations.locations.get(id)returns one location by id.locations.add(data)creates a location.locations.update(id, changes)updates a location.locations.remove(id)deletes a location.locations.duplicate(id, options)duplicates a location. The options are described under top-level helpers.locations.addFaction(locationId, factionId)adds a faction to a location.locations.addActor(locationId, actorUuid)adds an actor to a location.locations.setJournal(id, journal)links a journal record.
relations
Section titled “relations”relations.getIndividual(fromId, toId)returns an actor-to-actor relation value.relations.setIndividual(fromId, toId, value)sets an actor-to-actor relation.relations.getFactionToActor(factionId, actorId)returns a faction-to-actor value.relations.setFactionToActor(factionId, actorId, value)sets a faction-to-actor value.relations.getActorToFaction(actorId, factionId)returns an actor-to-faction value.relations.setActorToFaction(actorId, factionId, value)sets an actor-to-faction value.relations.getFactionToFaction(fromId, toId)returns a faction-to-faction value.relations.setFactionToFaction(fromId, toId, value)sets a faction-to-faction value.relations.setFactionToFactionBidirectional(aId, bId, value)sets both directions of a faction pair.relations.getFactionToLocation(factionId, locationId)returns a faction-to-location value.relations.setFactionToLocation(factionId, locationId, value)sets a faction-to-location value.relations.getActorToLocation(actorId, locationId)returns an actor-to-location value.relations.setActorToLocation(actorId, locationId, value)sets an actor-to-location value.relations.getControllersOfLocation(locationId)returns the factions and actors that control a location as{ kind, id, value }entries, wherekindis'faction'or'actor'. Only positive control values are returned, strongest first.relations.isMirrored(fromId, toId)returns whether a faction pair is mirrored.relations.setMirrored(fromId, toId, mirrored)sets the mirrored state of a faction pair.relations.remove(type, fromId, toId)deletes the stored value without firingbondsmith.relationChanged.
The relation value setters take a fourth opts argument, apart from setFactionToFactionBidirectional. note and attribution are recorded on the changelog entry the write creates. internal suppresses the chat message. A setter warns and writes nothing when the user is not allowed to make that change. A player can only change an individual or actor-to-faction relation pointing away from an actor they own.
reputation
Section titled “reputation”reputation.get(id, type, opts)returns a reputation value for an actor or faction. Passopts.memberIdto read a single PC’s relation instead of the aggregate.reputation.set(id, type, value, opts)sets a reputation value. Passopts.memberIdto write a single PC’s relation instead of the aggregate.reputation.getMode(id, type)always returns'manual', the only mode the module implements.reputation.setMode(id, type, mode)accepts'manual'and throws for any other value.reputation.getEffectiveLimits(id, type)returns the effective minimum and maximum for an entity.reputation.getEffectiveTiers(factionId)returns a faction’s roll-table tier list ornull.reputation.calcMemberAverageActor(actorUuid)returns the average of each party PC’s individual relation toward that actor.reputation.calcMemberAverageFaction(factionId)returns the average reputation of a faction’s members. Members carrying a rank are weighted by that rank’s multiplier.reputation.calcPartyAverageFaction(factionId)returns the active party’s average reputation toward a faction.
Setting an aggregate spreads the change across the party members’ relations. It writes nothing when the party has no members. opts accepts note and attribution for the changelog entry. An aggregate write shows no toast. Pass silent on a memberId write to suppress that PC’s toast.
await BONDSMITH.api.reputation.set('Actor.abc123', 'actor', 25);decay.getConfig(kind, id)returns the decay override for an actor or faction, ornull.decay.setConfig(kind, id, config)writes the decay override for an actor or faction, or clears it whenconfigis falsy.decay.periodValues(current)returns the period values available for a dropdown. The calendar day and calendar month periods are added when Calendaria is active, and the calendar season period only when Calendaria reports a current season.decay.periodPaused(period)returns whether a period cannot tick because Calendaria is inactive.
kind is 'actors' or 'factions'. A config carries disabled, rate, period and target. lastTick is stamped for you when it is absent. A config with disabled set stops that entity decaying even while global decay runs.
party.getActiveId()returns the active party id.party.setActive(id)sets the active party.party.followSystemPrimary()syncs the active party to the system primary party when the follow setting is enabled. It runs only on the primary GM client. It does nothing unless the system exposes a primary party actor. If no faction is linked to that actor, one is created and its members synced before it becomes the active party.
visibility
Section titled “visibility”visibility.isHidden(category, id)returns whether an entity is hidden from players.categoryis'actors','factions', or'locations'.visibility.toggleHidden(category, id)toggles entity visibility and returns the new hidden state.visibility.isRelationHidden(type, fromId, toId, userId)returns whether a relation is hidden.visibility.toggleRelationHidden(type, fromId, toId)toggles relation visibility for the default audience.visibility.getRelationVisibility(type, fromId, toId, userId)returns the relation visibility state.visibility.setRelationVisibility(type, fromId, toId, target, state)sets the relation visibility state. Pass'_default'astargetfor the default audience or a user id for a per-user override.
A relation’s visibility state is 'known' or 'unknown', and an unset relation reads as 'known'. Writing a per-user state that matches the default audience removes the override instead of storing it.
presets
Section titled “presets”presets.list()returns the available setting presets.presets.get(key)returns one preset by its key, ornullwhen no preset carries that key.presets.resolve(entity, parent)resolves an entity’s preset chain to a settings object.
changelog
Section titled “changelog”changelog.get(factionId)returns a faction’s changelog.changelog.add(factionId, entry)adds an entry to a faction’s changelog.changelog.getActor(actorUuid)returns an actor’s changelog.changelog.addComment(type, id, entryId, comment)writes an entry’s comment, replacing any comment already on it.changelog.setEntryTimestamp(type, id, entryId, timestamp)sets an entry’s timestamp.changelog.setEntryWorldSeconds(type, id, entryId, seconds)sets an entry’s in-world stamp from a world-time value in seconds. It writes nothing while Calendaria is inactive.changelog.getRange(start, end, { type, id })returns the change-log entries falling inside a range, sorted by time.startandendare seconds. Each returned entry carriesentityType,entityId, andseconds. The range is read in world-time seconds when the Calendaria timeline setting is on and Calendaria is active. Otherwise entries are placed by their real-world timestamp.
An entry passed to changelog.add supplies oldValue, newValue, comment and tag. The id, timestamps and acting user are stamped for you.
graphs
Section titled “graphs”graphs.getIndex()returns the graph index.graphs.getEntry(id)returns one graph index entry.graphs.create({ name, type, description })creates a graph and returns its index entry.graphs.delete(id)deletes a graph.graphs.load(id)loads a graph document.graphs.save(id, graph)saves a graph document. Only the GM can save.graphs.builder(type)returns aGraphBuilderfor the given type.graphs.canUserView(graph, userId)returns whether a user can view a loaded graph.graphs.canUserEdit(graph, userId)returns whether a user can edit a loaded graph.graphs.setPermissions(graph, userId, perms)sets a user’s permissions on a loaded graph.permsis{ view, edit }, and only the keys you supply are changed. A GM passes both checks regardless of what is stored.graphs.updateNode(graph, nodeId, changes)updates a node on a loaded graph.graphs.updateLink(graph, linkId, changes)updates a link on a loaded graph.graphs.addShape(graph, shape)adds a shape to a loaded graph.graphs.updateShape(graph, shapeId, changes)updates a shape on a loaded graph.graphs.removeShape(graph, shapeId)removes a shape from a loaded graph.
Graph mutators change the loaded graph object in memory. Persist the result with graphs.save(id, graph).
A builder chains name, addTrackedActors, addFactions, addIndividualRelations, addFactionRelations, addMembershipLinks, addLocations, addLocationLinks and addChangelogEntries. getResult() returns the assembled nodes and links without saving. build() creates the graph, saves it, and returns its index entry.
automation
Section titled “automation”automation.getRules()returns the configured automation rules.automation.addRule(partial)adds a rule and returns it.automation.updateRule(ruleId, patch)patches one rule.automation.removeRule(ruleId)deletes a rule.automation.testFire(ruleId)runs a rule against its last captured payload, or against a synthetic payload when none exists.automation.registerTriggerHook({ hookName, label, toPayload, syntheticPayload, extractUuid })adds an event to the trigger registry and returns whether it was added.automation.getTriggerHooks()returns the registered events as{ value, label }entries.
registerTriggerHook binds the named Foundry hook once. toPayload maps the hook arguments into the payload that conditions read by path. extractUuid returns the triggering actor UUID from that payload, which the Triggering actor and Triggering actor’s faction targets resolve against. syntheticPayload supplies the object a test firing uses. label is a localization key, falling back to the literal string when the key is absent. When label is omitted it defaults to BONDSMITH.Automation.Hooks.<hookName>.
You can register after Foundry’s ready phase. An open settings window re-renders with the new event. Registering an event clears the broken flag from any rule waiting on it, and flags a rule broken when its event is not registered. Rules evaluate only on the primary GM client.
canvas
Section titled “canvas”canvas.refreshBadges()redraws all token reputation badges.canvas.refreshConnections()redraws all scene connection lines.
Both helpers do nothing while no canvas is ready. canvas.refreshConnections() is throttled, and draws nothing on a scene that has neither connections nor the relationship board turned on.
undo.undo()reverts the last tracked change. It returns whether a snapshot was restored, and warns when the stack is empty.undo.clear()clears the undo stack.undo.size()returns the number of stored snapshots.
The stack lives in memory on one client and is not shared between users. A snapshot is pushed on every data write.
viewer
Section titled “viewer”viewer.setPerspective(type, id)sets the open viewer’s perspective and returns whether a viewer was open to receive it. Omittypeandidto clear the perspective. Only the GM can change it.viewer.getPerspective()returns the open viewer’s current perspective ornull.
ui.open()opens the main viewer.ui.openSettings()opens the settings window.ui.openCreator(entityType, parentId)opens the entity creator.ui.openPicker(pickType, callback, options)opens the entity picker.ui.openGraphs()opens the graph dashboard.
entityType is 'faction', 'location' or 'actorless', and defaults to 'faction'. parentId preselects a parent for the faction and location types.
pickType is one of actor, worldActor, compendiumActor, groupActor, faction, factionOrActor, location, journal, macro or table. The callback receives the chosen id and, for factionOrActor, the kind that id belongs to. options.exclude is an array of ids to hide, written as kind:id for factionOrActor.
top-level helpers
Section titled “top-level helpers”search(query)returns matching actors, factions, and locations grouped by type.duplicate(type, sourceId, options)duplicates a faction or location.enterLocation(actorId, locationId, repDelta)adds an actor to a location. A non-zerorepDeltais added to the actor’s relation with the location’s strongest controlling faction. Actor controllers are skipped.batchSetRep(changes)sets reputation for a list of{ id, type, value }entries.adjustRep(id, type, delta)applies a relative reputation change through a serialized queue.
The duplicate options accepts name for the copy, plus includeChildren, includeRelations, includeDocRefs, includeMembers, includeChangelog and moveMembers. Every include flag copies unless you set it to false. moveMembers clears the members from the source once they are copied. Locations ignore the member and changelog flags. The call returns the new faction or location object, or null when the source is missing. Duplicating the active party faction is refused.
await BONDSMITH.api.adjustRep('Actor.abc123', 'actor', -5);constants and models
Section titled “constants and models”constantsholds the module constants listed under Constants.models.GraphBuilderis the graph builder class.
Bondsmith fires its hooks with Hooks.callAll. Listen with Hooks.on('bondsmith.repChanged', callback).
Each change hook fires only on the client that made the change, and a listener on another client never receives it. A write made by a player or a second GM does not trigger automation rules bound to bondsmith.repChanged.
Automation rules can subscribe to bondsmith.repChanged, and to any event added through automation.registerTriggerHook.
| Hook | Fires when | Payload |
|---|---|---|
bondsmith.ready | The API is mounted during Foundry’s ready phase. | none |
bondsmith.repChanged | A reputation value changes. | { id, type, oldValue, value, memberId, source, ruleId, depth } |
bondsmith.relationChanged | A relation value changes. | { type, fromId, toId, oldValue, newValue } |
bondsmith.settingsChanged | Settings are saved. | { settings } |
bondsmith.factionDuplicated | A top-level faction is duplicated. | { sourceId, newId, options } |
bondsmith.locationDuplicated | A top-level location is duplicated. | { sourceId, newId, options } |
bondsmith.journalLinked | A journal is linked to an actor, faction, or location. | { type, id, journal, previous } |
bondsmith.journalUnlinked | A journal link is removed. | { type, id, previous } |
bondsmith.dataReset | Module data is reset. | { scope } |
bondsmith.ruleFired | An automation rule applies a change. | { ruleId, hookName, target, delta, payload, isTestFire } |
The scope on bondsmith.dataReset carries entityData, settings, tiers and graphs. Each key that is set clears that part of the module’s storage. A reset always empties the undo stack.
On bondsmith.repChanged, memberId is the UUID of the party PC whose relation changed. Setting an aggregate value fires a per-member event for each affected relation, then a final roll-up event without memberId. The roll-up’s oldValue and value are the aggregate before and after the change.
source is 'automation' for a rule change, 'decay' for a decay step, and null otherwise. ruleId names the rule behind an automation change. depth counts how many rules chained to produce the change. Rules ignore events deeper than two links.
Hooks.on('bondsmith.repChanged', ({ id, type, value }) => { console.log(`${type} ${id} is now at ${value}`);});Constants
Section titled “Constants”MODULE_IDis'bondsmith'.HOOKSmaps each hook key to itsbondsmith.*event name.RELATION_TYPESholds the relation type values:individual,faction,actorFaction,factionToFaction,factionToLocation, andactorToLocation.GRAPH_TYPESholds the graph type values:force,genealogy,map, andtimeline.REP_MODESholds the reputation mode values:manual.