Agent Lifecycle
Normative semantics: This page describes agent creation and removal APIs. Activation-pass eligibility, same-pass additions and removals, collection bulk operations, and the target lifecycle contract are defined in Simulation Semantics V1.
ABMForge agents have a small but explicit lifecycle contract.
The goal is to make agent creation, removal, event cancellation, spatial removal, and lifecycle recording predictable and reproducible.
Lifecycle statuses
ABMForge currently defines two agent lifecycle statuses:
| Status | Meaning |
|---|---|
active |
The agent is alive and can participate in simulation |
removed |
The agent has been removed from the model |
New agents start as:
agent.lifecycle_status == "active"
agent.is_alive is True
When an agent is removed:
agent.lifecycle_status == "removed"
agent.is_alive is False
Creating agents
Agents are normally created through the model's agent collection:
agent = model.agents.create(MyAgent, wealth=10)
or in batches:
agents = model.agents.create(MyAgent, n=100, wealth=10)
Each agent receives a stable unique_id.
Removing agents
Agents can remove themselves:
agent.remove()
This calls:
model.remove_agent(agent)
Agents can also be removed directly by id:
model.remove_agent(agent.unique_id)
Removal guarantees
When an agent is removed, ABMForge guarantees the following behaviour:
agent.remove()
-> agent.is_alive = False
-> agent.lifecycle_status = "removed"
-> agent is removed from model.agents
-> agent is removed from model.world, if a world is attached
-> pending events owned by the agent are cancelled
-> lifecycle_records receives an "agent_removed" record
-> event_records receives "cancelled" records for cancelled owned events
This contract makes removal behaviour easier to test, audit, and reproduce.
Collection removal
After removal, the agent is no longer in the model's agent collection.
agent.remove()
assert agent.unique_id not in model.agents
Looking up a removed agent by id should fail.
World removal
If the model has a spatial world attached, ABMForge attempts to remove the agent from the world as well.
Example:
model.world.place(agent, (2, 2))
agent.remove()
assert not hasattr(agent, "pos")
The agent's position is cleared by the space implementation.
Owned event cancellation
ABMForge's event queue supports event ownership.
When an agent is removed, pending events owned by that agent are cancelled.
Example:
model.events.schedule(
callback=lambda: None,
after=1.0,
owner=agent.unique_id,
)
agent.remove()
The pending event is cancelled and should not execute later.
This is important for event-driven ABM models where agents schedule future actions.
Lifecycle records
Agent removal writes a lifecycle record.
A typical lifecycle record contains:
run_id
step
time
event = "agent_removed"
agent_id
details
Lifecycle records make simulation history easier to inspect after a run.
Event records
If owned events are cancelled during agent removal, ABMForge records event transitions with status:
cancelled
This links agent lifecycle changes to the event queue audit trail.
Snapshot behaviour
lifecycle_status is framework-managed lifecycle metadata.
It is intentionally excluded from user-facing agent snapshot state.
For example, if an agent has user attributes:
agent.wealth = 10
agent.mood = "happy"
the snapshot user state should contain:
{
"wealth": 10,
"mood": "happy",
}
not framework internal lifecycle metadata.
Modelling recommendation
Use agent.remove() when the removal is initiated by the agent itself.
Use model.remove_agent(agent_id) when the removal is initiated by the model, scheduler, policy rule, or external event.
Managed collection and space lifecycle integrity
AgentCollection.remove(...) and Model.remove_agent(...) use the same
managed lifecycle contract.
The collection accepts only active living agents. Removed or non-living agents cannot be added or re-added.
Managed removal performs these operations:
- remove the agent from its actual space when placed;
- clear
agent.posandagent.world; - cancel pending owned events;
- remove the agent from
model.agents; - set
is_aliveto false; - set lifecycle status to
removed; - write one lifecycle removal record.
For managed removal, spatial cleanup completes before lifecycle mutation. A spatial removal failure therefore leaves collection membership, lifecycle state, owned events, and lifecycle records unchanged.
Repeated removal raises KeyError and does not create a duplicate lifecycle
record.
An agent object must be the current object stored under its identifier. An object with the same identifier but a different object is rejected.
space.remove(agent) performs spatial unplacement only. It clears spatial
indexes, agent.pos, and agent.world, but it does not remove the agent from
model.agents, cancel events, or change lifecycle status.
Research reproducibility recommendation
If agent removal is part of the model's scientific mechanism, document:
- why agents are removed,
- when removal happens,
- whether removed agents can re-enter,
- whether removal cancels future events,
- which lifecycle records are expected.
This makes model behaviour easier to audit and reproduce.
Activation-Pass Removal Semantics
Built-in collection operations and schedulers revalidate an agent immediately before every activation callback.
An agent removed before its turn is skipped even when the activation pass retains an earlier candidate snapshot containing that object.
Callback eligibility requires:
- current collection membership;
- identity equality with the object currently stored under the identifier;
- a living lifecycle state.
Agents added during an existing activation pass are deferred until a future pass.
If an agent is removed and replaced by another object using the same identifier:
- the old object fails the identity check;
- the replacement is absent from the original candidate snapshot;
- neither object is activated from that snapshot position.
This activation rule applies to all managed removal entry points,
including AgentCollection.remove(...) and Model.remove_agent(...).
Direct spatial unplacement through space.remove(...) is not lifecycle
removal. The agent remains an active collection member.