Weave
Graph analysis, image processing, and content DSL tools for OSINT knowledge graphs.
Weave is a Cargo workspace that publishes Rust crates to crates.io and an Elixir NIF package to hex.pm.
Packages
| Package | Registry | Version | Description |
|---|---|---|---|
weave-graph | crates.io | Conflict-of-interest pattern detection | |
weave-image | crates.io | Thumbnail download, resize, WebP conversion | |
weave-content | crates.io | Content DSL parser, validator, HTML generator | |
rbt_weave | hex.pm | Elixir NIF bridge (graph + image) |
Conflict Detection
weave-graph detects six conflict-of-interest patterns (COI-001 through COI-006) using three algorithms:
- Cycle detection -- directed simple cycles matching edge-type sequences (e.g. payment-appointment kickbacks)
- Path detection -- constrained DFS matching edge types and node labels (e.g. family appointments, payment influence chains)
- Hub detection -- Person-Organization pairs with concentrated influence edges exceeding a threshold
All algorithms operate on in-memory subgraphs extracted from Neo4j with O(1) adjacency lookups. Detection completes in <50ms for subgraphs up to 10K nodes / 50K edges.
Thumbnail Processing
weave-image handles thumbnail generation for entity images:
- Download from URL with 5 MB size limit and 15s timeout
- Center-crop and resize to 256x256 lossless WebP
- Deterministic storage keys via SHA-256 of source URL
- Output capped at 50 KB
Content DSL
weave-content parses, validates, and builds Markdown case files into structured output:
- Parser -- YAML front matter + Markdown sections (entities, relationships, timeline, related cases)
- Validator -- schema validation, enum enforcement, URL format checks, duplicate detection
- URL verifier -- concurrent HEAD/GET checks with caching and configurable concurrency
- Staleness checker -- flags cases that may need updates based on status and timeline gaps
- HTML generator -- produces semantic HTML fragments for case, entity, tag, and country pages
- Sitemap generator -- XML sitemap with cases, entities, countries, and tags
The HTML generator produces fragments (no <html>/<head> wrapper) with data-og-* attributes and Schema.org microdata, suitable for embedding in a Phoenix layout.
Generated pages
| Page | Path | Description |
|---|---|---|
| Case | /cases/{cc}/{type}/{year}/{slug}.html | Full case with entities, timeline, sources |
| Person | /people/{cc}/{slug}.html | Person profile with linked cases |
| Organization | /organizations/{cc}/{slug}.html | Organization profile with linked cases |
| Tag (global) | /tags/{tag}.html | Cases tagged with a specific tag |
| Tag (country) | /tags/{cc}/{tag}.html | Country-scoped tag page |
| Country | /countries/{cc}.html | Cases in a specific country |
| Countries index | /countries.html | All countries with case counts |
| Tags index | /tags.html | All tags with case counts |
| Sitemap | /sitemap.xml | Full XML sitemap |
Elixir Usage
Add rbt_weave to your dependencies:
def deps do
[
{:weave, "~> 0.2", hex: :rbt_weave}
]
endA Rust toolchain (1.88+) is required to compile the NIF.
# Verify NIF is loaded
"ok" = Weave.Graph.health_check()
# Detect conflicts (JSON-in, JSON-out)
{:ok, results_json} = Weave.Graph.detect_conflicts(subgraph_json, opts_json)
# Country name resolution (249 ISO 3166-1 codes)
"Indonesia" = Weave.Content.country_name("id")Rust Usage
Add crates to your Cargo.toml:
[dependencies]
weave-graph = "0.2"
weave-image = "0.2"
weave-content = "0.2"use weave_graph::graph::{Subgraph, IndexedSubgraph};
use weave_graph::detect::{detect_conflicts, DetectOpts};
let subgraph = Subgraph { nodes: vec![/* ... */], edges: vec![/* ... */] };
let indexed = IndexedSubgraph::from_subgraph(&subgraph);
let results = detect_conflicts(&indexed, &DetectOpts::default());Development
make ci # format check + clippy + test (Rust + Elixir)
cargo test # Rust tests only
mix test # Elixir NIF tests onlyLicense
MIT -- see LICENSE for details.