Skip to content

Crafting

Crafting has three moving parts, and separating them makes the API obvious:

  • a recipe is the rule: these inputs become that output, taking this long;
  • a hab is the place: a plot at a starbase where crafting can happen;
  • a process is the run: one recipe executing in one hab, right now.

Recipes are static definitions from the Game account, so they are the same for everyone and cheap to read:

const recipe = await sage.recipes.byId(recipeId);

Both hang off whoever owns them, which is usually a character or their state at a starbase:

const habs = await sage.craftingHabs.byCharacter(characterAddress);
const running = await sage.craftingProcesses.byCharacter(characterAddress);

A process is a lifecycle, not a boolean. It has a start, a duration derived from its recipe, and an end — which is why crafting occupies a hab for a period rather than completing instantly.

Crafting processes have no derivable address. You cannot compute where one lives from the character or the recipe; it is assigned when the process is created.

That is why the reads above are byCharacter, byProfile, and byStarbasePlayer rather than a single get(address) — each encodes a verified way of finding processes, rather than pretending you can calculate where they are. See the bindings escape hatch for the broader pattern of accounts without derivable addresses.

A finished process still exists. Completion is a state, not a deletion. Read the lifecycle rather than assuming presence means “in progress”.

Hab capacity is finite. A hab holds a limited number of concurrent processes, so “can this character craft” is not answerable from the recipe alone.

Recipe inputs are raw amounts. Like all quantities, they are bigint and need the cargo definitions to render as names and decimals.