Add ArcFlow to a Project
ArcFlow is infrastructure, not software — a spatial-temporal world model that runs in your process, no servers, no configuration. Every code block below is copy-pasteable and runnable.
Step 1: Install#
npm install arcflowNo other dependencies. No server to start. No Docker. No configuration files.
Step 2: Create a database#
import { openInMemory } from 'arcflow'
// In-memory (for development, testing, prototyping)
const db = openInMemory()
// Or persistent (for production — data survives restarts)
// import { open } from 'arcflow'
// const db = open('./data/world-model')Step 3: Write data#
// Create a world model entity with epistemic state
db.mutate(`
CREATE (e:Entity {
id: 'unit-01',
x: 12.4, y: 8.7, z: 0.0,
_observation_class: 'observed',
_confidence: 0.94
})
`)
// Create with parameters (always use this for dynamic values)
db.mutate(
"CREATE (e:Entity {id: $id, x: $x, y: $y, _observation_class: $cls, _confidence: $conf})",
{ id: 'contact-x', x: 80.0, y: 90.0, cls: 'predicted', conf: 0.38 }
)
// Create a relationship with provenance
db.mutate(`
MATCH (a:Entity {id: 'unit-01'})
MATCH (b:Entity {id: 'contact-x'})
MERGE (a)-[:DETECTS {sensor: 'lidar-1', _confidence: 0.91}]->(b)
`)
// Batch create (faster for bulk operations)
db.batchMutate([
"MERGE (e:Entity {id: 'sensor-1', x: 0.0, y: 0.0})",
"MERGE (e:Entity {id: 'sensor-2', x: 50.0, y: 0.0})",
"MERGE (z:Zone {id: 'zone-alpha', name: 'Perimeter'})",
])Step 4: Read data#
// Query returns typed results — numbers are numbers, not strings
const result = db.query(`
MATCH (e:Entity)
WHERE e._observation_class = 'observed' AND e._confidence > 0.8
RETURN e.id, e.x, e.y, e._confidence
ORDER BY e._confidence DESC
`)
// Access by column name
for (const row of result.rows) {
const id: string = row.get('e.id') as string
const conf: number = row.get('e._confidence') as number // 0.94 (number, not "0.94")
}
// Access as objects
const entities = result.rows.map(row => row.toObject())
// Result metadata
result.columns // ['e.id', 'e.x', 'e.y', 'e._confidence']
result.rowCount // number of rows returned
result.computeMs // 0.3 (milliseconds)Step 5: Query with parameters#
// Always use parameters for dynamic values — prevents injection
const result = db.query(
"MATCH (e:Entity {id: $id}) RETURN e.x, e.y, e._confidence",
{ id: 'unit-01' }
)
// result.rows[0].get('e._confidence') → 0.94
// Parameters work with all types
db.query(
"MATCH (e:Entity) WHERE e._confidence > $threshold RETURN e.id",
{ threshold: 0.85 }
)
db.query(
"MATCH (e:Entity {_observation_class: $cls}) RETURN e.id",
{ cls: 'observed' }
)Step 6: Update and delete#
// Update position (entity moved)
db.mutate(
"MATCH (e:Entity {id: $id}) SET e.x = $x, e.y = $y",
{ id: 'unit-01', x: 14.2, y: 9.1 }
)
// Upsert (create if not exists, update if exists)
db.mutate(
"MERGE (e:Entity {id: $id}) SET e._confidence = $conf",
{ id: 'unit-01', conf: 0.97 }
)
// Delete a node
db.mutate("MATCH (e:Entity {id: 'contact-x'}) DELETE e")
// Delete a node and all its relationships
db.mutate("MATCH (e:Entity {id: 'contact-x'}) DETACH DELETE e")
// Remove a property
db.mutate("MATCH (e:Entity {id: 'unit-01'}) REMOVE e.stale_field")Step 7: Run algorithms#
// No setup, no projection, no catalog — just call it
const pr = db.query("CALL algo.pageRank()")
for (const row of pr.rows) {
console.log(row.get('name'), row.get('rank'))
}
// Community detection
db.query("CALL algo.louvain()")
// Centrality
db.query("CALL algo.betweenness()")
// Graph stats
db.query("CALL db.stats()")Step 8: Vector search#
// Create index
db.mutate("CREATE VECTOR INDEX docs FOR (n:Doc) ON (n.embedding) OPTIONS {dimensions: 1536, similarity: 'cosine'}")
// Add data with embeddings
db.mutate("CREATE (d:Doc {title: 'AI Intro', embedding: '[0.1, 0.2, 0.3, ...]'})")
// Search by similarity
const results = db.query(
"CALL algo.vectorSearch('docs', $vec, 10)",
{ vec: JSON.stringify([0.1, 0.2, 0.3]) }
)Step 9: Handle errors#
import { ArcflowError } from 'arcflow'
try {
db.query("INVALID SYNTAX")
} catch (e) {
if (e instanceof ArcflowError) {
e.code // "EXPECTED_KEYWORD" — machine-readable
e.category // "parse" | "validation" | "execution" | "integration"
e.message // "Expected MATCH or CREATE, got ..."
e.suggestion // "Expected MATCH or CREATE" — fix hint
}
}Error codes you'll encounter:
| Code | Category | Meaning | Fix |
|---|---|---|---|
EXPECTED_KEYWORD | parse | Query syntax wrong | Check MATCH/CREATE/MERGE spelling |
UNKNOWN_FUNCTION | validation | Function doesn't exist | Run CALL db.help() to see available |
UNKNOWN_PROCEDURE | validation | Procedure doesn't exist | Run CALL db.procedures |
WORKFLOW_NOT_FOUND | validation | Workflow name not found | Run CALL arcflow.workflow.list |
EXECUTION_CONTEXT_MISMATCH | integration | Context guard failed | Run CALL db.setExecutionContext(...) first |
DB_CLOSED | integration | Called after db.close() | Don't use db after closing |
Step 10: Close#
db.close()
// After this, all operations throw ArcflowError with code 'DB_CLOSED'Complete example#
import { openInMemory, ArcflowError } from 'arcflow'
const db = openInMemory()
try {
// Build a world model
db.batchMutate([
"MERGE (e:Entity {id: 'unit-01', x: 12.4, y: 8.7, _observation_class: 'observed', _confidence: 0.94})",
"MERGE (e:Entity {id: 'unit-02', x: 45.0, y: 22.3, _observation_class: 'observed', _confidence: 0.88})",
"MERGE (e:Entity {id: 'contact-x', x: 80.0, y: 90.0, _observation_class: 'predicted', _confidence: 0.38})",
"MERGE (z:Zone {id: 'zone-alpha', name: 'Perimeter'})",
])
db.mutate(`
MATCH (a:Entity {id: 'unit-01'}) MATCH (b:Entity {id: 'contact-x'})
MERGE (a)-[:DETECTS {sensor: 'lidar-1', _confidence: 0.91}]->(b)
`)
// Query high-confidence observed entities
const trusted = db.query(`
MATCH (e:Entity)
WHERE e._observation_class = 'observed' AND e._confidence > 0.85
RETURN e.id, e.x, e.y, e._confidence
ORDER BY e._confidence DESC
`)
console.log(`${trusted.rowCount} trusted entities in world model`)
// Temporal: what did the world model show 5 seconds ago?
const past = db.query(
"MATCH (e:Entity) AS OF seq $seq RETURN e.id, e._confidence",
{ seq: 10 }
)
// Centrality: which entities are most connected?
const pr = db.query("CALL algo.pageRank()")
const stats = db.stats()
console.log(`${stats.nodes} nodes, ${stats.relationships} relationships`)
} catch (e) {
if (e instanceof ArcflowError) {
console.error(`${e.code}: ${e.message}`)
}
} finally {
db.close()
}Testing pattern#
import { describe, it, expect } from 'vitest' // or jest, node:test
import { openInMemory } from 'arcflow'
describe('my feature', () => {
it('does something with a graph', () => {
const db = openInMemory() // fresh graph per test
db.mutate("CREATE (n:Item {name: 'test', value: 42})")
const result = db.query("MATCH (n:Item) RETURN n.value")
expect(result.rows[0].get('value')).toBe(42)
db.close() // cleanup is optional — GC handles it
})
})Express/Fastify pattern#
import { open } from 'arcflow'
import express from 'express'
const db = open('./data/graph')
const app = express()
app.get('/api/people', (req, res) => {
const result = db.query("MATCH (n:Person) RETURN n.name, n.age")
res.json(result.rows.map(r => r.toObject()))
})
app.post('/api/people', express.json(), (req, res) => {
const { name, age } = req.body
db.mutate("CREATE (n:Person {name: $name, age: $age})", { name, age })
res.json({ ok: true })
})
process.on('SIGTERM', () => { db.close(); process.exit(0) })
app.listen(3000)What to remember#
openInMemory()for dev/test,open(path)for production- Always use
$paramsfor user input — prevents injection row.get('column')returns typed values — numbers, booleans, null, not strings- Algorithms: just
CALL algo.pageRank()— no setup - Errors are structured:
e.code,e.category,e.suggestion - No server needed. No Docker. No connection strings.
See Also#
- Agent-Native Database — filesystem workspace, CLI binary, watch mode, batch execution
- ArcFlow for Coding Agents — CLI patterns, structured errors, and checkpointing
- Swarm & Multi-Agent — coordinating multiple agents on a shared world model
- TypeScript API Reference — full method signatures and types
Try it
Open ↗⌘↵ to run
Loading engine…