Version: 0.4.0
Status: Implemented (lib/matrix.ts)
Last Updated: 2026-04-10
Agence implements a 3-tier matrix model for deterministic, decentralized task orchestration:
\[\text{TASKS} \xrightarrow{\text{aggregate}} \text{WORKFLOWS} \xrightarrow{\text{aggregate}} \text{PROJECTS}\]All computation via Bun TypeScript (lib/matrix.ts). No database — state lives in Git-committed JSON files under organic/.
Design principles:
See SYMBOLS.md for the canonical table.
| Symbol | Meaning | Numeric | Runnable |
|---|---|---|---|
~ |
human-assigned | — | ✓ |
$ |
human-working | — | ✗ (active) |
% |
agent-assigned | — | ✓ |
& |
agent-executing | — | ✗ (active) |
+ |
pending | +1 | ✓ |
- |
completed | -1 | ✗ (done) |
_ |
paused | 0 | ✗ |
# |
held by human | 0 | ✗ |
! |
failure | -1 | ✗ |
? |
awaiting input | — | ✓ |
Dependency operators:
| Symbol | Meaning |
|---|---|
^ |
Hard dependency (blocks downstream) |
; |
Soft dependency (advisory ordering) |
> |
Child task (subtask of parent) |
< |
Parent task (waits for children) |
| Variable | Range | Description |
|---|---|---|
| $P$ | 1–5 | Priority (integer) |
| $S$ | 0+ | Stars — human priority override |
| $H$ | 0.0–1.0 | Heat — complexity/urgency factor |
Higher score = pick first. Agent scheduler selects highest-scoring runnable task.
Matrices use standard linear algebra element notation:
| Matrix | Variable | Element | Description |
|---|---|---|---|
| TASKS | $T$ | $T_{ij}$ | Task $i$, attribute $j$ (state, owner, priority) |
| WORKFLOWS | $W$ | $W_{ik}$ | Workflow $i$, task $k$ completion vector |
| PROJECTS | $P$ | $P_{il}$ | Project $i$, workflow $l$ completion vector |
Aggregation hierarchy:
\[T \xrightarrow{\text{sum}} W \qquad W \xrightarrow{\text{sum}} P\] \[\text{workflow\_completion}_i = \sum_k W_{ik} \qquad \text{project\_completion}_j = \sum_i P_{ij}\]All files live under organic/:
{
"tasks": [
{
"id": "DOC-001",
"repo": "agence",
"title": "Update documentation",
"state": "~",
"priority": 2,
"stars": 1,
"heat": 0.2,
"agent": null,
"created": "2026-04-10T00:00:00Z",
"updated": "2026-04-10T00:00:00Z"
}
]
}
{
"edges": [
{ "from": "DOC-001", "to": "DOC-002", "type": "^" }
]
}
^ hard dependency: downstream task blocked until upstream completes; soft dependency: advisory ordering, does not block{
"workflows": [
{ "id": "WF-BUILD", "title": "Build pipeline", "tasks": ["BUILD-001", "TEST-001", "DEPLOY-001"] }
]
}
{
"projects": [
{ "id": "PROJ-1", "title": "v0.4.0 Release", "workflows": ["WF-BUILD", "WF-DOCS"] }
]
}
{
"agents": [
{ "name": "@ralph", "tier": "cheap", "cost": 1, "capacity": 5, "max_tokens": 2000 },
{ "name": "@sonya", "tier": "mid", "cost": 5, "capacity": 3, "max_tokens": 8000 },
{ "name": "@peers", "tier": "expensive", "cost": 20, "capacity": 1, "max_tokens": 32000 },
{ "name": "@olena", "tier": "local", "cost": 0, "capacity": 2 }
]
}
Each task computes a scalar score. The full task set forms a score vector:
\[\vec{s} = \begin{bmatrix} s_1 \\ s_2 \\ \vdots \\ s_n \end{bmatrix} \quad \text{where } s_i = 10P_i + 25S_i + 100H_i\]Tasks are ranked by descending score. Agent picks the highest-scoring runnable task.
Hard dependencies form a directed acyclic graph (DAG). A task is blocked if any hard dependency (^) has not reached state - (completed):
Cycle detection via DFS prevents circular dependency insertion.
Example blocking chain:
repo:init ──┐
v
repo:build ──> repo:test ──> repo:deploy
^
repo:docs ─────────────────── ; (soft, advisory)
A task is runnable if:
+, ~, %, ?-, _, #, !Filter: state ∈ {+, ~, %, ?} ∧ blockers = ∅
Sort: descending by score
Pick: top N (agent capacity)
Claim: state → & (agent-executing)
State transitions on claim:
Mark claimed tasks → score updates
Completed tasks → workflow row sums update
Workflow completion → project row sums update
All commands via airun matrix <cmd>:
| Command | Description |
|---|---|
score |
Score + rank all tasks (highest first) |
runnable |
Tasks eligible for agent pickup (JSON) |
blocked |
Show blocking dependency chains |
status |
Summary: counts, completion %, workflows |
workflow <id> |
Workflow detail with per-task status |
add <id> <title> |
Add new task (state=~, priority=1) |
set <id> <field> <value> |
Update task field |
assign <id> <agent> |
Assign task to agent (state → %) |
complete <id> |
Mark task completed (state → -) |
dep <from> <to> [^/;] |
Add dependency (default: ^ hard) |
init |
Create empty data files |
# Create tasks
airun matrix add BUILD-001 "Build core module"
airun matrix add TEST-001 "Run test suite"
airun matrix add DOCS-001 "Update documentation"
airun matrix add DEPLOY-001 "Deploy to staging"
# Set priorities and heat
airun matrix set BUILD-001 priority 3
airun matrix set BUILD-001 stars 2
airun matrix set BUILD-001 heat 0.8 # score = 30+50+80 = 160
# Add dependencies: BUILD → TEST → DEPLOY, DOCS → DEPLOY (soft)
airun matrix dep BUILD-001 TEST-001
airun matrix dep TEST-001 DEPLOY-001
airun matrix dep DOCS-001 DEPLOY-001 ";"
# Check state
airun matrix score # BUILD-001(160) > DEPLOY-001(70) > TEST-001(20) > DOCS-001(10)
airun matrix blocked # TEST-001 ⛔ BUILD-001, DEPLOY-001 ⛔ TEST-001
airun matrix runnable # BUILD-001, DOCS-001 (unblocked)
# Execute
airun matrix assign BUILD-001 ralph
airun matrix complete BUILD-001
airun matrix blocked # DEPLOY-001 ⛔ TEST-001 (TEST-001 now unblocked)
Reference snippets for jq and awk matrix operations. The canonical implementation is lib/matrix.ts; these are provided for portability on minimal systems.
# Get tasks assigned to a human
def human_tasks:
map(select(.status | test("^~|\\$")));
# Get tasks assigned to agent
def agent_tasks:
map(select(.status | test("^%|&")));
# Filter by minimum priority
def priority_tasks($min):
map(select(.priority >= $min));
# Sum token costs
def sum_tokens:
map(.token_cost) | add;
# Compute completion %
def completion:
(map(select(.status == "-")) | length) as $done
| ($done / length) * 100;
# matrix.awk — Compute task scores from CSV: id,priority,stars,heat
BEGIN { FS = "," }
{
score = ($2 * 10) + ($3 * 25) + ($4 * 100)
printf "%s\t%d\n", $1, score
}
Each Git fork is both a compute shard and a state shard:
organic/tasks.json (signed source of truth) lives in each shardgit remote add + git fetch --all.ailedger Merkle root snapshots verify integrity across shardsSee SHARDING.md for the full distribution model.
The scoring vector feeds into agent routing:
| Priority × Complexity | T0 (cheap) | T1 (mid) | T2 (expensive) | T3 (critical) |
|---|---|---|---|---|
| Low × Simple | @ralph | @ralph | — | — |
| Low × Complex | @ralph | @sonya | @peers | — |
| High × Simple | @ralph | @sonya | — | — |
| High × Complex | — | @sonya | @peers | @peers |
Agent capacity and cost are tracked in organic/agents.json (future implementation).
| *Implementation: lib/matrix.ts | Data: organic/* |