A spatial computing platform for AI agents.
- Spatial - 2D coordinate space with quadtree indexing, proximity queries
- Agents - Add, move, remove agents with position and query radius
- Time - Tick-based simulation, event sourcing, replay/time-travel
- Streams - Real-time communication via WebSocket/SSE, one per agent
- AI - LLM integration (OpenAI, Fanar) for agent responses
- API - REST endpoints for all operations
- Visualization - Web UI for chat and spatial network view
Malten is a spatial environment where AI agents exist, move, query, and interact - a 2D plane where agents occupy positions, have limited query range, and operate based on their configuration.
- Space - Agents exist at coordinates. Position matters.
- Locality - Queries limited to nearby agents.
- Time - Tick-based. All events logged immutably.
- Communication - Real-time streams via WebSocket/SSE.
Agents are software entities in the spatial environment. Each agent has:
- Position (x, y)
- Radius (query range for nearby entities)
- Purpose (prompt defining their role)
- Stream (communication channel for their activity)
Agents can be commanded through their stream - the AI uses their prompt and available tools to decide how to respond.
Each agent has a dedicated stream showing their activity:
- Commands you send them
- Actions they take (move, look, scan, speak)
- Their responses
The world stream shows global events from all agents.
The environment containing:
- Agents occupying positions
- Objects (obstacles, resources, tools)
- Zones (regions, boundaries, areas) - planned
- Rules (what's possible, what's not)
The simulation runs on ticks. Each tick, the state advances. Everything that happens is recorded as events - an immutable history that can be replayed, rewound, branched.
You can:
- Add agents into the environment
- Command agents through their stream
- Observe what's happening (API, visualization)
- Query the environment (who's near whom, what happened)
- Replay history, travel through time
- Simulation - Model scenarios, run experiments, observe outcomes
- Multi-agent systems - Agents that coordinate, compete, communicate
- Digital twins - Mirror physical spaces with AI-powered entities
- Interactive environments - Environments you can query and influence
- Prediction - What happens if we put these agents here?
┌─────────────────────────────────────────────────────────┐
│ Malten Platform │
├─────────────────────────────────────────────────────────┤
│ Environment │
│ - Spatial plane (2D) │
│ - Agents, objects, zones │
│ - Rules and constraints │
├─────────────────────────────────────────────────────────┤
│ Time │
│ - Tick-based progression │
│ - Event sourcing (immutable history) │
│ - Replay, time-travel, branching │
├─────────────────────────────────────────────────────────┤
│ Spatial Index │
│ - Quadtree for efficient queries │
│ - Proximity, range, nearest-neighbor │
├─────────────────────────────────────────────────────────┤
│ Communication │
│ - Streams (one per agent + world) │
│ - Real-time via WebSocket/SSE │
│ - AI integration (LLM backends) │
└─────────────────────────────────────────────────────────┘
- Spatial agents with position and radius
- Event sourcing - immutable history
- Time system - ticks, replay, time-travel
- Real-time streams via WebSocket/SSE
- AI integration (OpenAI, Fanar)
- Proximity queries
- Visualization (
/network) - Persistence - save/restore environment state
- Agent streams - UI connected to spatial backend
- Agent tools - move, look, speak, position, scan
- Objects - items that exist in space
- Zones - regions, boundaries, areas
- Obstacles - things that block movement or queries
- Resources - things entities can use or consume
- Actions beyond move/speak
- Agent-to-agent interaction
- Agent-to-object interaction
- Sensors and actuators
- Environment configuration format
- Initial state setup
- Scenario library
- Branching timelines
- Autonomy framework
- Perception → Decision → Action loop
- Goals, planning, memory
- Sandboxed execution
- Multiple environments
- Large populations
- Long-running environments
- External integrations
go install malten.ai@latestOr build from source:
git clone https://github.com/asim/malten
cd malten
go build -o malten .Create environment file at ~/.malten/env:
# For OpenAI
export OPENAI_API_KEY=your-key-here
# Or for Fanar
export FANAR_API_KEY=your-key-here
export FANAR_API_URL=https://api.fanar.qa
export FANAR_MODEL=FanarData is stored in ~/.malten/data/:
events.jsonl- Event log (all actions)network.json- Spatial network state
source ~/.malten/env
./maltenhttps://malten.ai- Default streamhttps://malten.ai/#world- Global events (all agent activity)https://malten.ai/#agentstream- Agent's streamhttps://malten.ai/network- Spatial view of the environment
Each agent can have a dedicated stream. When you visit /#streamname:
- If the stream belongs to an agent, you see their info and can command them
- Commands are processed by the AI using the agent's prompt and tools
- All agent actions appear in their stream
- The world stream shows all global events
When viewing an agent's stream, you see:
- Agent name
- Current position and radius
- Their purpose (prompt)
- Link to view them on the spatial map
Type in the stream to command the agent:
- "look around" - Agent queries for nearby agents
- "move to 100, 50" - Agent moves to that position
- "scan for objects" - Agent scans for nearby objects
- Any natural language command - AI decides what tools to use
# Add an agent with a stream
POST /agents
{"name": "Scout", "x": 0, "y": 0, "stream": "scout", "prompt": "You are an explorer.", "radius": 50}
# List all
GET /agents
# Get one
GET /agents/{id}
# Get agent by stream
GET /agent?stream=scout
# Move
POST /agents/{id}/move
{"x": 10, "y": 20}
# Who's nearby?
GET /agents/{id}/nearby
# Command an agent (uses agent's prompt + tools)
POST /agents/{id}/command
{"prompt": "look around and report nearby agents"}
# Remove
DELETE /agents/{id}When commanded, agents can use these tools:
- move - Move to a new position
{"x": 10, "y": 20} - look - Query nearby agents within radius
- scan - Detect nearby objects (items, resources, things)
- speak - Send a message to their stream
- position - Get current position
The agent's prompt defines their purpose. The LLM decides which tools to use based on the command.
# Create an object
POST /objects
{"type": "beacon", "name": "North Beacon", "x": 100, "y": 100}
# Create with properties
POST /objects
{"type": "resource", "name": "Crystal", "x": 50, "y": 50, "properties": {"amount": 10}}
# List all objects
GET /objects
# Get object
GET /objects/{id}
# Update object
PUT /objects/{id}
{"x": 60, "y": 60, "properties": {"amount": 5}}
# Delete object
DELETE /objects/{id}
# Find objects near a point
GET /objects/nearby?x=0&y=0&radius=100# Find agents near a point
GET /nearby?x=0&y=0&radius=50# List all streams (includes agent streams + world)
GET /streams
# Send command to stream (routed to agent if stream belongs to one)
POST /commands
{"stream": "scout", "prompt": "look around"}
# Send message to stream
POST /messages
{"stream": "scout", "message": "hello"}
# Get messages from stream
GET /messages?stream=scout&limit=25# Current tick
GET /tick
# Advance time
POST /tick
# History
GET /events
GET /events?from=0&to=100
# Snapshot
POST /snapshot
GET /snapshot
# Time travel
POST /replay
{"tick": 50}# Real-time stream (WebSocket or SSE)
GET /events?stream=scoutThe /network page shows a spatial visualization of all agents:
- Pan/zoom with mouse, touch, or keyboard
- Agents shown as points with radius circles
- Click an agent in the sidebar to focus on them
- Auto-refreshes every 2 seconds
URL parameters:
?x=60&y=60- Center view on coordinates?zoom=2- Set zoom level?focus=Scout- Focus on agent by name
When viewing an agent's stream, click "📍 view on map" to see them centered in the network view.
Entities can have multiple connected nodes (multi-point). This enables zones, boundaries, paths, and complex shapes.
Visit /spatial.html for a visualization that renders:
- Single-node entities (agents) with radius circles
- Multi-node entities (zones) with edges connecting nodes
# List all entities (filter by type)
GET /spatial/entities
GET /spatial/entities?type=zone
# Create multi-node entity
POST /spatial/entities
{
"type": "zone",
"name": "Boundary",
"nodes": [
{"id": "a", "x": 0, "y": 0},
{"id": "b", "x": 100, "y": 0},
{"id": "c", "x": 100, "y": 100},
{"id": "d", "x": 0, "y": 100}
],
"edges": [
{"from": "a", "to": "b"},
{"from": "b", "to": "c"},
{"from": "c", "to": "d"},
{"from": "d", "to": "a"}
]
}
# Get entity
GET /spatial/entities/{id}
# Delete entity
DELETE /spatial/entities/{id}
# Move entity (translates all nodes)
POST /spatial/entities/{id}/move
{"x": 50, "y": 50}
# Query nearby entities (finds any with node in range)
GET /spatial/nearby?x=0&y=0&radius=100- agent - Software entity with prompt and stream
- object - Item in space (beacon, resource, etc.)
- zone - Multi-node region or boundary
The world has an optional LLM-powered rules engine that can add/remove objects:
# Get world config
GET /world
# Enable world engine
PUT /world
{"enabled": true, "tick_interval": 10}
# Manually trigger world
POST /world
# Get world state summary
GET /world/stateThe world engine processes rules - observing the current state and applying changes.
AGPL-3.0 - See LICENSE
Commercial use requires a separate license agreement.
You can type commands directly in any stream:
Create a new agent:
add Scout at 0,0
add Explorer at 100,50 with radius 75
add Guard at 0,0 prompt "You are a guard. Stay alert."
The agent's stream will be their name in lowercase (e.g., scout, explorer).
Create a multi-point zone:
zone Boundary at 0,0 to 100,0 to 100,100 to 0,100
zone Path at 0,0 to 50,50 to 100,0
Zones with 3+ points are automatically closed (last point connects to first).
When in an agent's stream, you can give natural language commands:
look around
move to 100, 50
scan for objects
report status
query the area
The AI interprets these and uses available tools (move, look, scan, speak, position).
Use the start script for proper initialization:
./start.shThis:
- Creates
~/.malten/data/if needed - Loads environment from
~/.malten/env - Sets
MALTEN_DATA_DIR - Starts the server
Malten provides an MCP (Model Context Protocol) server for AI assistant integration.
go install malten.ai/cmd/mcp@latestAdd to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"malten": {
"command": "malten-mcp",
"args": ["-url", "http://localhost:9090"]
}
}
}list_agents- List all agents with positionscreate_agent- Create a new agentmove_agent- Move agent to coordinatesquery_nearby- Find entities near a pointcommand_agent- Send command to an agentget_world_state- Get world summary
Once configured, ask Claude things like:
- "Create an agent called Scout at 0,0"
- "What agents are in the Malten environment?"
- "Move Scout to 100, 50"