The stigmergy system is GraphPalace's collective intelligence layer. Inspired by ant colony optimization and adapted from STAN_X v8, it uses five types of pheromone trails to guide navigation through the memory palace. As agents and searches traverse the graph, they leave behind chemical-like signals that future navigators can follow.
Applied to Wing, Room, Closet, Drawer, and Entity nodes:
| Type | Signal | Decay Rate (ρ) | Half-life | Effect |
|---|---|---|---|---|
| Exploitation | "This location is valuable — come here" | 0.02/cycle | ~35 cycles | Attracts agents to valuable areas |
| Exploration | "This location has been searched — try elsewhere" | 0.05/cycle | ~14 cycles | Repels agents from over-searched areas |
Applied to all edge types (HAS_ROOM, HALL, TUNNEL, RELATES_TO, etc.):
| Type | Signal | Decay Rate (ρ) | Half-life | Effect |
|---|---|---|---|---|
| Success | "This connection led to good outcomes" | 0.01/cycle | ~69 cycles | Long-lasting quality signal |
| Traversal | "This path is frequently used" | 0.03/cycle | ~23 cycles | Popularity signal |
| Recency | "This connection was used recently" | 0.10/cycle | ~7 cycles | Short-term freshness signal |
All pheromones decay exponentially each cycle:
fn decay(current: f64, rate: f64) -> f64 {
current * (1.0 - rate)
}Half-life calculation: half_life = ln(2) / ln(1 / (1 - rate)) ≈ 0.693 / rate for small rates.
Decay is applied in bulk via Cypher every N cycles (default: 10):
-- Decay all node pheromones
MATCH (n)
WHERE n.exploitation_pheromone > 0.001 OR n.exploration_pheromone > 0.001
SET n.exploitation_pheromone = n.exploitation_pheromone * (1.0 - $exploitation_rate),
n.exploration_pheromone = n.exploration_pheromone * (1.0 - $exploration_rate)
-- Decay all edge pheromones
MATCH ()-[e]->()
WHERE e.success_pheromone > 0.001 OR e.traversal_pheromone > 0.001 OR e.recency_pheromone > 0.001
SET e.success_pheromone = e.success_pheromone * (1.0 - $success_rate),
e.traversal_pheromone = e.traversal_pheromone * (1.0 - $traversal_rate),
e.recency_pheromone = e.recency_pheromone * (1.0 - $recency_rate)Values below 0.001 are treated as zero (noise floor).
When a search path leads to a useful result, pheromones are deposited along the entire path. Earlier edges in the path (closer to the start) receive larger rewards:
fn deposit_path_success(path: &[Edge], base_reward: f64) {
for (i, edge) in path.iter().enumerate() {
let position_weight = 1.0 - (i as f64 / path.len() as f64);
let reward = base_reward * position_weight;
edge.success_pheromone += reward;
edge.traversal_pheromone += 0.1;
edge.recency_pheromone = 1.0; // Reset to max
}
for node in path.nodes() {
node.exploitation_pheromone += 0.2;
}
}Why position-weighted? The first edges in a successful path are the most valuable decisions — they set the right direction. Later edges contribute less to the overall success.
When a node is visited during exploration:
fn deposit_exploration(node: &mut Node) {
node.exploration_pheromone += 0.3;
}This discourages other agents from re-exploring the same area immediately, promoting diversity.
After any pheromone change, edge costs are recomputed. Pheromones reduce the effective cost of an edge — stronger pheromone trails make paths cheaper to traverse:
fn recompute_edge_cost(edge: &mut Edge) {
let pheromone_factor =
0.5 * edge.success_pheromone.min(1.0) // Quality: 50%
+ 0.3 * edge.recency_pheromone.min(1.0) // Freshness: 30%
+ 0.2 * edge.traversal_pheromone.min(1.0); // Popularity: 20%
edge.current_cost = (edge.base_cost * (1.0 - pheromone_factor * 0.5))
.clamp(0.0, 10.0);
}Interpretation:
- An edge with zero pheromones has
current_cost == base_cost - An edge with maximum pheromones (all 1.0) has
current_cost == base_cost * 0.5 - Pheromones can never reduce cost below 50% of base (prevents over-exploitation)
- The 50/30/20 weighting prioritizes quality (success) over freshness (recency) over popularity (traversal)
Default pheromone parameters in graphpalace.toml:
[pheromones]
exploitation_decay = 0.02 # Node: ~35 cycle half-life
exploration_decay = 0.05 # Node: ~14 cycle half-life
success_decay = 0.01 # Edge: ~69 cycle half-life (most persistent)
traversal_decay = 0.03 # Edge: ~23 cycle half-life
recency_decay = 0.10 # Edge: ~7 cycle half-life (most volatile)
decay_interval_cycles = 10 # How often to run bulk decayThe pheromone system produces several emergent properties without explicit programming:
-
Highway formation — Frequently successful paths develop strong pheromone trails, creating "highways" through the palace that agents prefer.
-
Exploration pressure — The exploration pheromone's faster decay (14 cycles vs. 35) means explored areas become "available" again before valuable areas lose their signal, creating a natural exploration/exploitation balance.
-
Recency bias — The recency pheromone's very fast decay (7 cycles) ensures recently-used connections are temporarily boosted, creating a "working memory" effect.
-
Quality persistence — Success pheromone's slow decay (69 cycles) means proven connections remain valuable long after they were last used.
-
Dead path pruning — Paths that are never successful have their pheromones decay to zero, effectively pruning them from consideration without explicit deletion.
Source: rust/gp-stigmergy/src/
| File | Purpose |
|---|---|
lib.rs |
Public API, module exports |
pheromones.rs |
PheromoneManager — read/write pheromone levels |
decay.rs |
DecayEngine — exponential decay with configurable rates |
rewards.rs |
RewardCalculator — position-weighted path rewards |
cost.rs |
Edge cost recomputation after pheromone changes |