Metadata-Version: 2.4
Name: domain-context-graph
Version: 0.4.2
Summary: Domain Context Graph protocol for grounding AI in verified domain knowledge.
Project-URL: Homepage, https://github.com/agentkg/dcg
Project-URL: Repository, https://github.com/agentkg/dcg
Project-URL: Issues, https://github.com/agentkg/dcg/issues
Project-URL: Changelog, https://github.com/agentkg/dcg/releases
License-Expression: Apache-2.0
Keywords: ai-grounding,domain-graph,domain-model,graph-protocol,llm-context
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Database :: Database Engines/Servers
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: mcp>=1.27
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Provides-Extra: ingest
Requires-Dist: requests>=2.28; extra == 'ingest'
Provides-Extra: ui
Description-Content-Type: text/markdown

# Domain Context Graph (DCG)

**An open protocol for structuring domain knowledge so AI systems reason about your product — not just your code.**

[![PyPI](https://img.shields.io/pypi/v/domain-context-graph)](https://pypi.org/project/domain-context-graph/)
[![Python](https://img.shields.io/pypi/pyversions/domain-context-graph)](https://pypi.org/project/domain-context-graph/)
[![License](https://img.shields.io/pypi/l/domain-context-graph)](https://github.com/agentkg/dcg/blob/main/LICENSE)

---

## Why DCG?

AI coding assistants write confident code that violates business rules nobody documented. Security scanners flag vulnerabilities without knowing which domain owns the affected service. Incident responders trace call graphs without understanding blast radius across business capabilities.

- **LLM training data is generic.** Models know what "payments" means in general — not what *your* Payments domain is, who owns it, or what depends on it.
- **Code graphs capture structure, not semantics.** They see imports and call chains — not that two modules serve the same bounded context.
- **Documentation decays instantly.** Wikis are stale, unstructured, and not machine-queryable.
- **Knowledge is tool-siloed.** Your security scanner's vulnerability data can't connect to your code graph's ownership data because there's no shared schema.

DCG fills this gap: a **standard, machine-readable protocol** for domain knowledge that any AI system can consume — composable, adapter-driven, and federated across teams and repos.

> **Protocol specification:** This repository contains both the protocol definition and the reference Python implementation. See [Protocol Concepts](#protocol-concepts) below.

---

## Table of Contents

- [Install](#install)
- [Quick Start](#quick-start)
- [Protocol Concepts](#protocol-concepts)
- [CLI Reference](#cli-reference)
- [Stack Composition](#stack-composition)
- [Adapters](#adapters)
- [YAML Seed Ingestion](#yaml-seed-ingestion)
- [MCP Integration](#mcp-integration)
- [Graph Explorer UI](#graph-explorer-ui)
- [Ontology Packs](#ontology-packs)
- [Static Export & Hosting](#static-export--hosting)
- [Extending DCG](#extending-dcg)
- [Package Structure](#package-structure)
- [License](#license)

---

## Install

```bash
pip install domain-context-graph
```

Optional extras:

```bash
pip install "domain-context-graph[ingest]"   # YAML seed batch ingestion (adds requests)
pip install "domain-context-graph[dev]"      # pytest + coverage for development
```

Verify the installation:

```bash
dcg --help
```

---

## Quick Start

### 1. Create a project

```bash
dcg init my-domain --description "My product's domain knowledge"
cd my-domain
```

This creates a `graph_card.json` manifest and a `graphs/default.json` data file.

### 2. Add knowledge via MCP

Start the ingest server and connect from Claude Code, Cursor, or any MCP client:

```bash
dcg ingest-mcp --project .
```

Or add to your project's `.mcp.json`:

```json
{
  "mcpServers": {
    "dcg-ingest": {
      "command": "dcg-ingest-mcp",
      "args": ["--project", "./my-domain"]
    }
  }
}
```

Then use natural language with your AI assistant to populate the graph:

> "Create a domain called Payments. Add a Function entity called charge_card in the Payments domain."

### 3. Query the graph

```bash
dcg query ./my-domain --type Function
dcg query ./my-domain --domain Payments
```

### 4. Use it programmatically

```python
from dcg.core import GraphStore, entity_uid, builders as kb

store = GraphStore()

# Define a domain
payments_uid = entity_uid(name="Payments")
store.add_entity(kb.entity(
    uid=payments_uid,
    label="Payments",
    description="Payment processing domain",
    attributes=[kb.attribute("instance of", kb.ref_value("dcg:meta:Domain"))],
))

# Place a code entity in that domain
fn_uid = entity_uid(name="charge_card", path="src/payments/charge.py")
store.add_entity(kb.entity(
    uid=fn_uid,
    label="charge_card",
    attributes=[
        kb.attribute("instance of", kb.ref_value("dcg:meta:Function")),
        kb.attribute("part of", kb.ref_value(payments_uid)),
        kb.attribute("file path", kb.string_value("src/payments/charge.py")),
    ],
))

# Query
functions = store.query(instance_of="dcg:meta:Function")
```

---

## Protocol Concepts

### Entities

Every piece of knowledge is an entity — a Wikibase-compatible JSON object with:

| Field | Description |
|-------|-------------|
| `id` | Content-addressed UID (`dcg:sha256:...`) — deterministic from identity keys |
| `label` | Human-readable name |
| `description` | What this entity represents |
| `aliases` | Alternative names for discovery |
| `attributes` | Typed key-value pairs (references, strings, quantities) |

### Content-Addressed Identity

Entity UIDs are SHA-256 hashes of their identity keys. The same entity always gets the same ID regardless of who creates it or when:

```python
from dcg.core import entity_uid

uid = entity_uid(name="SQL Injection", type="Vulnerability")
# → dcg:sha256:a1b2c3...  (deterministic)
```

### Two-Axis Classification

Every entity is classified on two orthogonal axes:

- **Type** (`instance of`): What it is structurally — Function, Class, Vulnerability, Domain
- **Domain** (`part of`): Where it belongs organizationally — Payments, Security, Infrastructure

This separation means you can query "all Functions in the Payments domain" or "all Vulnerabilities across all domains."

### Relations

Typed, directed edges between entities:

```
charge_card  --[calls]-->  validate_input
SQLInjection --[mitigates]--> InputValidation
```

Relations are also content-addressed (UID = hash of source + target + property) and can carry qualifiers for metadata.

### Retraction

Entities and relations can be soft-deleted (retracted) and later permanently purged. This preserves audit history while allowing cleanup.

---

## CLI Reference

| Command | Description |
|---------|-------------|
| `dcg init <name>` | Create a new domain graph project |
| `dcg compose <manifest>` | Validate a `dcg-stack.yml` manifest |
| `dcg query <path> [--type T] [--domain D]` | Query entities in a project |
| `dcg purge <path>` | Permanently remove retracted entities and relations |
| `dcg ingest --project <path> --seeds <dir>` | Batch-ingest YAML seed files |
| `dcg export-static <manifest> -o data.json` | Export full stack as static JSON bundle |
| `dcg ui --stack <manifest>` | Launch the graph explorer web UI |
| `dcg ingest-mcp --stack <manifest>` | Launch the read/write MCP server |

All commands support `--help` for detailed usage.

---

## Stack Composition

Stacks let you layer multiple domain graphs into a unified view. Each layer can be a DCG project directory or an adapter-backed external source.

### Manifest format (`dcg-stack.yml`)

```yaml
stack: my-appsec-stack

layers:
  - name: security
    source: ./graphs/security-domain

  - name: product
    source: ./graphs/product-domain
    extends: [security]

  - name: code
    adapter: graphify
    source: ./graphify-output
    extends: [product]
    mapping:
      domain: my-service
      code_only: true

joins:
  - property: mitigates
    rule: match entities by 'cwe_id' across layers
```

### How it works

- **`extends`** defines a resolution DAG. Querying the `code` layer walks `code` -> `product` -> `security` until an entity is found.
- **Cross-layer joins** materialize virtual relations between entities that share property values across layers (e.g., a Vulnerability in the security layer with `cwe_id: CWE-89` connects to a Function in the code layer with the same `cwe_id`).
- **Merged ontology** — all type and property registrations from all layers are unified.
- **Adapter layers** use the `adapter:` key instead of `source:` pointing to a DCG project. The adapter translates external formats on the fly.

### Validate a stack

```bash
dcg compose dcg-stack.yml
```

---

## Adapters

Adapters ingest external data sources as stack layers without pre-converting them to DCG format.

### Built-in adapters

| Adapter | Source Format | Description |
|---------|---------------|-------------|
| `graphify` | [Graphify](https://graphify.net) `graph.json` | Code graph ingestion from Tree-sitter + NetworkX output. Automatic type inference (Function, Class, File, Module), relation mapping, multi-repo support. |

### Graphify adapter

[Graphify](https://graphify.net) is an open-source code analysis tool that produces `graph.json` files in NetworkX `node_link_data` format. DCG's Graphify adapter:

- Infers entity types from metadata, file extensions, and naming patterns
- Maps Graphify edge types to DCG relation properties (`calls`, `imports`, `inherits from`, `depends on`, `contains`, etc.)
- Supports multi-repo analysis with automatic org-prefix stripping
- Loads the `code` ontology pack automatically

```yaml
# In dcg-stack.yml
- name: code
  adapter: graphify
  source: ./graphify-output    # directory containing graph.json
  extends: [product]
  mapping:
    domain: my-service         # assign all entities to this domain
    code_only: true            # filter non-code nodes
```

### Writing a custom adapter

```python
from dcg.adapters import register
from dcg.core.store import GraphStore
from pathlib import Path

class MyAdapter:
    def load(self, source: Path, store: GraphStore, config: dict) -> None:
        # Read your data source and populate the store
        data = json.loads((source / "data.json").read_text())
        for item in data["items"]:
            store.add_entity(...)

    def source_exists(self, source: Path) -> bool:
        return (source / "data.json").is_file()

register("my-adapter", MyAdapter)
```

Then use `adapter: my-adapter` in your `dcg-stack.yml`.

---

## YAML Seed Ingestion

Batch-populate graphs from declarative YAML files with a 7-pass pipeline:

```yaml
# seeds/security-domains.yaml
tier: T1
entities:
  - label: SQL Injection
    type: Vulnerability
    domain: AppSecurity
    description: Code injection via malicious SQL in user input
    properties:
      cwe_id: CWE-89
      owasp_category: A03:2021
    relations:
      - target: Input Validation
        property: mitigates
```

```bash
dcg ingest --project ./my-graph --seeds ./seeds/
```

### Tiers

| Tier | Confidence | Destination |
|------|-----------|-------------|
| T1 | Official / verified | Main graph |
| T2 | Moderate confidence | Main graph |
| T3 | Draft / AI-generated | Draft subgraph (for human review) |

### Pipeline passes

1. **Discovery** — scan seed files, filter by modification time
2. **Ontology validation** — check types and properties against registered ontology
3. **Domains** — create Domain entities first (dependency ordering)
4. **Entities** — create all non-domain entities
5. **Relations** — resolve targets by label/alias and create edges
6. **Review items** — generate ReviewItem entities for T3 draft entries
7. **Commit** — save to disk and update ingestion timestamp

Use `--dry-run` to validate seeds without writing.

---

## MCP Integration

DCG provides two [Model Context Protocol](https://modelcontextprotocol.io) servers for AI assistant integration:

### Servers

| Server | Command | Purpose |
|--------|---------|---------|
| `dcg-mcp` | `dcg serve --stack manifest.yml` | **Read-only** exploration |
| `dcg-ingest-mcp` | `dcg ingest-mcp --stack manifest.yml` | **Read/write** (all read tools + create, connect, classify, bulk ops) |

Both support stdio (default for MCP clients) and Streamable HTTP (`--http --port 3001`) transports.

### Configuration

Add to your project's `.mcp.json`:

```json
{
  "mcpServers": {
    "dcg-mcp": {
      "command": "dcg-mcp",
      "args": ["--stack", "./dcg-stack.yml"]
    },
    "dcg-ingest-mcp": {
      "command": "dcg-ingest-mcp",
      "args": ["--stack", "./dcg-stack.yml"]
    }
  }
}
```

For a single project (no stack):

```json
{
  "mcpServers": {
    "dcg-ingest": {
      "command": "dcg-ingest-mcp",
      "args": ["--project", "./my-graph"]
    }
  }
}
```

### Available tools

**Query tools** (both servers):

| Tool | Description |
|------|-------------|
| `dcg_query_snapshot` | Graph summary — entity count, relation count, domains, type distribution |
| `dcg_query_entities` | Filter entities by type and/or domain |
| `dcg_query_entity` | Fetch a single entity by UID |
| `dcg_query_relations` | Filter relations by source, target, and/or property |
| `dcg_query_by_name` | Get all relations for an entity by name |
| `dcg_query_uid` | Compute a content-addressed UID (dry run) |
| `dcg_query_ontology` | List all registered types and properties |
| `dcg_query_packs` | List available and loaded ontology packs |

**Stack tools** (both servers):

| Tool | Description |
|------|-------------|
| `dcg_stack_info` | Stack DAG structure, join rules, layer counts |
| `dcg_stack_switch_layer` | Change the active read/write layer |
| `dcg_stack_query` | Query entities across all or specific layers |
| `dcg_stack_resolve` | Resolve an entity by name following the extends DAG |
| `dcg_stack_cross_layer_relations` | Get materialized cross-layer join relations |

**Project tools** (both servers):

| Tool | Description |
|------|-------------|
| `dcg_project_info` | Project metadata and validation status |
| `dcg_project_reload` | Reload graph files from disk |
| `dcg_project_compact` | Purge retracted entities and save |

**Ingest tools** (ingest server only):

| Tool | Description |
|------|-------------|
| `dcg_ingest_create_domain` | Create a Domain entity |
| `dcg_ingest_create_entity` | Create an entity with type, domain, description, properties |
| `dcg_ingest_connect` | Create a relation between two entities by name |
| `dcg_ingest_bulk_create` | Batch-create multiple entities |
| `dcg_ingest_bulk_connect` | Batch-create multiple relations |
| `dcg_ingest_remove` | Soft-retract an entity by name |
| `dcg_ingest_classify` | Assign an entity to a domain |
| `dcg_ingest_register_type` | Register a custom entity type |
| `dcg_ingest_register_property` | Register a custom property |
| `dcg_ingest_load_pack` | Load an ontology pack into the active layer |
| `dcg_ingest_save` | Persist the active layer to disk |

---

## Graph Explorer UI

DCG includes a React-based graph explorer with Cytoscape.js visualization, Zustand state management, and React Query for data fetching.

### Live mode

Connect to a running MCP server for real-time exploration and editing:

```bash
dcg ui --stack dcg-stack.yml
# Opens http://localhost:5173
```

Features: graph visualization with multiple layouts (cola, dagre, cose, tree), entity detail panel, domain/type filtering, entity creation, relation connections, inline editing, layer switching.

### Static mode

Export and host the graph with no backend:

```bash
dcg export-static dcg-stack.yml --output ./site/graph/data.json
```

The UI auto-detects `data.json` at its base URL and renders in read-only mode — write actions (Save, New, Connect, edit) are hidden automatically.

---

## Static Export & Hosting

Export the full stack as a single JSON bundle for static hosting:

```bash
dcg export-static dcg-stack.yml --output data.json
```

The bundle contains: `snapshot`, `stack_info`, `ontology`, `entities[]`, and `relations[]`.

### Host on GitHub Pages

Build the UI with a custom base path and combine with the exported data:

```bash
# Export data
dcg export-static dcg-stack.yml --output ./site/graph/data.json

# Build UI for /graph/ subdirectory
cd src/dcg/ui
DCG_BASE_PATH=/graph/ npm run build

# Copy built UI
cp -r dist/* ./site/graph/
```

Serve `./site/` with any static file server — the graph explorer loads at `/graph/`.

### Host on S3 / CloudFront

Same build process, then sync to your bucket:

```bash
aws s3 sync ./site/graph/ s3://my-bucket/graph/ --delete
```

---

## Ontology Packs

Packs are pluggable type and property registries. Four ship with DCG:

### `core` (always loaded)

**Types:** Domain, Type

**Properties:** instance of, subclass of, part of, redirected to, depends on, related to, references, same as, triggers, contains, language, version

### `code`

**Types:** Function, Class, Struct, Interface, Trait, File, Module, Endpoint

**Properties:** calls, imports, inherits from, handles route, tested by, implements, file path, line number

### `security`

**Types:** Vulnerability, Category, Standard, Control

**Properties:** mitigates

### `dcg-development`

**Types:** ReviewItem

**Properties:** confidence, source_url, external_id

### Loading packs

In a stack manifest:

```yaml
layers:
  - name: security
    source: ./graphs/security
    packs: [security]
```

Via MCP: use the `dcg_ingest_load_pack` tool.

Via Python:

```python
from dcg.core.ontology import PackStore

pack_store = PackStore()
pack_store.load_pack("security")
```

---

## Extending DCG

### Custom entity types

```python
from dcg.core.ontology import register_global_type

register_global_type("Microservice", description="A deployable service unit")
```

Or via MCP: `dcg_ingest_register_type(name="Microservice", description="...")`

### Custom properties

```python
from dcg.core.ontology import register_property

register_property("sla_hours", datatype="quantity", description="SLA response time in hours")
```

Or via MCP: `dcg_ingest_register_property(name="sla_hours", datatype="quantity")`

### Custom storage backends

Implement `GraphStoreProtocol`:

```python
from dcg.core.store import GraphStoreProtocol

class MyStore(GraphStoreProtocol):
    def add_entity(self, entity: dict) -> str: ...
    def add_relation(self, relation: dict) -> str: ...
    def get_entity(self, uid: str) -> dict | None: ...
    def get_relations(self, **filters) -> list[dict]: ...
    def query(self, instance_of=None, part_of=None) -> list[dict]: ...
    def remove(self, uid: str) -> None: ...
    def to_json(self) -> dict: ...
    def load(self, data: dict) -> None: ...
```

### Custom adapters

See [Adapters](#adapters) section above.

---

## Package Structure

```
src/dcg/
  cli.py                   # CLI entry point (dcg command)
  core/
    uid.py                 # Content-addressed entity/relation IDs
    model.py               # Entity, Relation, Attribute dataclasses
    ontology.py            # Type/property registries + ontology packs
    builders.py            # Entity/attribute/relation construction helpers
    store.py               # GraphStore — in-memory graph with JSON persistence
    stack.py               # StackLoader — multi-layer composition + cross-layer joins
    project.py             # DomainProject — manifest-based project manager
    purge.py               # Retraction purge
    packs/                 # Built-in ontology pack YAML files
  adapters/
    base.py                # AdapterProxy with enrichment overlay support
    graphify.py            # Graphify code graph adapter
    registry.py            # Adapter name -> class registry
  ingest/                  # YAML seed ingestion pipeline (7-pass)
  mcp/                     # MCP servers (read-only + read/write)
  ops/                     # Orchestration layer (ingest, lifecycle, ontology ops)
  ui/                      # React graph explorer (Cytoscape.js + Tailwind)
```

---

## Contributing

```bash
git clone https://github.com/agentkg/dcg.git
cd dcg
pip install -e ".[dev]"
pytest
```

---

## License

[Apache-2.0](LICENSE)
