{"id":48801178,"url":"https://github.com/anormang1992/vre","last_synced_at":"2026-04-14T03:01:12.250Z","repository":{"id":342075751,"uuid":"1171200247","full_name":"anormang1992/vre","owner":"anormang1992","description":"Volute Reasoning Engine (VRE): Structural Epistemic Enforcement for Agentic AI","archived":false,"fork":false,"pushed_at":"2026-04-09T15:01:15.000Z","size":226,"stargazers_count":9,"open_issues_count":11,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-09T16:03:48.885Z","etag":null,"topics":["ai","ai-agents","ai-safety","ai-tools","anthropic","claude","claude-code","epistemic-agency","epistemic-ai","knowledge-graph","langchain","langraph","neo4j","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anormang1992.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-03T01:15:15.000Z","updated_at":"2026-04-09T14:06:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"3c25483a-2bed-420e-b3b3-0bef53ffe52c","html_url":"https://github.com/anormang1992/vre","commit_stats":null,"previous_names":["anormang1992/vre"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/anormang1992/vre","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anormang1992%2Fvre","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anormang1992%2Fvre/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anormang1992%2Fvre/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anormang1992%2Fvre/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anormang1992","download_url":"https://codeload.github.com/anormang1992/vre/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anormang1992%2Fvre/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31779947,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T02:24:21.117Z","status":"ssl_error","status_checked_at":"2026-04-14T02:24:20.627Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agents","ai-safety","ai-tools","anthropic","claude","claude-code","epistemic-agency","epistemic-ai","knowledge-graph","langchain","langraph","neo4j","python"],"created_at":"2026-04-14T03:01:11.492Z","updated_at":"2026-04-14T03:01:12.231Z","avatar_url":"https://github.com/anormang1992.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg width=\"800\" height=\"800\" alt=\"vre_logo\" src=\"https://github.com/user-attachments/assets/b5431335-c4a7-4a85-a251-601c5b11627f\" /\u003e\n\n# VRE — Volute Reasoning Engine\n\n**Epistemic enforcement for autonomous agents.**\n\nVRE is a Python library that gives autonomous agents an explicit, inspectable model of what they know before they act.\nIt is not a permissions system, a rules engine, or a safety classifier. It is a mechanism for making an agent's\nknowledge boundary a first-class object — one that can be queried, audited, and enforced at runtime.\n\n  ---\n\n## Table of Contents\n\n- [The Problem](#the-problem)\n- [How It Works](#how-it-works)\n    - [The Epistemic Graph](#the-epistemic-graph)\n    - [Relata](#relata)\n    - [Knowledge Gaps](#knowledge-gaps)\n    - [Layered Safety](#layered-safety)\n- [Scope](#scope)\n- [Getting Started](#getting-started)\n    - [Installation](#installation)\n    - [Infrastructure](#infrastructure)\n    - [Seeding the Graph](#seeding-the-graph)\n- [Core API](#core-api)\n    - [Connecting to VRE](#connecting-to-vre)\n    - [Agent Identity](#agent-identity)\n    - [Checking Grounding](#checking-grounding)\n    - [Using the Trace as Agent Context](#using-the-trace-as-agent-context)\n    - [Checking Policy](#checking-policy)\n- [The `vre_guard` Decorator](#the-vre_guard-decorator)\n    - [Parameters](#parameters)\n    - [Execution Flow](#execution-flow)\n- [Callbacks](#callbacks)\n    - [`on_trace`](#on_trace)\n    - [`on_policy`](#on_policy)\n    - [`on_learn`](#on_learn)\n- [Auto-Learning](#auto-learning)\n    - [How It Works](#how-it-works-1)\n    - [Candidate Types](#candidate-types)\n    - [Decisions and Provenance](#decisions-and-provenance)\n    - [Two-Phase Edge Placement](#two-phase-edge-placement)\n    - [The `LearningCallback` ABC](#the-learningcallback-abc)\n- [Policy System](#policy-system)\n    - [Defining Policies](#defining-policies)\n    - [Policy Callbacks](#policy-callbacks)\n    - [Evaluation Flow](#evaluation-flow)\n    - [Policy Wizard](#policy-wizard)\n- [Integrations](#integrations)\n    - [LangChain + Ollama Reference Agent](#langchain--ollama-reference-agent)\n    - [Claude Code Hook](#claude-code-hook)\n- [Future](#future)\n- [Tech Stack](#tech-stack)\n- [Project Structure](#project-structure)\n- [Contributing](#contributing)\n\n---\n\n## The Problem\n\nModern LLM-based agents fail in a specific and consistent way: they act as if they know more than they can justify.\n\nThis is not a capability problem. The models are capable. It is an *epistemic* problem — the agent has no internal\nrepresentation of the boundary between what it genuinely understands and what it is\nconfabulating. Hallucination, unsafe execution, and overconfident planning are all symptoms of the same root cause: **epistemic opacity**.\n\nWhen an agent is asked to delete files, migrate a database, or execute a shell command, the question is not only \"can I\ndo this?\" but \"do I actually understand what I am doing well enough to do it\nsafely?\" Current systems have no mechanism to answer that second question. They proceed anyway.\n\nThis is not hypothetical. In December 2025, Amazon's Kiro agent — given operator-level access to fix a small issue in\nAWS Cost Explorer — decided the correct approach was to delete and recreate the\nenvironment entirely, causing\na [13-hour outage](https://www.theregister.com/2026/02/20/amazon_denies_kiro_agentic_ai_behind_outage/). In February\n2026, [OpenClaw deleted the\ninbox](https://techcrunch.com/2026/02/23/a-meta-ai-security-researcher-said-an-openclaw-agent-ran-amok-on-her-inbox/) of\nSummer Yue — Meta's Director of AI Alignment — after context window compaction\nsilently discarded her instruction to wait for approval before taking action. In each case, the agent acted confidently\non knowledge it could not justify. The safety constraints were linguistic —\ninstructions that could be forgotten, overridden, or reasoned around. VRE's constraints are structural.\n\nVRE addresses this directly. It imposes a contract: before an action executes, the agent must demonstrate that the\nrelevant concepts are grounded in the knowledge graph at the depth required for\nexecution. If they are not, the action is blocked and the gap is surfaced explicitly. The agent does not guess. It does\nnot proceed on partial knowledge. It is structurally incapable of executing an\naction it does not understand with respect to its epistemic model — and perhaps more importantly, it surfaces what it\ndoes not know. Absence of knowledge is treated as a first-class object.\n\n\u003cimg width=\"3168\" height=\"710\" alt=\"image\" src=\"https://github.com/user-attachments/assets/4fedf455-a5d2-4443-acb5-ba85ac99f15c\" /\u003e\n\n---\n\n## How It Works\n\n### The Epistemic Graph\n\nVRE maintains a graph of **primitives** — conceptual entities like `file`, `create`, `permission`, `directory`. These\nare not tools or commands. They are concepts: the things an agent reasons *about*, not the mechanisms it uses to act.\n\nEach primitive is grounded across a hierarchy of **depth levels**:\n\n| Depth | Name         | Question answered                       |\n|-------|--------------|-----------------------------------------|\n| D0    | EXISTENCE    | Does this concept exist?                |\n| D1    | IDENTITY     | What is it, in principle?               |\n| D2    | CAPABILITIES | What can happen to it / what can it do? |\n| D3    | CONSTRAINTS  | Under what conditions does that hold?   |\n| D4+   | IMPLICATIONS | What follows if it happens?             |\n\nDepth is **monotonic**: D3 grounding implies D0–D2 are also grounded. Depth requirements are derived from the graph\nstructure itself — edges carry a source depth that determines when they become\nvisible and a target depth that determines when they resolve. An integrator can also enforce a minimum depth floor (e.g.\nD3 for execution) as a secondary safety lever.\n\n### Relata\n\nPrimitives are connected by typed, directional, depth-aware **relata**:\n\n```\ncreate --[APPLIES_TO @ D2]--\u003e file\nfile   --[CONSTRAINED_BY @ D3]--\u003e permission\n```\n\nA relatum declares that understanding one concept at a given depth requires understanding another concept at a specified\ndepth. When VRE resolves a grounding query, it follows these dependencies and checks that the entire connected subgraph\nmeets the required depth. A relational gap — where a dependency's target is not grounded deeply enough — is surfaced as\na distinct gap type.\n\n### Knowledge Gaps\n\nWhen grounding fails, VRE returns structured gap objects — not generic errors. There are four gap types:\n\n| Type              | Meaning                                                          |\n|-------------------|------------------------------------------------------------------|\n| `ExistenceGap`    | The concept is not in the graph at all                           |\n| `DepthGap`        | The concept exists but is not grounded to the required depth     |\n| `RelationalGap`   | A relatum's target does not meet the depth required by that edge |\n| `ReachabilityGap` | The concept is not connected to the other submitted concepts     |\n\nGaps are not failures to be hidden. They are information. An existence gap on `network` tells you the agent has no\nepistemic model of networking — not that the request was malformed. The agent can\nsurface this gap to the user, initiate a learning flow, or escalate to a human.\n\nVRE does not require a complete or richly-detailed graph to be useful. The enforcement mechanism is structural — depth\nrequirements are derived from edge placement. A minimal graph with a handful of\nprimitives enforces the contract correctly. A richer graph adds better context, not stronger enforcement.\n\n### Layered Safety\n\nVRE is one layer of a deliberately layered safety model:\n\n1. **Epistemic safety (VRE)** — prevents unjustified action. The agent cannot act on what it does not understand.\n2. **Mechanical safety (tool constraints)** — constrains *how* the agent can act. Sandboxing, path restrictions,\n   resource guards.\n3. **Human safety (policy gates)** — requires explicit consent for elevated or destructive actions.\n\nVRE governs only the first layer, by design. It does not replace sandboxing. It does not replace human oversight. It\nmakes those layers more meaningful by ensuring the agent understood what it was\ndoing when it asked for permission to act.\n\n---\n\n## Scope\n\n**VRE is not a sandbox.** It does not isolate processes, restrict filesystem access, or enforce OS-level permissions. It\noperates at the epistemic layer — determining whether an action is justified,\nnot whether it is physically permitted.\n\n**VRE is not a safety classifier.** It does not scan outputs for harmful content or filter model responses. It gates\nexecution, not generation.\n\n**VRE is not a replacement for human oversight.** Its policy gates are a mechanism for human oversight — surfacing\ndecisions that require consent and blocking until consent is given.\n\n---\n\n## Getting Started\n\n### Installation\n\n```bash\npip install vre\n# or with Poetry\npoetry add vre\n```\n\nAfter installation, download the spaCy language model:\n\n```bash\npython -m spacy download en_core_web_sm\n```\n\n### Infrastructure\n\nVRE requires a running Neo4j instance for the epistemic graph:\n\n```bash\ndocker run -d \\\n--name neo4j \\\n-p 7474:7474 -p 7687:7687 \\\n-e NEO4J_AUTH=neo4j/password \\\nneo4j:latest\n```\n\nIf you already have neo4j installed locally, ensure it is running and note the connection details\n(URI, username, password) for use in the next steps.\n\n### Seeding the Graph\n\nThe VRE repository includes seed scripts that populate the graph with testing scenarios. Each script clears the graph before seeding\nto ensure a clean slate. See [`scripts/README.md`](scripts/README.md) for full\ndetails.\n\n```bash\n# Fully grounded graph — 16 primitives, all at D3 with complete relata\npoetry run python scripts/seed_all.py \\\n--neo4j-uri neo4j://localhost:7687 --neo4j-user neo4j --neo4j-password password\n\n# Gap demonstration graph — 10 primitives, deliberately shaped to produce each gap type\npoetry run python scripts/seed_gaps.py \\\n--neo4j-uri neo4j://localhost:7687 --neo4j-user neo4j --neo4j-password password\n```\n\n---\n\n## Core API\n\n### Connecting to VRE\n\n```python\nfrom vre import VRE\nfrom vre.core.graph import PrimitiveRepository\n\nrepo = PrimitiveRepository(\n    uri=\"neo4j://localhost:7687\",\n    user=\"neo4j\",\n    password=\"password\",\n)\nvre = VRE(repo)\n```\n\n### Agent Identity\n\nAn optional `agent_key` associates the VRE instance with a stable agent identity. The key is resolved via a file-based\nregistry (`~/.vre/agents.json`) so that the same key always maps to the same UUID,\neven across restarts. When configured, every `GroundingResult` carries the agent's `agent_id`.\n\n```python\nvre = VRE(repo, agent_key=\"my-agent\", agent_name=\"My Agent\")\n\nvre.identity.agent_id  # stable UUID, persisted across restarts\nvre.identity.name  # \"My Agent\"\n```\n\n`agent_name` is a human-readable label used only on first registration — subsequent calls with the same key return the\nexisting identity. Both parameters are optional; without `agent_key`, traces are\nanonymous and `vre.identity` is `None`. You may also pass `registry_path` to customize the registry file location (\ndefault: `~/.vre/agents.json`).\n\n### Checking Grounding\n\n```python\nresult = vre.check([\"create\", \"file\"])\n\nprint(result.grounded)  # True / False\nprint(result.resolved)  # [\"create\", \"file\"] — canonical names after resolution\nprint(result.gaps)  # [] or list of KnowledgeGap instances\nprint(result)  # Full formatted epistemic trace\n```\n\n`vre.check()` derives depth requirements from graph structure — edges at higher source depths are only visible when the\nsource primitive is grounded to that depth. An optional `min_depth` parameter\nlets integrators enforce a stricter floor (e.g. D3 for execution). If any concept is unknown, lacks the required depth,\nhas an unmet relational dependency, or is disconnected from the other submitted\nconcepts, `grounded` is `False` and the corresponding gaps are surfaced.\n\n### Using the Trace as Agent Context\n\n`vre.check()` can be called before an agent runs to pre-load the epistemic trace into the model's context window. Rather\nthan letting the LLM reason from general knowledge alone, you give it the\ngraph's structured understanding of the relevant concepts before it decides what to do.\n\n```python\nresult = vre.check([\"delete\", \"file\"])\n\nif result.grounded:\n    context = str(result)  # full structured trace, formatted for readability\n    response = llm.invoke([\n        SystemMessage(content=\"You are a filesystem agent.\"),\n        SystemMessage(content=f\"Epistemic context:\\n{context}\"),\n        HumanMessage(content=user_input),\n    ])\nelse:\n    for gap in result.gaps:\n        print(f\"Knowledge gap: {gap}\")\n```\n\nThis is particularly useful for planning-mode interactions: the agent receives structured knowledge of what it\nunderstands (and at what depth) before it proposes an action.\n\n### Checking Policy\n\n```python\npolicy = vre.check_policy([\"delete\", \"file\"], cardinality=\"multiple\")\n\nif policy.action == \"BLOCK\":\n    print(policy.reason)\n    for v in policy.violations:\n        print(f\"  - {v.message}\")\n```\n\n`cardinality` hints whether the operation targets a single entity (`\"single\"`) or many (`\"multiple\"`, e.g. recursive or\nglob). An optional `on_policy` callback handles violations that require human\nconfirmation — it receives only the confirmation-required violations and returns `True` to proceed or `False` to block.\n\n---\n\n## The `vre_guard` Decorator\n\n`vre_guard` is the primary integration point. It wraps any callable and gates it behind a grounding check and a policy\nevaluation before the function body executes. This is designed to wrap the tools\nyour agent uses to act on the world, ensuring that every action is epistemically justified and compliant with your\ndefined policies.\n\n```python\nfrom vre.guard import vre_guard\n\n@vre_guard(vre, concepts=[\"write\", \"file\"])\ndef write_file(path: str, content: str) -\u003e str:\n    ...\n```\n\n### Parameters\n\n```python\nvre_guard(\n    vre,              # VRE instance\n    concepts,         # list[str] or Callable(*args, **kwargs) -\u003e list[str]\n    cardinality=None, # str | None or Callable(*args, **kwargs) -\u003e str | None\n    min_depth=None,   # DepthLevel | None — enforces a minimum depth floor\n    on_trace=None,    # Callable[[GroundingResult], None]\n    on_policy=None,   # Callable[[list[PolicyViolation]], bool]\n    on_learn=None,    # LearningCallback — auto-learning loop for knowledge gaps\n)\n```\n\n**`concepts`** can be static or dynamic. Static is appropriate when a function always touches the same concept domain.\nDynamic is appropriate when the concepts depend on the actual arguments — for\nexample, a shell tool that must inspect the command string:\n\n```python\nconcepts = ConceptExtractor()  # LLM-based — see examples/langchain_ollama/callbacks.py\n\n@vre_guard(vre, concepts=concepts)\ndef shell_tool(command: str) -\u003e str:\n    ...\n ```\n\nVRE does not own concept extraction. The integrator decides how to map tool arguments to primitives — an LLM call, a\nstatic alias table, a rule engine, or any combination.\n\n**`cardinality`** can also be static or dynamic. When dynamic, it receives the same arguments as the decorated function:\n\n```python\ndef get_cardinality(command: str) -\u003e str:\n    flags = {\"-r\", \"-R\", \"-rf\", \"--recursive\"}\n    tokens = set(command.split())\n    has_glob = any(\"*\" in t for t in tokens)\n    return \"multiple\" if (flags \u0026 tokens or has_glob) else \"single\"\n\n@vre_guard(vre, concepts=concepts, cardinality=get_cardinality)\ndef shell_tool(command: str) -\u003e str:\n    ...\n ```\n\n### Execution Flow\n\nEach call runs the following sequence:\n\n1. **Resolve concepts** — map names to canonical primitives via the graph\n2. **Ground** — verify the subgraph meets depth requirements (graph-derived + optional `min_depth` floor)\n3. **Fire `on_trace`** — surface the epistemic result to the caller\n4. **If not grounded and `on_learn` is present** — enter the [auto-learning loop](#auto-learning)\n5. **Fire `on_trace` again** — surface the post-learning epistemic result\n6. **If still not grounded** — return the `GroundingResult` immediately; the function does not execute\n7. **Evaluate policies** — check all `APPLIES_TO` relata for applicable policy gates\n8. **If hard blocks** — return `PolicyResult(BLOCK)` immediately; `on_policy` is not consulted\n9. **If confirmation required** — call `on_policy` with pending violations; block if declined or no handler\n10. **If BLOCK** — return the `PolicyResult`; the function does not execute\n11. **Execute** — call the original function and return its result\n\n---\n\n## Callbacks\n\n### `on_trace`\n\nCalled after grounding, whether grounded or not. Receives the full `GroundingResult`. Use this to render the epistemic\ntrace to your UI.\n\n```python\ndef on_trace(grounding: GroundingResult) -\u003e None:\n    if grounding.grounded:\n        print(f\"Grounded: {grounding.resolved}\")\n    else:\n        for gap in grounding.gaps:\n            print(f\"Gap: {gap}\")\n```\n\n`GroundingResult` carries:\n\n- `grounded: bool` — whether all concepts are grounded with no gaps\n- `resolved: list[str]` — canonical primitive names (or original if unresolvable)\n- `gaps: list[KnowledgeGap]` — structured gap descriptions (`ExistenceGap`, `DepthGap`, `RelationalGap`,\n  `ReachabilityGap`)\n- `trace: EpistemicResponse | None` — the full subgraph with all primitives, depths, relata, and pathway\n- `agent_id: UUID | None` — the stable agent identifier, when the VRE instance was created with an `agent_key`\n\nThe reference integration renders `on_trace` as a Rich tree:\n\n```\nVRE Epistemic Check\n├── ◈ create   ● ● ● ●\n│   ├── APPLIES_TO  →  file       (target D2)\n│   └── REQUIRES    →  filesystem (target D3)\n├── ◈ file   ● ● ● ●\n│   └── CONSTRAINED_BY  →  permission  (target D3)\n└── ✓ Grounded — EPISTEMIC PERMISSION GRANTED\n```\n\n\u003cimg width=\"2786\" height=\"1462\" alt=\"image\" src=\"https://github.com/user-attachments/assets/91d2ba34-716a-4d70-8c15-148a11e6c2b7\" /\u003e\n\n### `on_policy`\n\nCalled when policy evaluation produces violations that require human confirmation (`requires_confirmation=True`). Hard\nblocks (`requires_confirmation=False`) are handled before `on_policy` is ever\nconsulted. Returns `True` to proceed, `False` to block.\n\n```python\nfrom vre.core.policy.models import PolicyViolation\n\n\ndef on_policy(violations: list[PolicyViolation]) -\u003e bool:\n    for v in violations:\n        answer = input(f\"Policy gate: {v.message} [y/N]: \").strip().lower()\n        if answer != \"y\":\n            return False\n    return True\n```\n\nIf `on_policy` is not provided and a policy requires confirmation, the guard returns\n`PolicyResult(action=PolicyAction.BLOCK)` and the function does not execute.\n\n\u003cimg width=\"1392\" height=\"714\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8b701635-d4ca-4511-98e3-cda82a5dde38\" /\u003e\n\n\n### `on_learn`\n\nCalled when grounding fails and the guard enters the auto-learning loop. See [Auto-Learning](#auto-learning) for\ndetails.\n\n---\n\n## Auto-Learning\n\nWhen grounding fails and an `on_learn` callback is present, VRE enters an iterative learning loop that transforms\nknowledge gaps into graph growth. Rather than simply blocking the action, VRE surfaces\nstructured templates for each gap, invokes the callback to fill them, and persists accepted knowledge back to the\ngraph — then re-grounds to see if the action is now justified.\n\nThis is VRE's answer to its primary adoption bottleneck: manual graph authoring. The graph grows through use.\n\n### How It Works\n\n1. **Gap detected** — grounding check reveals one or more knowledge gaps\n2. **Template created** — VRE generates a structured candidate template based on the gap type\n3. **Callback invoked** — the integrator's `on_learn` callback receives the template, the full grounding result, and the\n   specific gap. The callback fills the template (via LLM, user input, or any other\n   mechanism) and returns a decision.\n4. **Persistence** — accepted or modified candidates are persisted to the graph with provenance tracking\n5. **Re-ground** — VRE re-checks grounding. The gap landscape may have shifted — new gaps may have appeared, existing\n   ones may be resolved. The loop continues until grounded, all gaps are addressed, or\n   the user rejects.\n\n### Candidate Types\n\nEach gap type has a corresponding candidate model. Candidates carry only what's *new* — all context (primitive IDs,\nexisting depths, required depths) lives on the gap itself.\n\n| Gap Type          | Candidate               | What the Agent Fills In                                                |\n|-------------------|-------------------------|------------------------------------------------------------------------|\n| `ExistenceGap`    | `ExistenceCandidate`    | D1 identity for a new concept (D0 is auto-generated)                   |\n| `DepthGap`        | `DepthCandidate`        | Missing depth levels with properties                                   |\n| `RelationalGap`   | `RelationalCandidate`   | Missing depth levels on the edge target                                |\n| `ReachabilityGap` | `ReachabilityCandidate` | Edge placement: target name, relation type, source/target depth levels |\n\n`ExistenceCandidate`, `DepthCandidate`, and `RelationalCandidate` all use `ProposedDepth`:\n\n```python\nfrom vre.learning.models import ProposedDepth\n\nProposedDepth(\n    level=DepthLevel.CAPABILITIES,\n    properties={\"operations\": [\"read\", \"write\"], \"attributes\": [\"size\", \"permissions\"]},\n)\n```\n\n### Decisions and Provenance\n\nThe callback returns one of four decisions, and provenance is derived from what actually happened:\n\n| Decision   | Effect                                               | Provenance       |\n|------------|------------------------------------------------------|------------------|\n| `ACCEPTED` | Persist as proposed                                  | `learned`        |\n| `MODIFIED` | Persist after user refinement                        | `conversational` |\n| `SKIPPED`  | Intentionally dismissed — loop continues to next gap | —                |\n| `REJECTED` | Discard — stops the learning loop entirely           | —                |\n\n`SKIPPED` is particularly important for reachability gaps: the absence of an edge can itself be an enforcement\nmechanism. If a concept *should not* be connected, the user skips rather than placing an\nedge.\n\n### Two-Phase Edge Placement\n\nReachability candidates focus solely on edge placement — they declare *where* the edge goes, not what depths need to\nexist. If the source or target lacks the declared depth level, the engine\nautomatically synthesizes a `DepthGap` and invokes the callback to learn the missing depths *before* placing the edge.\nThis keeps each candidate type focused on its single concern while handling\ncascading dependencies naturally.\n\n### The `LearningCallback` ABC\n\n```python\nfrom vre.learning.callback import LearningCallback\nfrom vre.learning.models import LearningCandidate, CandidateDecision\n\n\nclass MyLearner(LearningCallback):\n    def __call__(self, candidate, grounding, gap) -\u003e tuple[LearningCandidate | None, CandidateDecision]:\n        # Fill the template, present to user, return (filled, decision)\n        ...\n```\n\n`LearningCallback` is an abstract base class with `__call__` as the only required method. It also supports context\nmanager lifecycle via `__enter__` and `__exit__` (default no-ops) — `learn_all` wraps\nthe session in `with callback:`, allowing callbacks to manage state across a learning session.\n\n### Example\n\nThe following walkthrough uses the `seed_gaps` script and attempts to create and write to a file. The learning loop\nresolves several knowledge gaps through agent-user conversational turns:\n\n1. **Existence Gap** — `write` did not exist in the graph\n2. **Reachability Gap** — no edges connecting `write` and `file`\n3. **Depth Gaps** — both `write` and `file` were missing the depths required by the edge placement\n\n\u003cimg width=\"3372\" height=\"906\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2c73380d-dbf9-4acd-8f74-f492c46f468a\" /\u003e\n\n\u003cimg width=\"3410\" height=\"1520\" alt=\"image\" src=\"https://github.com/user-attachments/assets/23a7fe9c-8ae5-490d-b7c7-7638abd0c90b\" /\u003e\n\n\u003cimg width=\"3406\" height=\"850\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8b31127f-bd50-4549-aa70-4d0bef281633\" /\u003e\n\n\u003cimg width=\"3404\" height=\"1498\" alt=\"image\" src=\"https://github.com/user-attachments/assets/cd7852f3-df99-4a83-8070-a5293d4332c4\" /\u003e\n\nOf note: the agent correctly identified additional relata that should be attached to the `File` primitive and attempted\nto record them in the `properties` object. This indicates the agent is reasoning\nfrom within the epistemic envelope defined by the grounding trace, using neighboring primitives in the subgraph to\nenrich its own proposals.\n\nThe repository includes a reference `DemoLearner` implementation (`examples/langchain_ollama/learner.py`) that uses\nChatOllama structured output to fill templates and Rich to present proposals. The\nuser chooses: accept, modify (provide feedback, LLM re-proposes), skip, or reject.\n\n---\n\n## Policy System\n\nPolicies live on `APPLIES_TO` relata. They define human-in-the-loop gates for specific concept relationships: which\nactions require confirmation, under what cardinality conditions they fire, and what\nconfirmation message to surface.\n\n### Defining Policies\n\n```python\nfrom vre.core.policy.models import Policy, Cardinality\n\nPolicy(\n    name=\"confirm_file_deletion\",\n    requires_confirmation=True,\n    trigger_cardinality=Cardinality.MULTIPLE,  # fires on recursive/glob ops\n    confirmation_message=\"This will delete multiple files. Proceed?\",\n)\n```\n\n### Policy Callbacks\n\nA `PolicyCallback` is a callable attached to a `Policy` that runs *during* evaluation to make domain-specific pass/fail\ndecisions. This is distinct from `on_policy`, which handles human confirmation\n*after* violations are collected. A policy callback determines whether a violation fires at all.\n\nThe callback receives a `PolicyCallContext` containing the tool name, the full grounding result, and the original\nfunction arguments. It returns a `PolicyCallbackResult` — `passed=True` suppresses the\nviolation, `passed=False` fires it.\n\n```python\nfrom vre.core.policy.callback import PolicyCallback, PolicyCallContext\nfrom vre.core.policy.models import PolicyCallbackResult\n\n\nclass BlockProtectedFiles:\n    \"\"\"Block deletion of files matching 'protected*'.\"\"\"\n\n    def __call__(self, context: PolicyCallContext) -\u003e PolicyCallbackResult:\n        command = context.call_args[0] if context.call_args else \"\"\n        targets = [t for t in command.split()[1:] if not t.startswith(\"-\")]\n\n        for target in targets:\n            if target.startswith(\"protected\"):\n                return PolicyCallbackResult(\n                    passed=False,\n                    message=f\"'{target}' is a protected file.\",\n                )\n\n        return PolicyCallbackResult(passed=True, message=\"No protected files affected.\")\n```\n\nCallbacks are registered on a `Policy` via a dotted import path, resolved at evaluation time:\n\n```python\nPolicy(\n    name=\"protected_file_guard\",\n    requires_confirmation=False,  # hard block — no confirmation prompt\n    trigger_cardinality=None,\n    # fires on any cardinality\n    callback=\"myproject.policies.BlockProtectedFiles\",  # dotted path to the callable\n    confirmation_message=\"Deletion blocked by protected file policy.\",\n)\n```\n\nA single relatum can carry multiple policies with different callbacks — one that checks file patterns, another that\nchecks time-of-day, another that checks user role — and each independently decides\nwhether its violation fires.\n\nThe repository includes a reference `protected_file_delete` callback (`examples/langchain_ollama/policies.py`) that\ninspects `rm` commands across three detection modes: literal filename match, glob\nexpansion against the filesystem, and recursive directory inspection. It demonstrates how a callback can make nuanced,\ncontext-aware decisions by inspecting both the command arguments and the actual\nfilesystem state.\n\n### Evaluation Flow\n\n1. **Cardinality filter** — if the policy specifies a `trigger_cardinality`, it only fires when the operation's\n   cardinality matches\n2. **Callback evaluation** — if a callback is registered, it runs with the full call context. `passed=True` suppresses\n   the violation entirely\n3. **Violation collection** — unsuppressed policies produce `PolicyViolation` objects\n4. **Hard blocks vs confirmation** — violations with `requires_confirmation=False` are immediate blocks. Those with\n   `requires_confirmation=True` are deferred to the `on_policy` handler\n\n### Policy Wizard\n\nThe wizard provides an interactive CLI to attach policies to `APPLIES_TO` relata without manually editing seed scripts:\n\n```bash\npoetry run python -m vre.core.policy.wizard\n```\n\nIt walks you through selecting source and target primitives, viewing the relata table, defining policy fields, and\npersisting the result to the graph.\n\n\u003cimg width=\"1968\" height=\"1592\" alt=\"image\" src=\"https://github.com/user-attachments/assets/81257f0f-4273-4235-85ca-dcb50c21439b\" /\u003e\n\n---\n\n## Integrations\n\nThe repository includes reference integrations that demonstrate how to wire VRE into real agent frameworks. These are\nnot part of the `vre` package — they live in the `examples/` directory and are\nmeant to be read, adapted, and used as starting points for your own integration.\n\n### LangChain + Ollama Reference Agent\n\n`examples/langchain_ollama/` contains a complete LangChain + Ollama agent that exercises all of VRE's enforcement layers\nagainst a sandboxed filesystem.\n\n#### Prerequisites\n\nIn addition to Neo4j, this example requires [Ollama](https://ollama.com/) running locally:\n\n```bash\nbrew install ollama\nollama pull qwen3:8b\n```\n\nInstall the example dependencies:\n\n```bash\npoetry install --extras examples\n```\n\n#### Running\n\n```bash\npoetry run python -m examples.langchain_ollama.main \\\n    --neo4j-uri neo4j://localhost:7687 \\\n    --neo4j-user neo4j \\\n    --neo4j-password password \\\n    --model qwen3:8b \\\n    --concepts-model qwen2.5-coder:7b \\\n    --sandbox examples/langchain_ollama/workspace\n```\n\nThe agent exposes a single `shell_tool` — a sandboxed subprocess executor — guarded by `vre_guard`. Every shell command\nthe LLM decides to run is intercepted before execution:\n\n1. A `ConceptExtractor` sends the command to a local LLM to identify conceptual primitives (`touch foo.txt` -\u003e\n   `[\"create\", \"file\"]`)\n2. Those concepts are grounded against the graph\n3. The epistemic trace is rendered to the terminal via `on_trace`\n4. Applicable policies are evaluated\n5. If a policy fires, `on_policy` prompts for confirmation before the command runs\n\n**The agent cannot execute a command whose conceptual domain it does not understand**, and it cannot bypass policies\nthat require human confirmation.\n\n#### Concept Extraction\n\n`ConceptExtractor` (`examples/langchain_ollama/callbacks.py`) sends each command segment to a local Ollama model and\ncollects the conceptual primitives it identifies. The prompt includes few-shot\nflag-to-concept examples (e.g. `rm -rf dir/` -\u003e delete + directory + file) and an explicit instruction to never return\nflag names as primitives.\n\nIt splits compound commands (pipes, `\u0026\u0026`, `;`) into segments and extracts concepts from each independently. The model is\nconfigurable via `--concepts-model` (default `qwen2.5-coder:7b`).\n\n`get_cardinality` is a simple rule-based function that inspects flags and globs — no LLM needed. Integrators can mix LLM\nand rule-based strategies for different parameters.\n\n#### Wiring It Together\n\n```python\nfrom vre.guard import vre_guard\n\nconcepts = ConceptExtractor()\n\n\n@vre_guard(\n    vre,\n    concepts=concepts,  # LLM extracts primitives from command string\n    cardinality=get_cardinality,\n    # inspects flags/globs -\u003e \"single\" or \"multiple\"\n    on_trace=on_trace,  # renders epistemic tree to terminal\n    on_policy=on_policy,\n    # Rich Confirm.ask prompt\n    on_learn=on_learn,  # auto-learning callback for knowledge gaps\n)\ndef shell_tool(command: str) -\u003e str:\n    result = subprocess.run(command, shell=True, capture_output=True, text=True, cwd=sandbox)\n    return result.stdout + result.stderr\n```\n\n### Claude Code Hook\n\n`examples/claude-code/` contains a [PreToolUse hook](https://docs.anthropic.com/en/docs/claude-code/hooks)\nfor [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) that intercepts\nevery Bash tool call before execution and gates it through VRE grounding and policy evaluation. Unlike the LangChain\nexample — which uses a local Ollama model for concept extraction — this integration\nlets Claude itself propose the conceptual primitives, using a two-pass protocol.\n\n#### Install\n\n```bash\npoetry run python examples/claude-code/claude_code.py install \\\n    --uri neo4j://localhost:7687 --user neo4j --password password\n```\n\nThis writes your Neo4j connection details to `~/.vre/config.json` and injects a `PreToolUse` hook entry into\n`~/.claude/settings.json` that matches all `Bash` tool calls. Safe to call multiple times —\nexisting VRE hook entries are replaced, not duplicated.\n\n#### How It Works\n\nThe hook uses a **two-pass protocol** that lets Claude propose the concepts:\n\n**Pass 1 — Concept Request:**\n\n1. Claude invokes a Bash command (e.g. `rm -rf foo/`)\n2. The hook sees no `# vre:` prefix and blocks (exit 2), asking Claude to identify the conceptual primitives and retry\n   with a `# vre:concept1,concept2` prefix\n\n**Pass 2 — Epistemic Check:**\n\n3. Claude reasons about the command, identifies primitives, and retries: `# vre:delete,file,directory\\nrm -rf foo/`\n4. The hook extracts the concepts and grounds them against the graph\n5. **If not grounded** — blocks with the full grounding trace as context\n6. **If confirmation-required** — returns `permissionDecision: \"ask\"`, deferring to Claude Code's native TUI approval\n   prompt\n7. **If hard blocks or user declines** — blocks with the policy result\n8. **If grounded, no violations** — allows execution with the `# vre:` prefix stripped\n\nThe `# vre:` line is a shell comment — inert if executed directly. The hook strips it via `updatedInput` before the\ncommand runs.\n\n\u003cimg width=\"1638\" height=\"788\" alt=\"Screenshot 2026-03-04 at 10 34 15 AM\" src=\"https://github.com/user-attachments/assets/d8bbf86e-fe71-4fa5-b6a2-c4865aedf291\" /\u003e\n\n\u003cimg width=\"1627\" height=\"780\" alt=\"Screenshot 2026-03-04 at 10 55 10 AM\" src=\"https://github.com/user-attachments/assets/a8c6f466-8fe2-4831-8c88-9e4d463e1f13\" /\u003e\n\n#### Uninstall\n\n```bash\npoetry run python examples/claude-code/claude_code.py uninstall\n```\n\nRemoves the VRE hook entry from `~/.claude/settings.json` and leaves `~/.vre/config.json` in place.\n\n---\n\n## Future\n\n### Learning Through Failure\n\nWhen a mechanical failure occurs during execution — permission denied, missing dependency, invalid path — the failure\nreveals a constraint that was not modeled. The agent proposes the missing relatum\n(e.g. `create --[CONSTRAINED_BY]--\u003e permission`), seeks human validation, and persists the new knowledge. Depth was\nhonest before the failure and more complete after.\n\n### VRE Networks\n\nAn agentic network of agents that share grounded knowledge across different epistemic graphs while applying the same\nenforcement mechanisms. A concept grounded at D3 in one agent's graph carries its\nepistemic justification with it — the network federates knowledge while keeping each agent's epistemic contract intact.\n\n### Epistemic Memory\n\nA new class of memory that stores not just information but the agent's epistemic relationship to that information.\nMemories are indexed by concept and depth, decay or are reinforced based on usage and\ngrounding history, and affect the agent's confidence in related concepts.\n\n---\n\n## Tech Stack\n\n| Concern            | Technology               |\n|--------------------|--------------------------|\n| Language           | Python 3.12+             |\n| Epistemic graph    | Neo4j                    |\n| Concept resolution | spaCy (`en_core_web_sm`) |\n| Data models        | Pydantic v2              |\n| Package management | Poetry                   |\n\n\n---\n\n## Project Structure\n\n```\nsrc/vre/\n├── __init__.py                  # VRE public interface (check, learn_all, check_policy)\n├── guard.py                     # vre_guard decorator (grounding → learning → policy → execution)\n├── tracing.py                   # JSONL persistence of epistemic traces\n│\n├── identity/\n│   ├── models.py                # AgentIdentity — stable UUID bound to a registration key\n│   └── registry.py              # AgentRegistry — file-based, append-only identity persistence\n│\n├── core/\n│   ├── models.py                # Primitive, Depth, Relatum, RelationType, DepthLevel, gaps, Provenance\n│   ├── errors.py                # VREError hierarchy — typed exceptions for all failure modes\n│   ├── graph.py                 # PrimitiveRepository (Neo4j)\n│   ├── grounding/\n│   │   ├── resolver.py          # ConceptResolver — spaCy lemmatization + name lookup\n│   │   ├── engine.py            # GroundingEngine — depth-gated query, gap detection\n│   │   └── models.py            # GroundingResult\n│   └── policy/\n│       ├── models.py            # Policy, Cardinality, PolicyResult, PolicyViolation\n│       ├── gate.py              # PolicyGate — collects violations from a trace\n│       ├── callback.py          # PolicyCallContext, PolicyCallback protocol\n│       └── wizard.py            # Interactive policy attachment CLI\n│\n└── learning/\n    ├── callback.py              # LearningCallback ABC\n    ├── models.py                # Candidate models, CandidateDecision, LearningResult\n    ├── templates.py             # TemplateFactory — gap → structured candidate template\n    └── engine.py                # LearningEngine — template → callback → validate → persist\n\nscripts/\n├── clear_graph.py               # Clear all primitives from the Neo4j graph\n├── seed_all.py                  # Seed fully grounded graph (16 primitives)\n└── seed_gaps.py                 # Seed gap-demonstration graph (10 primitives)\n\nexamples/\n├── claude-code/\n│   └── claude_code.py           # Claude Code PreToolUse hook — two-pass concept protocol\n└── langchain_ollama/\n    ├── main.py                  # Entry point — argparse + agent setup\n    ├── agent.py                 # ToolAgent — LangChain + Ollama streaming loop\n    ├── tools.py                 # shell_tool with vre_guard applied\n    ├── callbacks.py             # ConceptExtractor, on_trace, on_policy, get_cardinality\n    ├── policies.py              # Demo PolicyCallback — protected file deletion guard\n    ├── learner.py               # DemoLearner — ChatOllama structured output + Rich UI\n    └── repl.py                  # Streaming REPL with Rich Live display\n```\n\n---\n\n## Guiding Principle\n\n\u003e **The agent must never act as if it knows more than it can justify.**\n\nVRE exists to enforce that rule — not as a policy, but as a structural property of the system.\n\n---\n\n## Contributing\n\nContributions are welcome! Please open an issue or submit a pull request with your proposed changes. For major changes,\nplease discuss them in an issue first to ensure alignment with the project's\ngoals and architecture.\n\nAreas where contributions would be particularly valuable:\n\n- Additional seed scripts for more complex domains (e.g. networking, databases, cloud infrastructure)\n- Integration examples with other Python agent frameworks or tool libraries — any integration submission should include\n  a demo that exercises the integration and demonstrates epistemic resolution\n  behavior\n- VRE integration into other language environments (Node.js, Go, etc.)\n\nThis is a project that I am passionate about and is the culmination of almost 10 years of philosophical thought. I hope\nto connect with other like-minded community members who prioritize safety and\nepistemic integrity in autonomous agentic systems.\n\nI look forward to seeing how this evolves!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanormang1992%2Fvre","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanormang1992%2Fvre","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanormang1992%2Fvre/lists"}