# klieo-graph-projector

Episode→Graph projector — subscribes to a `ProjectableEpisodic` wrapper
and writes structural facts to a `KnowledgeGraph` so subsequent recalls
have a graph index over the run's tool calls, LLM calls, and bus
events.

**Status:** stable at 2.x. Trait freeze contract recorded in [ADR-039](../../docs/adr/adr-039-graphrag-1-0-promotion.md).

## Layers

- `klieo-core` (Layer 0) — `EpisodicMemory`, `Episode`
- `klieo-memory-graph` (Layer 1) — `KnowledgeGraph` trait + `EntityExtractor`
- **`klieo-graph-projector`** (Layer 2) — this crate

## Quickstart

```toml
[dependencies]
klieo-graph-projector = "2"
klieo-memory-graph    = "2"
```

```rust,no_run
use std::sync::Arc;
use klieo_core::memory::{EpisodicMemory, Scope};
use klieo_graph_projector::{
    EpisodeProjector, HintsOnlyExtractor, ProjectableEpisodic,
};
use klieo_memory_graph::KnowledgeGraph;
use tokio_util::sync::CancellationToken;

# fn run(
#     inner: Arc<dyn EpisodicMemory>,
#     graph: Arc<dyn KnowledgeGraph>,
# ) {
let extractor = Arc::new(HintsOnlyExtractor::default());
let projector = Arc::new(
    EpisodeProjector::builder()
        .build(graph, extractor, Scope::Workspace("acme".into())),
);
let (wrapper, rx) = ProjectableEpisodic::new(inner);
let cancel = CancellationToken::new();
let _handle = Arc::clone(&projector).spawn(rx, cancel);
// Drop the agent's episodic memory into `wrapper` and run as normal —
// projected facts land in `graph` in the background.
# let _ = wrapper; }
```

`EpisodeProjector::builder()` defaults the shared `RecallMetrics`
counter so callers only supply the three domain-required values
(`graph`, `extractor`, `scope`). Override the counter via
`.metrics(Arc::new(my_metrics))` when you want to read
`metrics.snapshot()` from an ops endpoint.

## Advanced wiring — direct constructor

`EpisodeProjector::new(graph, extractor, scope, metrics)` stays
available for callers wanting explicit control over every argument.

## License

MIT.
