Purpose: AI-readable reference for the Structs Guild Stack PostgreSQL database. Covers core game state tables, the key-value grid pattern, event categories, and ready-to-use query patterns.
Requires: Guild Stack running locally. See .cursor/skills/structs-guild-stack/SKILL.md for setup.
PostgreSQL 17 with TimescaleDB extension. Four schemas:
| Schema | Purpose |
|---|---|
structs |
Game state (~50 tables covering all game objects) |
cache |
Blockchain event indexing (event-sourcing from chain to game state) |
signer |
Transaction signing queue (TSA account/role/tx management) |
sqitch |
Schema migration tracking |
| Role | Access | Used By |
|---|---|---|
structs |
Superuser (owner) | Administration, migrations |
structs_indexer |
Read/write on structs.*, cache.* |
structsd (indexer), structs-grass |
structs_webapp |
Read/write on most structs.*, full on signer.* |
Webapp, MCP, TSA |
structs_crawler |
Read-only on select tables | Crawler |
For agent queries, use structs_indexer via the GRASS container (see guild-stack skill).
structs.player| Column | Type | Notes |
|---|---|---|
id |
varchar PK | 1-{index} (e.g., 1-142) |
index |
integer | Numeric portion of ID |
guild_id |
varchar | Guild membership (e.g., 0-1) |
planet_id |
varchar | Home planet (e.g., 2-105) |
fleet_id |
varchar | Fleet (e.g., 9-142) |
primary_address |
varchar | Cosmos address |
creator |
varchar | Who created this player |
structs.fleet| Column | Type | Notes |
|---|---|---|
id |
varchar PK | 9-{index} |
owner |
varchar | Player ID |
status |
varchar | on_station, away |
location_type |
varchar | planet |
location_id |
varchar | Planet ID where fleet is located |
command_struct |
varchar | Command Ship struct ID |
space_slots / air_slots / land_slots / water_slots |
integer | Available slots per ambit |
structs.struct| Column | Type | Notes |
|---|---|---|
id |
varchar PK | 5-{index} |
type |
integer | FK to struct_type.id (1-22) |
owner |
varchar | Player ID |
location_type |
varchar | fleet or planet |
location_id |
varchar | Fleet/planet ID |
operating_ambit |
varchar | space, air, land, water |
slot |
integer | Position within ambit (0-3) |
is_destroyed |
boolean | Destruction state |
destroyed_block |
bigint | Block height when destroyed |
structs.struct_typeThe authoritative reference for all game balance data (~60 columns). Key columns:
Weapons (primary + secondary prefixed):
*_weapon_control – guided or unguided*_weapon_charge – charge cost per attack*_weapon_ambits – bitmask of targetable ambits*_weapon_ambits_array – JSONB readable form*_weapon_shots, *_weapon_damage – shots per attack, damage per shot*_weapon_blockable, *_weapon_counterable – boolean*_weapon_recoil_damage – self-damage after firing*_weapon_shot_success_rate_numerator/denominator – per-shot hit rateDefense:
unit_defenses – signalJamming, armour, defensiveManeuver, stealthMode, indirectCombatModule, noUnitDefensesguided_defensive_success_rate_numerator/denominator – evasion vs guidedunguided_defensive_success_rate_numerator/denominator – evasion vs unguidedcounter_attack – counter-attack damage (cross-ambit)counter_attack_same_ambit – counter-attack damage (same ambit)Other:
planetary_shield_contribution – shield value for planet structsgenerating_rate – power generation per gram (generators)ore_mining_difficulty, ore_refining_difficulty – PoW difficultybuild_difficulty – PoW difficulty for constructionactivate_charge, build_charge, defend_change_charge, move_charge, stealth_activate_chargeclass, class_abbreviation, unit_descriptionstructs.struct_attributeKey-value attributes per struct instance.
| Column | Type | Notes |
|---|---|---|
object_id |
varchar | Struct ID |
attribute_type |
varchar | health, status, protectedStructIndex, etc. |
val |
integer | Attribute value |
structs.struct_defenderDefense assignments.
| Column | Type | Notes |
|---|---|---|
defending_struct_id |
varchar PK | The defender |
protected_struct_id |
varchar | The struct being protected |
structs.planet| Column | Type | Notes |
|---|---|---|
id |
varchar PK | 2-{index} |
owner |
varchar | Player ID |
max_ore |
integer | Maximum ore capacity |
space_slots / air_slots / land_slots / water_slots |
integer | Slot counts |
status |
varchar | Planet status |
structs.planet_attribute| Column | Type | Notes |
|---|---|---|
object_id |
varchar | Planet ID |
attribute_type |
varchar | planetaryShield, etc. |
val |
integer | Attribute value |
structs.planet_raid| Column | Type | Notes |
|---|---|---|
planet_id |
varchar | Target planet |
fleet_id |
varchar | Raiding fleet |
status |
varchar | initiated, completed, etc. |
seized_ore |
numeric | Ore taken |
structs.grid is a key-value store for resource attributes. This is the most common source of query errors.
| Column | Type | Notes |
|---|---|---|
object_id |
varchar | Player/planet/struct/etc ID |
attribute_type |
varchar | ore, alpha, structsLoad, capacity, fuel, power, etc. |
val |
numeric | The value |
Wrong (no ore column exists):
SELECT ore FROM structs.grid WHERE object_id = '1-142';
Correct (filter by attribute_type):
SELECT val FROM structs.grid WHERE object_id = '1-142' AND attribute_type = 'ore';
Multiple attributes (use JOINs):
SELECT p.id,
COALESCE(g_ore.val, 0) as ore,
COALESCE(g_cap.val, 0) as capacity,
COALESCE(g_load.val, 0) as structs_load
FROM structs.player p
LEFT JOIN structs.grid g_ore ON g_ore.object_id = p.id AND g_ore.attribute_type = 'ore'
LEFT JOIN structs.grid g_cap ON g_cap.object_id = p.id AND g_cap.attribute_type = 'capacity'
LEFT JOIN structs.grid g_load ON g_load.object_id = p.id AND g_load.attribute_type = 'structsLoad'
WHERE p.id = '1-142';
| attribute_type | Found On | Meaning |
|---|---|---|
ore |
player, planet | Ore balance (player = mined/stealable; planet = remaining) |
capacity |
player, reactor, substation | Energy capacity |
structsLoad |
player | Energy consumed by active structs |
fuel |
reactor | Total ualpha infused |
power |
infusion | Energy generated from fuel |
connectionCapacity |
substation | Available capacity per connection |
connectionCount |
substation | Active connections |
load |
player | Base player load |
TimescaleDB hypertable for all planet-level events.
| Column | Type | Notes |
|---|---|---|
time |
timestamp | Event time |
seq |
integer | Sequence number (monotonically increasing, use as high-water mark) |
planet_id |
varchar | Planet where event occurred |
category |
enum | Event type (see below) |
detail |
JSONB | Event-specific data |
| Category | Description |
|---|---|
block |
New block committed |
raid_status |
Raid initiated/completed/failed |
fleet_arrive |
Fleet arrived at planet |
fleet_advance |
Fleet movement in progress |
fleet_depart |
Fleet departed from planet |
struct_attack |
Combat attack event |
struct_defense_add |
Defense assignment added |
struct_defense_remove |
Defense assignment removed |
struct_status |
Struct status change (online/offline/destroyed) |
struct_move |
Struct moved between slots/ambits |
struct_block_build_start |
Build PoW started |
struct_block_ore_mine_start |
Mining PoW started |
struct_block_ore_refine_start |
Refining PoW started |
struct_health |
Struct health changed (damage) |
guild_consensus |
Guild consensus events |
guild_meta |
Guild metadata changes |
guild_membership |
Membership changes |
player_consensus |
Player consensus events |
player_meta |
Player metadata changes |
-- Initialize: set high-water mark
SELECT COALESCE(MAX(seq), 0) as last_seq
FROM structs.planet_activity
WHERE planet_id IN ('2-105');
-- Poll every ~6 seconds
SELECT seq, planet_id, category, detail::text
FROM structs.planet_activity
WHERE planet_id IN ('2-105', '2-127')
AND seq > $LAST_SEQ
ORDER BY seq ASC;
The detail column for struct_attack includes attackerStructId, targetStructId, and eventAttackShotDetail with per-shot damage breakdowns.
| Table | Key Columns | Notes |
|---|---|---|
reactor |
id, guild_id, validator |
Links validator address to guild |
infusion |
destination_id, address, fuel, power, commission |
Composite PK: (destination_id, address) |
allocation |
id, source_id, destination_id, locked |
Energy routing |
substation |
id, owner |
Power distribution nodes |
provider |
id, rate_amount, rate_denom, access_policy |
Energy marketplace listings |
agreement |
id, provider/consumer refs, capacity, duration |
Active purchase contracts |
| Hypertable | Purpose | Key Columns |
|---|---|---|
ledger |
Financial transaction log | time, address, amount, action, direction, denom |
stat_ore |
Ore value history | time, object_type, object_index, value |
stat_capacity |
Capacity history | Same pattern |
stat_fuel |
Fuel history | Same pattern |
stat_load |
Load history | Same pattern |
stat_power |
Power history | Same pattern |
stat_struct_health |
Struct health over time | time, object_index, value |
stat_struct_status |
Struct status over time | Same pattern |
stat_structs_load |
structsLoad over time | Same pattern |
genesis, received, sent, migrated, infused, defusion_started, defusion_cancelled, defusion_completed, mined, refined, seized, forfeited, minted, burned, diversion_started, diversion_completed
The TSA manages a pool of signing accounts. Services insert rows into signer.tx with status='pending'. TSA claims them, signs, and broadcasts.
| Table | Key Columns | Notes |
|---|---|---|
signer.role |
id, player_id, guild_id, status |
Status: stub, generating, pending, ready |
signer.account |
id, role_id, address, status |
Status: stub, generating, pending, available, signing |
signer.tx |
id, module, command, args (JSONB), status |
Status: pending, claimed, broadcast, error. 90+ command types. |
All game object IDs follow {type_prefix}-{index}. See entity-relationships.md for the complete type code table.
| Prefix | Object Type | Example |
|---|---|---|
0- |
Guild | 0-1 |
1- |
Player | 1-142 |
2- |
Planet | 2-105 |
3- |
Reactor | 3-1 |
4- |
Substation | 4-5 |
5- |
Struct | 5-1165 |
6- |
Allocation | 6-10 |
9- |
Fleet | 9-142 |
10- |
Provider | 10-2 |
11- |
Agreement | 11-1 |
.cursor/skills/structs-guild-stack/SKILL.md – Setup and common queriesknowledge/infrastructure/guild-stack.md – Architecture overviewknowledge/entities/entity-relationships.md – Full entity graph and ID formatknowledge/entities/struct-types.md – Struct type stats (mirrors struct_type table)