Rensei docs
Graph

Graph Context Injection

Graph triplets into prompts.

Graph context injection composes a ## Knowledge Graph Triplets markdown block at session start, surfacing the most architecturally relevant (source, relationship, target) triplets for the current work item. It works alongside the observation-based memory block - if the graph engine is disabled or returns no results, the block falls back to observations only. The combined block is delivered to the agent over the durable inject rail shortly after a worker claims the session (see Delivery).

Activation

Graph context injection has two independent gates that are AND-combined:

  1. Per-project enablement: isGraphEnabledForProject(orgId, projectId) must be true. That means the project's memory is enabled and graph is on for the project - either via an explicit project_memory_config.graph_enabled = true toggle or because the org's plan grants the kg_enabled feature flag (OR semantics). See Knowledge Graph Store → Per-project enablement. The old org-wide graph_engine_enabled flag no longer exists.
  2. Work-type inclusion: the current session's work type must be selected for graph-augmented recall.

Which work types receive graph context is the operator recall matrix - an operator-configured, per-work-type setting (with per-org overrides) managed in the memory admin console (/admin/memory, operator-only), not static code. The console ships safe defaults: bug_fix, refactor, and feature are graph-augmented; chore is off; unknown work types fall back to included.

Delivery

The block is composed by injectContextForClaimedSession after a worker claims the session, and delivered through the durable session_memory_injects queue: the platform enqueues the rendered block (## Relevant Past Observations + ## Knowledge Graph Triplets), and the session's owning worker pulls and applies it via the daemon's handle.Inject on its next lock-refresh beat - the same rail the in-session injector uses.

Delivery guards:

  • non-empty block only;
  • the project's runtimeInjectEnabled memory sub-toggle must be on (the per-project tenant authority for auto-pushing memory into running sessions) - when it is off, the block is still computed and logged, just not pushed;
  • enqueue is idempotent per (sessionId, contentHash), so a re-claimed session recomputing the identical block is a no-op;
  • fire-and-forget - an enqueue failure never affects the session.

Retrieval query text

The retrieval query used for both observation recall and graph search is composed from the work item, not the raw issue UUID: issue identifier + cached issue title + the first line of the description (read from the platform's Linear issue cache, written on session creation - no extra Linear API calls). It degrades stepwise to identifier-only → issue UUID → session id when fields are missing (retrieval-query.ts).

Block format

The injected markdown block follows the Source → relationship → Target format:

## Knowledge Graph Triplets
- AuthService → depends_on → PostgresDB
- AuthService → implements → IAuthProvider
- UserController → calls → AuthService

Triplets are added in descending importance order until the token budget is exhausted. The budget defaults to 500 tokens (characters / 4). Over-budget triplets are silently skipped - the block never exceeds the budget.

Cedar enforcement

Before any triplet reaches the prompt, buildGraphContextBlock runs Cedar PEP authorization on both endpoint nodes of each triplet. A triplet is included only if both source and target pass enforceGraphAccess with verb: 'read'. Cross-org triplets always fail this check - they cannot reach any agent prompt.

import { buildGraphContextBlock } from '@/lib/memory/graph-context'

const block = await buildGraphContextBlock({
  identity: { agentId, orgId, projectId, sessionId },
  scope: { orgId, projectId },
  engine,          // GraphSearchEngine instance
  queryText,       // natural-language query (same text as observation retrieval)
  budgetTokens: 500,
  topK: 10,
  neighborhoodDepth: 2,
})
// block.block - markdown string (empty if no authorized triplets)
// block.triplets - authorized GraphContextTriplet[]
// block.actualTokens - estimated token usage

The function degrades gracefully on any error (missing embedder, store unavailable, Cedar deny-all) by returning an empty block.

Injection log

The surfaced triplet node IDs are persisted to context_injection_logs alongside the session's other memory context. These IDs are the input to the feedback system: when the session completes, applyFeedback reads the injection log to identify which nodes and edges influenced the agent's work.

interface GraphContextTriplet {
  sourceEntity: string
  relationship: string
  targetEntity: string
  relevanceScore: number      // lower = more relevant
  sourceNodeId: string        // graph_nodes UUID
  targetNodeId: string        // graph_nodes UUID
  provenance?: {
    observationId?: string | null
    sessionId?: string | null
    timestamp?: Date | null
  }
}

Checking graph context at runtime

To verify that graph context is being injected for a session, inspect the injection log:

SELECT graph_node_ids, graph_edge_keys, created_at
FROM context_injection_logs
WHERE session_id = '<session-id>'
ORDER BY created_at DESC
LIMIT 1;

An empty graph_node_ids array means the graph block was not populated (project memory or graph off, work type not selected in the recall matrix, no matching triplets, or Cedar denied everything).

On this page