Create Context Graph
Memory frameworkOfficial neo4j-labs project
Created by neo4j-labs
Published in neo4j-labs/create-context-graph. Publisher page
747 GitHub stars
What it is
AI agents with graph based reasoning memory, scaffolded in seconds
AutoGineer overview, from the brain’s own files
Create Context Graph is an interactive scaffolding tool designed to accelerate the development of AI agents that utilize graph-based memory. By walking developers through a wizard, it generates a complete, domain-specific application stack including a FastAPI backend, a Next.js frontend with interactive graph visualization, and a configured AI agent. The tool supports multiple agent frameworks and offers a choice between a hosted memory backend (NAMS) or a self-hosted Neo4j instance. It includes built-in support for importing data from various SaaS platforms, generating domain-specific ontologies, and creating MCP servers for integration with Claude Desktop.
How it works
Memory model: Hybrid
AutoGineer overview, from the brain’s own files
The tool operates as a CLI that uses Jinja2 templates to generate project code based on a selected industry domain and agent framework. It creates a FastAPI backend for agent logic and a Next.js frontend for visualization. Memory is managed either via the hosted NAMS service or a self-hosted Neo4j database. The system supports data ingestion from various connectors and can generate domain-specific ontologies, schemas, and agent tools automatically.
| Folder | Role | Files |
|---|---|---|
| .github | agent-config | 2 |
| docs | docs | 105 |
| scripts | scripts | 2 |
| src | source-code | 168 |
| tests | tests | 48 |
| .serena | folder | 1 |
| npm-wrapper | folder | 3 |
The agent reads
- get_entity_detail_nams evidence: CLAUDE.md
- list_traces evidence: CLAUDE.md
- list_documents_nams evidence: CLAUDE.md
- find_decisions evidence: CLAUDE.md
- search_sessions evidence: CLAUDE.md
- get_collector evidence: CLAUDE.md
The agent writes
- delete_entity evidence: CLAUDE.md
- add_relationship evidence: CLAUDE.md
- add_entity evidence: CLAUDE.md
Requirements
Runtimes: Python >=3.11
Databases: Neo4j
API keys (by name): ANTHROPIC_API_KEY, GOOGLE_API_KEY, LINEAR_API_KEY, MEMORY_API_KEY, OPENAI_API_KEY
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)
Set it up
This brain runs code automatically: 1 script. Review Makefile before opening the folder in Claude Code. No step below turns a hook on for you.
Makefile:uv venv && uv pip install -e ".[dev]"
- Not scanned by AutoGineerIts dependencies are installed by pip or uv when you run it and were not scanned by AutoGineer (7 declared). https://pypi.org/project/create-context-graph/
Created by neo4j-labs. Published in neo4j-labs/create-context-graph. Licence: Apache License 2.0.
Usage
AutoGineer overview, from the brain’s own files
- Scaffold a new project using the interactive CLI wizard.
- Generate a project with a specific domain and agent framework via CLI flags.
- Connect SaaS data sources like GitHub, Slack, or Notion to populate the graph.
- Configure the memory backend for either hosted NAMS or self-hosted Neo4j.
- Generate an MCP server configuration for Claude Desktop integration.
- Re-import data or seed the graph using generated make commands.
- “uvx create-context-graph my-app --domain healthcare --framework strands --nams-api-key sk-nams-...”
- Generates a healthcare-focused agent application using the Strands framework and hosted NAMS memory.
- “uvx create-context-graph my-app --domain personal-knowledge --framework pydanticai --self-hosted --connector github”
- Generates a personal knowledge application with self-hosted Neo4j, pre-populated with GitHub data.
Documentation by neo4j-labs
Create Context Graph
This is an experimental Neo4j Labs project and not part of Neo4j's supported product lineup. See the Neo4j Labs disclaimer.
Neo4j Labs Project — This project is part of Neo4j Labs. It is maintained by Neo4j staff and the community, but not officially supported. For help, use GitHub Issues or the Neo4j Community Forum.
Interactive CLI scaffolding tool that generates fully-functional, domain-specific context graph applications. Pick your industry domain, pick your agent framework, and get a complete full-stack app in under 5 minutes.
<p align="center"> <img src="docs/static/img/app-three-panel.png" alt="Generated app: chat interface, graph visualization, and document browser" width="800" /> </p>
# Python — NAMS-default (hosted memory)
uvx create-context-graph my-app --domain healthcare --framework strands --nams-api-key sk-nams-...
# Self-hosted Neo4j with full demo fixtures
uvx create-context-graph my-app --domain healthcare --framework pydanticai --self-hosted --demo
# Node.js / interactive wizard
npx create-context-graphWhat It Does
Create Context Graph walks you through an interactive wizard and generates a complete project:
FastAPI backend with an AI agent configured for your domain, powered by neo4j-agent-memory v0.4 for multi-turn conversations with automatic entity extraction. Memory backend is configurable: hosted NAMS (default) or self-hosted bolt Neo4j (
--self-hosted).LiteLLM provider injection for the memory layer — pick any LLM + embedding provider via
MEMORY_LLM/MEMORY_EMBEDDINGenv vars (Anthropic, OpenAI, Bedrock, Vertex AI, Ollama, Groq, Together, …). Native adapters resolve first; everything else routes through LiteLLM.Next.js + Chakra UI v3 frontend with streaming chat (Server-Sent Events), real-time tool call visualization (Timeline with live spinners), interactive graph visualization (schema view, double-click expand, drag/zoom, property panel), entity detail panel, document browser, and decision trace viewer
Neo4j schema with domain-specific constraints, indexes, and GDS projections (self-hosted mode)
Rich demo data — LLM-generated entities, relationships, professional documents (discharge summaries, trade confirmations, lab reports), and multi-step decision traces
SaaS data import — connect GitHub, Slack, Gmail, Jira, Notion, Google Calendar, Salesforce, Linear, Google Workspace, Claude Code, Claude AI, ChatGPT, or local files
Custom domains — describe your domain in plain English and the LLM generates a complete ontology
Domain-specific agent tools with Cypher queries tailored to your industry
MCP server for Claude Desktop — optionally generates an MCP server config so Claude Desktop can query the same knowledge graph (
--with-mcp)
Creating context graph application...
Domain: Wildlife Management
Framework: PydanticAI
Data: Demo (synthetic)
Neo4j: Docker (neo4j://localhost:7687)
[1/6] Generating domain ontology... ✓
[2/6] Creating project scaffold... ✓
[3/6] Configuring agent tools & system prompt... ✓
[4/6] Generating synthetic documents (25 docs)... ✓
[5/6] Writing fixture data... ✓
[6/6] Bundling project... ✓
Done! Your context graph app is ready.
cd my-app
make install && make startQuick Start
There are two flows depending on what you want:
NAMS (default) — hosted memory backend. No Neo4j to install or operate. Graph starts empty; the agent populates it as you chat.
Self-hosted (
--self-hosted) — bolt Neo4j you run yourself (Aura, Docker, neo4j-local). Full demo fixtures available viamake seed.
Prerequisites
Python 3.11+ (with uv recommended)
Node.js 18+ (for the frontend)
NAMS path: a NAMS API key from memory.neo4jlabs.com
Self-hosted path: Neo4j 5+ (Docker, Aura, or local install)
Either path:
ANTHROPIC_API_KEYfor the agent (orOPENAI_API_KEY/GOOGLE_API_KEYdepending on framework)
NAMS path (default, hosted memory)
uvx create-context-graph my-app \
--domain healthcare \
--framework strands \
--nams-api-key sk-nams-...
cd my-app
echo 'ANTHROPIC_API_KEY=sk-ant-...' >> .env # Strands needs Anthropic
make install
make startOpen http://localhost:3000. Graph starts empty — chat with the agent and entities populate via auto-extraction.
Self-hosted path (bolt Neo4j + full demo data)
uvx create-context-graph my-app \
--domain healthcare \
--framework pydanticai \
--self-hosted \
--demo
cd my-app
echo 'ANTHROPIC_API_KEY=sk-ant-...' >> .env
make install
make docker-up # or: make neo4j-start (for neo4j-local)
make seed
make startOpen http://localhost:3000. Pre-populated graph with ~85 entities, 180 relationships, 25 documents, and decision traces.
Other scaffold patterns
# Interactive wizard (asks 6 prompts, autocomplete domain picker)
uvx create-context-graph
# Custom domain from description
uvx create-context-graph my-app \
--custom-domain "veterinary clinic management" \
--framework pydanticai \
--self-hosted --demo \
--anthropic-api-key $ANTHROPIC_API_KEY
# Import real data from SaaS services
uvx create-context-graph my-app \
--domain personal-knowledge --framework pydanticai --self-hosted \
--connector github --connector slack
# With MCP server for Claude Desktop (works on either backend)
uvx create-context-graph my-app \
--domain healthcare --framework strands \
--nams-api-key sk-nams-... --with-mcp
# Pick a specific LiteLLM provider for memory entity extraction
uvx create-context-graph my-app \
--domain healthcare --framework strands --nams-api-key sk-nams-... \
--memory-llm bedrock/anthropic.claude-3-haiku-20240307-v1:0 \
--memory-embedding sentence-transformers/all-MiniLM-L6-v2Explore the running app
Frontend: http://localhost:3000 — Chat with the AI agent, explore the knowledge graph
Backend API: http://localhost:8000/docs — FastAPI auto-generated docs
Health endpoint: http://localhost:8000/health — reports the active memory backend
NAMS dashboard: memory.neo4jlabs.com (NAMS path only)
Neo4j Browser: http://localhost:7474 (self-hosted Docker / neo4j-local only)
NAMS write-path caveats (v0.4)
The NAMS REST API has a narrower write surface than bolt Cypher. The CLI and the generated import_data.py work around it with a hybrid write shape:
Relationships encoded as
ccg-edgesYAML blocks inside each source entity'sdescription. The frontend graph view parses them out and renders edges; a future migration replays them as native edges when NAMS addsadd_relationship.Entity properties collapse into
descriptionas a markdown block (NAMS REST accepts onlyname/type/description).Documents are dual-tracked —
long_term.add_entity(type=OBJECT)(queryable, matches bolt:Document) ANDshort_term.add_message(role="document")(extraction fuel).No preferences or facts via REST.
auto_preferencesforced off on NAMS.GDS endpoints and arbitrary Cypher writes return 501 on NAMS.
For native graph edges + GDS + arbitrary Cypher, use --self-hosted --demo.
Supported Domains
27 industry domains, each with a purpose-built ontology, sample data, agent tools, and demo scenarios:
| Domain | Key Entities | Domain | Key Entities |
|---|---|---|---|
| Financial Services | Account, Transaction, Decision, Policy | Real Estate | Property, Listing, Agent, Inspection |
| Healthcare | Patient, Provider, Diagnosis, Treatment | Vacation & Hospitality | Resort, Booking, Guest, Activity |
| Retail & E-Commerce | Customer, Product, Order, Review | Oil & Gas | Well, Reservoir, Equipment, Permit |
| Manufacturing | Machine, Part, WorkOrder, Supplier | Data Journalism | Source, Story, Claim, Investigation |
| Scientific Research | Researcher, Paper, Dataset, Grant | Trip Planning | Destination, Hotel, Activity, Itinerary |
| GenAI / LLM Ops | Model, Experiment, Prompt, Evaluation | GIS & Cartography | Feature, Layer, Survey, Boundary |
| Agent Memory | Agent, Conversation, Memory, ToolCall | Wildlife Management | Species, Sighting, Habitat, Camera |
| Gaming | Player, Character, Quest, Guild | Conservation | Site, Species, Program, Funding |
| Personal Knowledge | Note, Contact, Project, Topic | Golf & Sports Mgmt | Course, Player, Round, Tournament |
| Digital Twin | Asset, Sensor, Reading, Alert | Software Engineering | Repository, Issue, PR, Deployment |
| Product Management | Feature, Epic, UserPersona, Metric | Hospitality | Hotel, Room, Reservation, Service |
| Options Intelligence | Underlying, OptionsContract, Regime, KeyLevel | Legal | Case, Matter, Contract, Filing |
| Education | Student, Instructor, Course, Assessment | Cybersecurity | Asset, Vulnerability, Alert, Incident |
| Government | Agency, Program, Policy, Regulation |
# List all available domains
create-context-graph --list-domainsCustom domains: Don't see your industry? Select "Custom (describe your domain)" in the wizard or use --custom-domain "your description". The LLM generates a complete ontology with entity types, relationships, agent tools, and more.
SaaS Data Connectors
<p align="center"> <img src="docs/static/img/connector-data-flow.png" alt="SaaS connector data flow into Neo4j knowledge graph" width="700" /> </p>
Import real data from your existing tools instead of (or in addition to) synthetic demo data:
| Service | What's Imported | Auth |
|---|---|---|
| GitHub | Issues, PRs, commits, contributors | Personal access token |
| Notion | Pages, databases, users | Integration token |
| Jira | Issues, sprints, users | API token |
| Slack | Channel messages, threads, users | Bot OAuth token |
| Gmail | Emails (last 30 days) | Google Workspace CLI or OAuth2 |
| Google Calendar | Events, attendees (last 90 days) | Google Workspace CLI or OAuth2 |
| Salesforce | Accounts, contacts, opportunities | Username/password |
| Linear | Issues, projects, cycles, teams, users, labels, comments, milestones, initiatives, attachments + decision traces from history | Personal API key |
| Google Workspace | Drive files, comment threads (as decision traces), revisions, Drive Activity, Calendar events, Gmail metadata | Google OAuth 2.0 |
| Claude Code | Session history, messages, tool calls, files, decisions, preferences, errors | None (local files) |
| Claude AI | Conversations, messages, tool calls, thinking traces from Claude AI web/app export | None (local file) |
| ChatGPT | Conversations, messages, tool results from ChatGPT data export | None (local file) |
The Google Workspace connector extracts resolved comment threads from Google Docs as first-class decision traces — capturing the question, deliberation, resolution, and participants. Combined with Linear, it provides the full decision lifecycle: from meeting discussion to code execution.
The Claude Code connector reads your local session history from ~/.claude/projects/ — no API keys needed. It extracts decision traces from user corrections and error-resolution cycles, identifies developer preferences from explicit statements and behavioral patterns, and automatically redacts secrets before storage.
The Claude AI and ChatGPT connectors import your conversation exports directly from the official data export features. Export your data from Settings, pass the .zip file to the CLI with --import-type claude-ai or --import-type chatgpt, and get a fully populated context graph from your real conversations — no API keys needed.
Connectors run at scaffold time to populate initial data. They're also generated into your project so you can re-import with make import:
cd my-app
make import # Re-import from connected services
make import-and-seed # Import and seed into Neo4jAgent Frameworks
Select your preferred agent framework at project creation time:
| Framework | Description |
|---|---|
| PydanticAI | Structured tool definitions with Pydantic models and RunContext |
| Claude Agent SDK | Anthropic tool-use with agentic loop |
| OpenAI Agents SDK | @function_tool decorators with Runner.run() |
| LangGraph | Stateful graph-based agent workflow with create_react_agent() |
| CrewAI | Multi-agent crew with role-based tools |
| Strands | Tool-use agents with Anthropic model |
| Google ADK | Gemini agents with FunctionTool calling |
| Anthropic Tools | Modular tool registry with Anthropic API agentic loop |
All frameworks share the same FastAPI HTTP layer, Neo4j client, and frontend. Only the agent implementation differs. "Full streaming" means token-by-token text + real-time tool calls. "Tool streaming" means real-time tool calls with text delivered at the end.
Note on memory providers: Conversation memory uses local
sentence-transformers/all-MiniLM-L6-v2embeddings by default — no API key required. Override withMEMORY_EMBEDDING(LiteLLM provider string) for OpenAI, Vertex AI, Bedrock, or others. The entity-extraction LLM defaults toanthropic/claude-haiku-4-5whenANTHROPIC_API_KEYis set, oropenai/gpt-4o-miniif onlyOPENAI_API_KEYis set. Override withMEMORY_LLMfor full control. See Configure Memory Providers.
Generated Project Structure
<p align="center"> <img src="docs/static/img/ontology-pipeline.png" alt="From domain YAML through Jinja2 templates to generated code" width="750" /> </p>
A single domain YAML drives the entire generated application — schema, models, agent tools, and visualization — through the Jinja2 template engine.
my-app/
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI application
│ │ ├── agent.py # AI agent (framework-specific)
│ │ ├── config.py # Settings from .env
│ │ ├── routes.py # REST API endpoints
│ │ ├── models.py # Pydantic models (from ontology)
│ │ ├── context_graph_client.py # Neo4j CRUD operations
│ │ ├── memory.py # Memory integration (MemoryIntegration)
│ │ ├── gds_client.py # Graph Data Science algorithms
│ │ ├── vector_client.py # Vector search
│ │ └── connectors/ # SaaS connectors (if selected)
│ ├── scripts/
│ │ ├── generate_data.py # Data seeding script
│ │ └── import_data.py # SaaS import script (if connectors selected)
│ └── pyproject.toml
├── frontend/
│ ├── app/ # Next.js pages
│ ├── components/
│ │ ├── ChatInterface.tsx # Streaming AI chat (SSE) with real-time tool calls + graph data flow
│ │ ├── ContextGraphView.tsx # Interactive NVL graph (schema view, expand, drag/zoom, properties)
│ │ ├── DecisionTracePanel.tsx # Reasoning trace viewer with step details
│ │ ├── DocumentBrowser.tsx # Document browser with template filtering
│ │ └── Provider.tsx # Chakra UI v3 provider
│ ├── lib/config.ts # Domain configuration
│ ├── theme/index.ts # Chakra theme with domain colors
│ └── package.json
├── cypher/
│ ├── schema.cypher # Constraints & indexes
│ └── gds_projections.cypher # GDS algorithm config
├── data/
│ ├── ontology.yaml # Domain ontology definition
│ └── fixtures.json # Pre-generated sample data
├── .env # Neo4j + API key configuration
├── .env.example # Configuration template (tracked in git)
├── .dockerignore # Docker build context exclusions
├── docker-compose.yml # Local Neo4j instance (Docker mode only)
├── Makefile # start, seed, reset, install, test, test-connection, lint
├── mcp/ # MCP server config (only if --with-mcp)
└── README.md # Domain-specific documentation (with framework docs + troubleshooting)CLI Reference
create-context-graph [PROJECT_NAME] [OPTIONS]
Arguments:
PROJECT_NAME Project name (optional — auto-generated from domain+framework if omitted)
Options:
--domain TEXT Domain ID (e.g., healthcare, gaming)
--framework TEXT Agent framework (strands [default], pydanticai, claude-agent-sdk, openai-agents, langgraph, crewai, google-adk, anthropic-tools)
--self-hosted Use self-hosted Neo4j (bolt) instead of NAMS hosted memory
--nams-api-key TEXT NAMS API key [env: MEMORY_API_KEY] — obtain at https://memory.neo4jlabs.com
--nams-endpoint TEXT Override NAMS endpoint URL (default: https://memory.neo4jlabs.com/v1)
--memory-llm TEXT LiteLLM provider string for memory entity extraction (e.g. anthropic/claude-haiku-4-5)
--memory-embedding TEXT LiteLLM provider string for memory embeddings (e.g. sentence-transformers/all-MiniLM-L6-v2)
--demo-data Generate synthetic demo data
--custom-domain TEXT Generate custom domain from description (requires --anthropic-api-key)
--connector TEXT SaaS connector to enable; repeatable (github, slack, jira, notion, gmail, gcal, salesforce, linear, google-workspace, claude-code, claude-ai, chatgpt)
--import-type TEXT Chat history import: claude-ai or chatgpt (requires --import-file)
--import-file PATH Path to chat export file (.zip, .json, .jsonl)
--import-depth TEXT Import extraction depth: fast (default) or deep
--import-filter-after TEXT Only import conversations after this date (ISO 8601)
--import-filter-before TEXT Only import conversations before this date (ISO 8601)
--import-filter-title TEXT Only import conversations matching title pattern (regex)
--import-max-conversations INT Max conversations to import, 0=all (default: 0)
--linear-api-key TEXT Linear API key (required for --connector linear) [env: LINEAR_API_KEY]
--linear-team TEXT Linear team key to filter import (e.g., ENG) [env: LINEAR_TEAM]
--gws-folder-id TEXT Google Drive folder ID to scope import [env: GWS_FOLDER_ID]
--gws-include-comments / --gws-no-comments Import comment threads (default: on)
--gws-include-revisions / --gws-no-revisions Import revision history (default: on)
--gws-include-activity / --gws-no-activity Import Drive Activity (default: on)
--gws-include-calendar Import Calendar events (default: off)
--gws-include-gmail Import Gmail thread metadata (default: off)
--gws-since TEXT Import data since date (ISO format, default: 90 days ago)
--gws-mime-types TEXT MIME types to include (default: docs,sheets,slides)
--gws-max-files INT Maximum files to import (default: 500)
--claude-code-scope TEXT Import current project or all (default: current)
--claude-code-project TEXT Explicit project path to import sessions for
--claude-code-since TEXT Import sessions since date (ISO format)
--claude-code-max-sessions INT Max sessions to import, 0=all (default: 0)
--claude-code-content TEXT Content mode: truncated, full, none (default: truncated)
--with-mcp Generate MCP server configuration for Claude Desktop
--mcp-profile TEXT MCP tool profile: core (6 tools) or extended (16 tools, default)
--session-strategy TEXT Memory session strategy: per_conversation (default), per_day, persistent
--auto-extract/--no-auto-extract Auto-extract entities from messages (default: on)
--auto-preferences/--no-auto-preferences Auto-detect user preferences (default: on)
--ingest Ingest data into Neo4j after generation
--neo4j-uri TEXT Neo4j connection URI [env: NEO4J_URI] (--self-hosted only)
--neo4j-username TEXT Neo4j username [env: NEO4J_USERNAME] (--self-hosted only)
--neo4j-password TEXT Neo4j password [env: NEO4J_PASSWORD] (--self-hosted only)
--neo4j-aura-env PATH Path to Neo4j Aura .env file with credentials (--self-hosted only)
--neo4j-local Use @johnymontana/neo4j-local for local Neo4j (--self-hosted only)
--anthropic-api-key TEXT Anthropic API key for LLM generation [env: ANTHROPIC_API_KEY]
--openai-api-key TEXT OpenAI API key for LLM generation [env: OPENAI_API_KEY]
--google-api-key TEXT Google/Gemini API key (required for google-adk) [env: GOOGLE_API_KEY]
--output-dir PATH Output directory (default: ./<project-name>)
--demo Shortcut for --reset-database --demo-data --ingest
--reset-database Clear all Neo4j data before ingesting
--dry-run Preview what would be generated without creating files
--verbose Enable verbose debug output
--list-domains List available domains and exit
--version Show version and exit
--help Show help and exitContext Graph Architecture
<p align="center"> <img src="docs/static/img/architecture-overview.png" alt="Architecture: generation pipeline and runtime components" width="800" /> </p>
Every generated app demonstrates the three-memory-type architecture from neo4j-agent-memory:
<p align="center"> <img src="docs/static/img/memory-architecture.png" alt="Three memory types: short-term, long-term, and reasoning memory in Neo4j" width="700" /> </p>
Short-term memory — Conversation history and document content stored as messages
Long-term memory — Entity knowledge graph built on the POLE+O model (Person, Organization, Location, Event, Object)
Reasoning memory — Decision traces with full provenance: thought chains, tool calls, causal relationships
This is what makes context graphs different from simple RAG — the agent doesn't just retrieve text, it reasons over a structured knowledge graph with full decision traceability.
With --with-mcp, the generated project also includes an MCP server configuration that connects Claude Desktop to the same knowledge graph. This dual-interface architecture means the web app and Claude Desktop share one context graph — entities, conversations, and reasoning traces are available everywhere.
Development
# Clone and install
git clone https://github.com/neo4j-labs/create-context-graph.git
cd create-context-graph
uv venv && uv pip install -e ".[dev]"
# Run tests (no Neo4j or API keys required)
source .venv/bin/activate
pytest tests/ -v # Fast: 1,177 tests
pytest tests/ -v --slow # Full: 1,398 tests (includes domain x framework matrix + perf + generated project tests)
pytest tests/ --integration # Integration tests (requires running Neo4j)
# Test a specific scaffold
create-context-graph /tmp/test-app --domain software-engineering --framework pydanticai --demo-dataMakefile Targets
| Target | Description | Requirements |
|---|---|---|
make test | Run fast unit tests (1,177 tests) | None |
make test-slow | Full suite including matrix + perf + generated project tests (1,398 tests) | None |
make test-matrix | Domain × framework matrix only (176 combos) | None |
make test-coverage | Tests with HTML coverage report | None |
make smoke-test | E2E smoke tests for 3 key frameworks | Neo4j + LLM API keys |
make lint | Run ruff linter | ruff |
make scaffold | Scaffold a test project to /tmp/test-scaffold | None |
make build | Build Python package (sdist + wheel) | None |
make docs | Start Docusaurus dev server | Node.js |
E2E Smoke Tests
The smoke tests scaffold a real project, install dependencies, start the backend, and send chat prompts to verify the full pipeline works end-to-end. Pass --backend nams to test the hosted-memory path (requires MEMORY_API_KEY env); the default bolt exercises self-hosted Neo4j with full demo fixtures:
# Run all 3 smoke tests (requires Neo4j + at least one LLM API key)
make smoke-test
# Or run individual framework tests directly (default: --backend bolt)
python scripts/e2e_smoke_test.py --domain financial-services --framework pydanticai --quick
python scripts/e2e_smoke_test.py --domain real-estate --framework google-adk --quick
python scripts/e2e_smoke_test.py --domain trip-planning --framework strands --quick
# Test against NAMS hosted backend (requires MEMORY_API_KEY env)
python scripts/e2e_smoke_test.py --domain healthcare --framework strands --backend nams --quick
# Test all 27 domains with one framework
python scripts/e2e_smoke_test.py --all-domains --framework pydanticai --quick
# Full mode (all prompts per scenario, not just first)
python scripts/e2e_smoke_test.py --domain healthcare --framework claude-agent-sdkRequired environment variables:
NEO4J_URI,NEO4J_USERNAME,NEO4J_PASSWORD— Neo4j connection (Aura, Docker, or local) for--backend boltMEMORY_API_KEY— NAMS API key for--backend namsANTHROPIC_API_KEY— for Claude-based frameworks (PydanticAI, Claude Agent SDK, Anthropic Tools, Strands, CrewAI)OPENAI_API_KEY— for OpenAI-based frameworks (OpenAI Agents, LangGraph)GOOGLE_API_KEY— for Google ADK (Gemini)
CI Pipeline
GitHub Actions (.github/workflows/ci.yml) runs automatically:
| Job | Trigger | Description |
|---|---|---|
| test | All pushes + PRs | Unit tests on Python 3.11 and 3.12 (1,177 tests including security, doc snippets, frontend logic, NAMS adapter, wizard, route integration) |
| lint | All pushes + PRs | Ruff linter on src/ and tests/ |
| matrix | Push to main only | Full suite + 176 domain × framework matrix + perf + generated project tests (1,398 tests) |
| smoke-test | Push to main only | Neo4j integration tests + E2E for all 8 frameworks (scaffold → install → start → chat) |
The smoke-test CI job is gated behind a SMOKE_TESTS_ENABLED repository variable. To enable it:
Go to Settings → Variables → Repository variables and add
SMOKE_TESTS_ENABLED=trueGo to Settings → Secrets → Repository secrets and add:
NEO4J_URI— e.g.,neo4j+s://xxxxx.databases.neo4j.ioNEO4J_USERNAMENEO4J_PASSWORDANTHROPIC_API_KEYOPENAI_API_KEYGOOGLE_API_KEY
The smoke-test job uses fail-fast: false so one framework failure doesn't block the others, and it only runs after the unit test job passes.
The npm package is a thin wrapper that delegates to the Python CLI via uvx, pipx, or python3 -m. It requires Python 3.11+ to be installed.
Automated Publishing (GitHub Actions)
Both packages are published automatically when you push a version tag:
# 1. Update version in pyproject.toml and npm-wrapper/package.json
# 2. Commit the version bump (and any CHANGELOG.md update)
# 3. Tag and push
git tag v0.13.0
git push origin v0.13.0This triggers a GitHub Actions workflow, release.yml with jobs:
publish-pypi — Builds and publishes to PyPI
publish-npm — Publishes the npm wrapper to npmjs.com Both use trusted publishing/OIDC.
Version Bumping
Both packages must use the same version. Update in two places:
pyproject.toml→version = "X.Y.Z"npm-wrapper/package.json→"version": "X.Y.Z"
Note: a job called validate-version-consistency in release.yml ensures that the correct versions exist in both places.
License
Apache-2.0
CLAUDE.md
CLAUDE.md — Create Context Graph
Project Overview
Interactive CLI scaffolding tool that generates domain-specific context graph applications. Like create-next-app but for AI agents with graph memory. Invoked via uvx create-context-graph or npx create-context-graph.
Given a domain (e.g., "healthcare", "wildlife-management") and an agent framework (e.g., PydanticAI, Claude Agent SDK), it generates a complete full-stack application: FastAPI backend, Next.js + Chakra UI v3 + NVL frontend, Neo4j schema, synthetic data, and a configured AI agent with domain-specific tools.
Status: v0.14.0. Community PR hardening release — integrates PRs #52/#56/#58/#59/#60, closes the gaps found reviewing them, and fixes five breaks found by live-testing the full NAMS flow against the production service with neo4j-agent-memory 0.5.0: (1) conversation memory was silently failing on every message — the NAMS service only accepts messages addressed to conversation ids IT minted, so generated memory.py now creates conversations per session and targets the server id (_resolve_nams_conversation()), and store_message() treats MemoryIntegration's swallowed {"error": ...} returns as failures; (2) every document/body ingest write failed (role="document" rejected — only user/assistant/system allowed — plus the conversation-404), fixed across all three NAMS ingest implementations (run_nams_ingest, scaffolded import_data.py, make seed's ingest_fixtures_nams) with role="user" + metadata.kind markers and server-created channels; (3) /api/documents and /api/schema/visualization returned nothing (the live service coerces OBJECT/EVENT entity types to custom and rejects empty search queries) — both adapters are now cypher-first via the _pole_type: OBJECT_ description marker / type-count aggregation with search fallbacks; (4) graph expand + entity connections were dead (long_term.get_entity(id) doesn't exist in 0.5.x) — expand_node_nams/get_entity_detail_nams resolve through the cypher API; (5) NAMS reset never deleted anything (delete_entity doesn't exist upstream; the old loop swallowed the AttributeError and printed "0 removed") — --reset-database and make reset now honestly report that no delete API exists and point at the NAMS dashboard. NAMS domain ontology activation (new): NAMS pre-registers a server-side ontology for every bundled domain but auto-binds workspaces to nams-default until one is activated — generated apps now bind on connect_memory() (activate catalog match by domain id, or create-from-backend/app/ontology_document.json + activate for custom domains, best-effort via _ensure_nams_ontology()), the CLI ingest and scaffolded import_data.py run the same stage-0 sequence (parity-pinned), and build_nams_ontology_document() in ontology.py produces the server document shape ({domain, entity_types, relationships}) used by the renderer and ingest; verified live — workspace flips nams-default→healthcare on first connect, custom test-domain creates+activates server-side; stored entity type still coerces to {Person,Organization,Location,custom} server-side regardless (activation governs version stamp + extraction vocabulary). Verified live: 19/19 API checks, clean document ingest, working chat-memory writes, cypher reads (writes rejected server-side), trace ingest OK (list_traces NotSupported → /traces degrades to empty), and add_relationship still NotSupported so ccg-edges remains the design. New --neo4j-database / NEO4J_DATABASE for the self-hosted backend, threaded end-to-end: CLI flag, wizard prompt, Aura .env import (explicit flag wins), generated .env + .env.example, Settings.neo4j_database, MemorySettings (key omitted when blank so the SDK default neo4j applies), execute_cypher() sessions, scaffold-time ingest.py (_ingest_with_memory_client/_ingest_with_driver/reset_neo4j), the scaffolded import_data.py bolt session, and validate_connection(database=). Live memory-write failures now surface: store_message() records into the classified error state and the bolt /health gains memory/memory_error/memory_error_detail (startup lifecycle checks get_client() instead of assuming success). execute_cypher() dispatches to NAMS client.query.cypher (with _coerce_nams_records() shape coercion) so agent tools and POST /cypher work on the hosted backend; _require_neo4j() 503s when the NAMS client is missing. --ontology-file is implemented (was documented-only, issue #50): scaffolds from a hand-written YAML, copies it to data/ontology.yaml, mutually exclusive with --custom-domain, works through the wizard path too. load_domain() resolves custom domains from ~/.create-context-graph/custom-domains/ with a declared-domain.id fallback (issue #30); bundled domains shadow same-id customs; the test suite is hermetic against that directory via an autouse conftest fixture. Playwright spec template survives missing demo_scenarios AND a scenario with empty prompts. Schema-DDL splitter bug fixed: the old split(";") + skip-// pattern silently dropped 5 real statements behind comment headers (person_name, document_title, document_domain, document_name_unique, local_file_fulltext were never created by seeding) and executed a comment tail as Cypher; new shared split_cypher_statements() in ontology.py is used by ingest.py, the generated generate_data.py, and test_integration.py. New test surfaces: tests/test_generated_client_runtime.py (26 tests executing the rendered client/memory modules against doubles), +6 app-level route tests, +12 CLI tests, +5 wizard tests, +17 template pins, +9 ontology tests, +3 integration tests, generated test_routes.py gains 2 backend-specific /health tests, test_generated_tests.py runs one bolt scaffold, and e2e_smoke_test.py asserts the /health contract shape. Carry-forward from v0.13.1 (feedback-report triage): create-context-graph --dry-run no longer demands a NAMS API key (the credential gate is now scoped to non-dry-run flows in cli.py:392). Dead template_id parameter dropped from list_documents_nams (NAMS branch already raises 501). Generated Pydantic app/models.py now emits Field(...) for required fields instead of bare = ... Ellipsis literal. New GET /schema/models endpoint introspects app.models at runtime and returns the JSON Schema for each entity model — makes the previously-unused models.py load-bearing. Last key={\${e.name}-${i}`}site (DocumentBrowser mentioned-entities) replaced withkey={`${selectedDoc.document.title}-${e.name}`}. New regression tests (TestCompositeKeyRegressionsintest_frontend_logic.pyplusTestV0131ModelsPolishandTestV0131TemplateIdRemovalintest_generated_project.py) plus 3 new Playwright tests pin the v0.12.0/v0.13.0 fixes. The v0.13.0 report's claims about connector code being removed from scaffolded projects, pyproject.toml bloat on NAMS, and missing domains (media, insurance, supply-chain) were verified-false against current code — see CHANGELOG.md"Not Changed" section. **Carry-forward from v0.13.0 (v0.12.0 feedback-report fixes):** Fixed the bolt async/sync mismatch in the scaffoldedimport_data.py (ingest_via_bolt()isasync defand both call sites wrap withasyncio.run); ChatInterface stale-closure bug fixed by moving streamingEntities/streamingPreferencesto refs;list_documents_namspushes the OBJECT filter server-side;externalInputuseEffect depends onloading. Removed the --framework maf alias entirely (Click rejects with "Invalid value"). Restored 4 domains as YAML definitions (legal, education, cybersecurity, government); domain count is now 27. New Docusaurus page docs/docs/explanation/ccg-edges.mddocuments the relationship-encoding strategy. **Carry-forward from v0.12.0 (NAMS-native connector ingest release):** Default memory backend is the hosted Neo4j Agent Memory Service (NAMS,MEMORY_API_KEYenv), with--self-hostedpreserving the bolt-Neo4j path. **LiteLLM provider injection** for memory layer viaMEMORY_LLM/MEMORY_EMBEDDINGenv vars (LiteLLM-style strings) routes through native adapters when available, LiteLLM otherwise. Default framework is **AWS Strands**. Wizard collapsed from 11 prompts to 6 with autocomplete domain picker and a single "Customize advanced settings" gate. NAMS ingest now uses a **hybrid write shape**: entities viaadd_entitywith non-name properties markdown-serialized into thedescriptionfield; **outbound relationships encoded into the source entity'sdescriptionas a fenced ```ccg-edges``` YAML block** (sorted bytypethentarget) since NAMS REST has no add_relationshipyet — the frontend parses these out for the graph view, and a future migration will replay them as native edges; **documents dual-tracked** aslong_term.add_entity(type=OBJECT)(queryable source of truth, matches bolt:Documentshape) ANDshort_term.add_message(role="document")(extraction fuel); **entity bodies routed throughadd_message** when the connector declares a BODY_FIELDS: dict[label, property]map (e.g.Comment.bodyfor Linear,Message.contentfor Claude AI/ChatGPT/Claude Code,DecisionThread.content/Reply.contentfor Google Workspace,Document.description/Section.descriptionfor local-file); decision traces viareasoning.start_trace/add_step/complete_trace. Preferences and facts still unsupported by NAMS REST (logged-skipped). Schema DDL skipped on NAMS (server-owned). The two ingest consumers (src/create_context_graph/ingest.py run_nams_ingest()and the scaffoldedtemplates/backend/connectors/import_data.py.j2) share the same NAMS write sequence pinned by tests/test_nams_ingest_parity.py(~526 LOC contract test). Generatedimport_data.pyis **idempotent**: per-connector watermarks in.context-graph/watermarks.json(re-runs fetch deltas only), failures appended to.context-graph/deadletter.jsonl, new --dry-run(fetch only) and--retry(drain deadletter) modes, surfaced viamake import(fetch + ingest),make import-dry-run, make import-retry(the legacymake import-and-seedtarget is gone —make importis the single entrypoint)./documents?template_id=...returns HTTP 501 on NAMS (template filtering needsMENTIONSedges that NAMS doesn't have); un-filtered/documentsworks on both backends. Bolt ingest hardened withrequire_safe_cypher_identifier()(relationship types and labels validated against[A-Za-z][A-Za-z0-9]*before string interpolation) and labeledMATCH (a:SourceLabel)/MATCH (b:TargetLabel)(no more label-less fallback that could mis-merge).ingest_data()library entry point now accepts either aProjectConfigor the legacy(neo4j_uri, neo4j_username, neo4j_password) triple (v0.11.0 had broken legacy callers). Frontend routes (/expand, /documents, /traces, /schema/visualization, /entities/{name}, /search) dispatch through memory_adapter.pyon NAMS. MCP profile coerced tocoreon NAMS (extended-profile tools rely on unsupported endpoints).auto_preferencesforcedFalseon NAMS. Generatedpyproject.tomlpinsneo4j-agent-memory[litellm,sentence-transformers]>=0.4.0,<0.6.0; self-hosted scaffolds also pull [extraction,fuzzy]. 27 domains, 8 agent frameworks (7 working out of box — openai-agents requires OPENAI_API_KEY, google-adk requires GOOGLE_API_KEY with clear warnings), **streaming chat via Server-Sent Events** (token-by-token text in 6 frameworks + real-time tool call visualization with Timeline/Spinner/Collapsible + entities_extractedandpreferences_detected SSE events displayed as badges), neo4j-agent-memory v0.1.0 MemoryIntegration for multi-turn conversations with automatic entity extraction and preference detection (local sentence-transformers embeddings by default — no OpenAI key required; auto-upgrades to OpenAI embeddings if OPENAI_API_KEY is set), MCP server generation for Claude Desktop (--with-mcpflag,make mcp-server target, dual-interface architecture), configurable session strategies (per_conversation/per_day/persistentviaSESSION_STRATEGYenv var), interactive NVL graph visualization (schema view, double-click expand, drag/zoom, property panel, agent-driven graph updates — now updated incrementally during streaming, node hover tooltips, "Ask about this" button), LLM-generated demo data (80-90 entities, 25+ documents, 8-12 decision traces per domain) with post-generation value clamping for 28 property types, markdown rendering in chat and document browser with ReactMarkdown, document browser with pagination, entity detail panel, decision trace viewer, 13 SaaS connectors (including Linear for real project data import, Google Workspace for decision trace extraction from comment threads, Claude Code for local session history import with decision/preference extraction, Claude AI + ChatGPT for importing conversation exports from AI chat platforms, and local-file for deterministic ingestion of local Markdown / PDF / HTML / AsciiDoc / Word documents into Document → Section hierarchies), custom domain generation, Neo4j Aura .env import + neo4j-local support, Docusaurus documentation site (24 pages including quick-start, domain catalog, framework comparison, Neo4j Aura/Local guides, Docker guide, architecture diagram, "Why Context Graphs?" explainer, Google Workspace tutorial, decision trace explainer, GWS schema reference, chat history import tutorial, chat import schema reference, andccg-edgesencoding explainer), graceful Neo4j degradation with /health endpoint (retry with backoff on initial load) and 503 guards on all endpoints, Cypher injection prevention, enum identifier sanitization, configurable CORS/model/timeouts, --dry-run/--verbose/--reset-database/--demo CLI flags, CLI auto-slug generation (PROJECT_NAME optional in non-interactive mode), CLI warnings for framework-specific API key requirements (openai-agents, google-adk), constants module, WCAG accessibility improvements, chat timeout/cancel with AbortController, mobile-responsive layout, .dockerignore for Docker builds,make test-connectiontarget, framework-specific README sections, troubleshooting guide, thread-safe async bridging for sync frameworks (CrewAI/Strands), bounded agentic loops (max 15 iterations), domain-specific static name pools (1000+ names across 118 entity labels — all domain YAML labels covered) with domain-aware base entities, tool-use emphasis in all agent system prompts, domain-scoped chat history localStorage keys, SSR hydration fix, retry button on chat errors, PydanticAI tool serialization fix (JSON string return types), Google ADK API key support (--google-api-key flag) with AttributeError guard for SDK cleanup, Strands robust text extraction, CrewAI explicit Anthropic LLM config withcrewai[anthropic] dependency, domain-scoped MERGE keys ({name, domain}) for cross-domain isolation when sharing a Neo4j instance, improved static data quality (26 domain-specific industry pools, POLE-type-aware entity descriptions with 5 label categories + 7 label-specific overrides, entity-derived document titles, realistic decision trace observations, 20+ domain-specific property pools, float value clamping, taxonomy class correction), agent thinking text collapsible filter with continuation pattern support, Cypher query validation tests across all domains, fixture cross-validation tests (schema alignment + data quality), proper Document/DecisionTrace node ingestion via --ingest, Chakra UI Pro-inspired chat input redesign, list/get-by-id agent tools for all 27 domains (7-8+ tools per domain), ON CREATE/MATCH SET for constraint-safe seeding, hardened Linear connector (named constants, structured logging, URLError/JSONDecodeError/429 handling with retry, pagination safety limits, null-safe field access, team key validation in authenticate(), incremental sync via updated_after, decision traces in generated template), optional credential prompts in interactive wizard, Google Workspace connector with decision trace extraction from 6 Google APIs (Drive Files, Comments, Revisions, Activity, Calendar, Gmail) with 10 decision-focused agent tools and cross-connector Linear linking, scaffolded Claude Code connector with full entity extraction (9 entity types, 14 relationship types, secret redaction, decision/preference extraction, language detection), connector-specific demo scenarios, 1,454 passing tests in the fast suite; the full CI suite (dev+connectors extras, --slow --functional`) runs 1,866 passing / 1,881 collected.
Quick Reference
# Setup
uv venv && uv pip install -e ".[dev]"
# Run tests
source .venv/bin/activate && pytest tests/ -v
# Default scaffold (NAMS-backed, empty graph — agent populates via chat)
create-context-graph my-app --domain healthcare --framework strands --nams-api-key sk-...
# Self-hosted scaffold (bolt Neo4j, full demo fixtures)
create-context-graph my-app --domain financial-services --framework pydanticai --self-hosted --demo-data
# List available domains
create-context-graph --list-domainsArchitecture
src/create_context_graph/
├── cli.py # Click CLI entry point (interactive + flag modes)
├── wizard.py # 7-step Questionary interactive wizard
├── config.py # ProjectConfig Pydantic model
├── ontology.py # YAML domain ontology loader, validation, code generation
├── custom_domain.py # LLM-powered custom domain YAML generation
├── renderer.py # Jinja2 template engine (renders project scaffold)
├── generator.py # LLM-powered synthetic data pipeline (4 stages)
├── name_pools.py # Realistic name pools and value generators for static fallback
├── ingest.py # Neo4j ingestion via neo4j-agent-memory or direct driver
├── neo4j_validator.py # Neo4j connection testing
├── connectors/ # SaaS data connectors (10 services)
│ ├── __init__.py # BaseConnector ABC, NormalizedData model, registry
│ ├── github_connector.py
│ ├── notion_connector.py
│ ├── jira_connector.py
│ ├── slack_connector.py
│ ├── gmail_connector.py # Prefers gws CLI, falls back to Python OAuth2
│ ├── gcal_connector.py # Prefers gws CLI, falls back to Python OAuth2
│ ├── salesforce_connector.py
│ └── oauth.py # Shared OAuth2 flow + gws CLI helpers
├── domains/ # 23 YAML ontology definitions + _base.yaml
├── fixtures/ # 22 pre-generated JSON fixture files
└── templates/ # Jinja2 templates for generated projects
├── base/ # .env, .env.example, Makefile, docker-compose, README, .gitignore
├── backend/
│ ├── shared/ # FastAPI main, config, neo4j client, GDS, vector, models, routes
│ ├── agents/ # Per-framework agent.py (8 frameworks)
│ └── connectors/ # Generated connector modules + import_data.py
├── frontend/ # Next.js + Chakra UI v3 + NVL components
└── cypher/ # Schema constraints + GDS projectionsKey Design Decisions
Templates are domain-agnostic, data-driven
No per-domain template directories. The ontology YAML drives all domain customization via Jinja2 context variables. Only backend/agents/{framework}/agent.py.j2 varies by framework — everything else is shared.
Jinja2 + JSX/Python escaping
Templates that contain JSX curly braces or Python dict literals must use {% raw %}...{% endraw %} blocks to avoid conflicts with Jinja2's {{ }} syntax. Break out of raw mode only for actual Jinja2 substitutions:
{% raw %}JSX code with {curly} braces{% endraw %}{{ jinja_var }}{% raw %}more JSX{% endraw %}Two-layer ontology inheritance
_base.yaml defines shared POLE+O entity types (Person, Organization, Location, Event, Object). Domain YAMLs declare inherits: _base and add domain-specific entity types. The ontology.py loader merges base entities/relationships into each domain.
Rich fixture data pipeline
Pre-generated fixtures (shipped): All 27 domains ship with high-quality LLM-generated fixture data (80-90 entities, 160-280 relationships, 25+ documents at 200-1600 words, 3-5 decision traces with multi-step reasoning). Generated via
scripts/regenerate_fixtures.pyusing Claude API.Static fallback (no LLM key at runtime): Uses domain-specific name pools (
name_pools.py) with 1000+ names across 118 entity labels (all domain YAML labels covered — no more fallback to generic "Label 1" names), label-aware ID prefixes (PAT- for Patient, ACT- for Account), contextual property generators (emails from names, realistic IDs, domain-appropriate ranges), 26 domain-specific industry pools (DOMAIN_INDUSTRY_POOL), POLE-type-aware entity descriptions (_generate_descriptionwith 5 label categories:_PERSON_LABELS,_ORGANIZATION_LABELS,_LOCATION_LABELS,_EVENT_LABELS,_OBJECT_LABELS+ 7 label-specific override templates), entity-derived document titles (reference primary entities instead of sequential numbers), Markdown-formatted document content, 12+ domain-specific property pools (currency codes, ticker symbols, drug classes, medical specialties, severities, etc.), float clamping for confidence/rating/efficiency fields, and realistic decision trace observations (reference entity names).Post-generation validation (
_validate_and_clamp()ingenerator.py): LLM-generated entities are post-processed to clamp unrealistic numeric values (28 property range rules) and fix taxonomy class mismatches (species → correct class mapping).LLM-powered (with
--anthropic-api-keyat runtime): Generates realistic entities, documents, and decision traces via Anthropic or OpenAI APIs.Data seeding (
make seed): Loads all four data types into Neo4j — entities, relationships, documents (as:Documentnodes with:MENTIONSlinks to entities), and decision traces (as:DecisionTrace→:HAS_STEP→:TraceStepchains).
Dual ingestion backends
ingest.py tries neo4j-agent-memory MemoryClient first, falls back to direct neo4j driver if the package isn't installed. Both paths create entities via MemoryClient or direct Cypher, plus create :Document and :DecisionTrace/:TraceStep nodes using direct Cypher (matching the generate_data.py.j2 schema the frontend queries expect). Both paths tag all entities with a domain property for cross-domain isolation when sharing a Neo4j instance.
Custom domain generation
custom_domain.py generates complete domain ontology YAMLs from natural language descriptions using LLM (Anthropic/OpenAI). Uses _base.yaml + 2 reference domain YAMLs as few-shot examples. Validates output against DomainOntology Pydantic model with retry loop (up to 3 attempts). Generated domains can be saved to ~/.create-context-graph/custom-domains/ for reuse.
Streaming chat via Server-Sent Events (SSE)
The chat uses a streaming architecture where the backend emits SSE events as the agent executes. The POST /chat/stream endpoint creates an asyncio.Queue on the CypherResultCollector and launches the agent in a background task. As tools execute, the collector emits tool_start and tool_end events (with graph data). For frameworks that support it (PydanticAI, Anthropic Tools, Claude Agent SDK, OpenAI Agents, LangGraph), text_delta events stream tokens as they arrive. Other frameworks (CrewAI, Strands, Google ADK) emit tool events in real-time with text arriving at the end. Two additional event types support memory feedback: entities_extracted (emitted by CypherResultCollector.emit_entities_extracted() when entities are extracted from stored messages) and preferences_detected (emitted by CypherResultCollector.emit_preferences_detected() when preferences are detected). These are displayed as badges in the frontend. The frontend parses SSE via fetch + ReadableStream (not EventSource, which only supports GET). Tool calls render as a Chakra UI Timeline with live Spinner indicators. Text deltas are batched (~50ms) before updating ReactMarkdown to avoid excessive re-renders. Graph visualization updates incrementally after each tool_end event. The original /chat endpoint is preserved for backward compatibility. The SSE endpoint has a 120s per-event idle timeout and a 300s overall timeout.
Thread-safe async bridging for sync frameworks
CrewAI and Strands are synchronous frameworks that run in worker threads via asyncio.to_thread(). Their tools need to call async execute_cypher(). The _run_sync() helper uses asyncio.run_coroutine_threadsafe() to schedule coroutines on the main event loop (captured via _capture_loop() before to_thread), with a 30s timeout. The CypherResultCollector._push_event() is also thread-safe — it detects worker threads and uses loop.call_soon_threadsafe() instead of direct put_nowait(). Google ADK uses nest_asyncio for same-thread reentrant calls with a cross-thread run_coroutine_threadsafe fallback.
Bounded agentic loops
Claude Agent SDK and Anthropic Tools use agentic while loops that process tool calls until the model stops. These loops are bounded to 15 iterations (for _iteration in range(max_iterations)) with a 60s timeout on each API call. If max iterations is exceeded, a fallback message is returned instead of hanging indefinitely.
Tool-use emphasis in system prompts
All 8 agent templates append a tool-use emphasis suffix to the domain system prompt: "IMPORTANT: You MUST use the available tools to query the knowledge graph before answering any question about the data." This ensures agents consistently invoke their tools rather than generating ungrounded answers.
Agent tool return type convention
All agent tools must return str (JSON-serialized via json.dumps(result, default=str)), not raw list[dict]. PydanticAI, CrewAI, Strands, Google ADK, and other frameworks need to serialize tool outputs to send them back to the LLM. Raw Neo4j Node/Relationship objects cause silent serialization failures. The default=str handler ensures Neo4j-specific types (datetime, spatial) serialize correctly.
Agent thinking text filter
The frontend ChatInterface includes a splitThinkingAndResponse() function that detects agent "thinking" patterns (lines starting with "Let me", "I'll", "First, I need to", etc.) and renders them in a collapsible "Show reasoning" section. CONTINUATION_PATTERNS catch multi-sentence thinking blocks (lines starting with "and", "also", "then", "so", "because", etc.) that follow an initial thinking line. Lines with markdown formatting (#, -, *, |) break out of thinking mode. This keeps the primary response focused while making the full reasoning chain available on demand.
Interactive graph visualization with agent integration
The frontend ContextGraphView starts in schema view (calls db.schema.visualization() via GET /schema/visualization) showing entity types as nodes and relationship types as edges. When the user interacts with the agent chat, tool call results flow to the graph automatically via the CypherResultCollector in context_graph_client.py. In streaming mode, graph data arrives incrementally with each tool_end SSE event — the ChatInterface calls onGraphUpdate for each tool completion, so the graph updates as each tool finishes rather than all at once. The page.tsx passes data to ContextGraphView as externalGraphData. Double-clicking a schema node loads instances of that label; double-clicking a data node calls POST /expand to fetch neighbors (deduplicated merge). NVL uses d3Force layout with drag/zoom/pan, click for property details, and canvas click to deselect. Nodes have hover tooltips showing full name, labels, and top 5 properties. Clicking a node reveals an "Ask about [entity]" button that sends a chat query via the onAskAbout → externalInput → ChatInterface callback chain.
neo4j-agent-memory integration
Generated projects use MemoryIntegration from neo4j-agent-memory v0.4+ for conversation memory with automatic entity extraction (and, on the bolt backend, preference detection). The memory.py.j2 template generates a shared backend/app/memory.py module with connect_memory(), close_memory(), store_message(), get_context(), and resolve_session_id() functions. context_graph_client.py.j2 delegates memory lifecycle to this module via from app.memory import connect_memory, close_memory. The store_message() return value includes extracted entities and detected preferences, which are emitted as SSE events (entities_extracted, preferences_detected) and displayed as badges in the frontend. Session identity is configurable via SESSION_STRATEGY env var: per_conversation (default), per_day, or persistent. The generated pyproject.toml pins neo4j-agent-memory>=0.4.0,<0.6.0 with extras conditional on the backend: NAMS scaffolds get [litellm,sentence-transformers] (extraction happens server-side); self-hosted bolt scaffolds also pull [extraction,fuzzy] for local spaCy/GLiNER + rapidfuzz. All 8 agent frameworks import from app.memory and call resolve_session_id(), store_message(), and get_context() (which returns messages + entities + preferences + traces). The frontend ChatInterface captures session_id from the first SSE response and sends it in all subsequent requests.
MCP server generation
Generated projects optionally include an MCP (Model Context Protocol) server configuration for Claude Desktop. When --with-mcp is passed (or selected in the wizard), the scaffold generates mcp/claude_desktop_config.json (pre-configured for the project's Neo4j instance), mcp/README.md (setup instructions), and a make mcp-server Makefile target. The MCP server runs neo4j-agent-memory's built-in MCP server with 16 tools (extended profile) or 6 tools (core profile, via --mcp-profile core). This creates a dual-interface architecture: the web app and Claude Desktop both query the same knowledge graph.
Neo4j driver serialization
context_graph_client.py.j2 uses a custom _serialize() function instead of the driver's .data() method. This preserves Neo4j Node metadata (elementId, labels), Relationship metadata (elementId, type, startNodeElementId, endNodeElementId), and Path expansion. Without this, the frontend graph visualization and agent tools receive flat property dicts with no type information.
SaaS connectors
connectors/ package with 13 service connectors (GitHub, Notion, Jira, Slack, Gmail, Google Calendar, Salesforce, Linear, Google Workspace, Claude Code, Claude AI, ChatGPT, local-file). Each connector implements BaseConnector ABC with authenticate(), fetch(), and get_credential_prompts() methods. Credential prompts support an optional flag — the wizard skips blank optional fields instead of aborting. Returns NormalizedData matching the fixture schema so ingest.py works unchanged. Gmail/Google Calendar prefer the Google Workspace CLI (gws) if available, with Python OAuth2 fallback. The Linear connector uses GraphQL with cursor-based pagination and rate limiting against https://api.linear.app/graphql, mapping 12 entity types (Issue, Project, Cycle, Team, Person, Label, WorkflowState, Comment, ProjectUpdate, ProjectMilestone, Initiative, Attachment) to the POLE+O entity model with 26 relationship types. Imports issue relations (BLOCKS, BLOCKED_BY, RELATED_TO, DUPLICATE_OF), threaded comments with resolution tracking (REPLY_TO, RESOLVED_BY), project updates with health status, milestones, initiatives, attachments, and Linear Docs. Issue history entries are transformed into decision traces (DecisionTrace → TraceStep chains) capturing state transitions, assignment changes, and priority changes with actor attribution. The Linear connector includes structured logging (logging.getLogger(__name__)), named constants for all page sizes and limits, error handling for URLError/JSONDecodeError/GraphQL errors, HTTP 429 retry with exponential backoff, pagination safety limits (MAX_PAGES), null-safe field access via _safe_nodes() helper, team key validation during authenticate() (lists available keys on mismatch), incremental sync via fetch(updated_after="ISO8601"), and truncation warnings when comments or history exceed page limits. The generated template (linear_connector.py.j2) has full parity with the source connector including decision trace generation. The Google Workspace connector imports from 6 Google APIs (Drive Files, Drive Comments, Drive Revisions, Drive Activity, Calendar, Gmail) with OAuth2 authentication and dynamic scope building. Its defining feature is decision trace extraction: resolved comment threads in Google Docs become DecisionThread graph nodes with question, deliberation, resolution, and participants — linked to documents, people, meetings, and email threads. Includes 10 decision-focused agent tools (find_decisions, decision_context, who_decided, document_timeline, open_questions, meeting_decisions, knowledge_contributors, trace_decision_to_source, stale_documents, cross_reference) injected via the renderer when the connector is active. Cross-connector linking detects Linear issue references (e.g., ENG-123) in comment bodies, doc names, email subjects, and meeting descriptions, creating RELATES_TO_ISSUE relationships. Rate limiting enforces 950 queries/100s with exponential backoff. 9 CLI flags (--gws-folder-id, --gws-include-comments, --gws-include-revisions, --gws-include-activity, --gws-include-calendar, --gws-include-gmail, --gws-since, --gws-mime-types, --gws-max-files). The generated template (google_workspace_connector.py.j2) has full parity with the source connector: all 7 stages (Files, Comments, Revisions, Activity, Calendar, Gmail, Cross-references) are included, using OAuth2 only (no gws CLI fallback). The Claude Code connector reads local session JSONL files from ~/.claude/projects/ — no authentication or API keys required. Parses user/assistant messages, tool_use/tool_result blocks, and progress entries. Extracts 7 entity types (Project, Session, Message, ToolCall, File, GitBranch, Error) with 10 relationship types (HAS_SESSION, HAS_MESSAGE, NEXT, USED_TOOL, MODIFIED_FILE, READ_FILE, PRECEDED_BY, ON_BRANCH, ENCOUNTERED_ERROR, RESOLVED_BY). Includes heuristic decision extraction (user corrections, deliberation markers, error-resolution cycles, dependency changes) producing Decision/Alternative entities and traces, and preference extraction (explicit statements, package frequency) producing Preference entities. Secret redaction (API keys, tokens, passwords, connection strings) is applied by default. 8 session intelligence agent tools (search_sessions, decision_history, file_timeline, error_patterns, tool_usage_stats, my_preferences, project_overview, reasoning_trace) injected via the renderer. 5 CLI flags (--claude-code-scope, --claude-code-project, --claude-code-since, --claude-code-max-sessions, --claude-code-content). Implementation split into connectors/claude_code_connector.py (main connector) and connectors/_claude_code/ subpackage (parser.py, redactor.py, decision_extractor.py, preference_extractor.py). The Claude AI connector imports conversations from the official Claude AI data export (Settings > Account > Export Data). Parses conversations.jsonl from .zip or raw .jsonl with streaming line-by-line processing for memory efficiency on large exports (1GB+). Extracts content from structured content blocks (text, tool_use, tool_result, thinking). Normalizes sender values (human → user). Creates Conversation, Message entities with HAS_MESSAGE/NEXT relationships. Generates Document per conversation for search/RAG. Deep mode extracts tool call sequences as DecisionTrace nodes. 7 CLI flags (--import-type, --import-file, --import-depth, --import-filter-after, --import-filter-before, --import-filter-title, --import-max-conversations). Implementation split into connectors/claude_ai_connector.py (main connector) and connectors/_claude_ai/ subpackage (parser.py). Shared data models and zip utilities in connectors/_chat_import/ subpackage (models.py, zip_reader.py). The ChatGPT connector imports conversations from the official ChatGPT data export (Settings > Data Controls > Export Data). Parses conversations.json from .zip or raw .json. Handles tree-structured mapping field with parent/children references — walks depth-first following last child at branch points. Filters out system messages and hidden messages (is_visually_hidden_from_conversation). Converts Unix float timestamps to ISO 8601. Handles content types: text, code, execution_output, multimodal_text. Tool-role messages captured with execution output as tool results. Same entity schema and CLI flags as Claude AI connector. Implementation in connectors/chatgpt_connector.py and connectors/_chatgpt/ subpackage (parser.py). The local-file connector ingests local Markdown, PDF, HTML, AsciiDoc, and Word documents into :Document → :Section hierarchies with LINKS_TO edges between sections and documents. Fully deterministic — no LLMs, no embeddings, no randomness. URI-keyed nodes integrate with the existing MERGE-on-(name, domain) pipeline in ingest.py without modification. Section URIs use GitHub/Pandoc slug rules (NFKD-normalize, ASCII-lower, [a-z0-9_] runs collapse to -); duplicate-heading collisions disambiguate per-parent (-1, -2, …); skipped heading levels (e.g. H1 → H3) preserve the original level on the child node. Per-format parser strategy: markdown-it-py with GFM extensions (Markdown); three-tier fallback pypdf outline → /StructTreeRoot → pdfplumber font-size heuristic (PDF); BeautifulSoup + lxml (HTML); pure-Python regex with block-delimiter state tracking (AsciiDoc); python-docx (Word). New optional dependencies in the connectors extra: markdown-it-py, mdit-py-plugins, pdf-oxide, pypdf, pdfplumber, beautifulsoup4, lxml, python-docx. Implementation in connectors/local_file_connector.py and connectors/_local_file/ subpackage (parser, mapper, slug, link-resolver). Connectors run at scaffold time AND are generated into the project with make import / make import-and-seed targets.
Domain Ontology YAML Schema
Each domain YAML file must contain:
inherits: _base— merge base POLE+O typesdomain:— id, name, description, tagline, emojientity_types:— label, pole_type (PERSON/ORGANIZATION/LOCATION/EVENT/OBJECT), subtype, color (hex), icon, properties (name, type, required, unique, enum)relationships:— type, source, targetdocument_templates:— id, name, description, count, prompt_template, required_entitiesdecision_traces:— id, task, steps (thought/action), outcome_templatedemo_scenarios:— name, prompts listagent_tools:— name, description, cypher query, parameterssystem_prompt:— multi-line agent system promptvisualization:— node_colors, node_sizes, default_cypher
Property types: string, integer, float, boolean, date, datetime, point
YAML booleans in enum values must be quoted: enum: ["true", "false"] not enum: [true, false]
Generated Project Structure
When a user runs the CLI, the output is:
my-app/
├── backend/app/ # FastAPI + chosen agent framework
│ ├── main.py, config.py, memory.py, routes.py, models.py
│ ├── agent.py # Framework-specific (8 frameworks available)
│ ├── context_graph_client.py, gds_client.py, vector_client.py
│ ├── ontology_document.json # NAMS ontology doc (create-on-connect for custom domains)
│ ├── connectors/ # Only if SaaS connectors selected
│ │ ├── __init__.py
│ │ └── {service}_connector.py # One per selected service
│ └── __init__.py
├── backend/tests/
│ ├── __init__.py
│ └── test_routes.py # Generated test scaffold (health, scenarios)
├── backend/scripts/
│ ├── generate_data.py
│ └── import_data.py # Only if SaaS connectors selected
├── backend/pyproject.toml
├── frontend/ # Next.js + Chakra UI v3 + NVL
│ ├── app/ (layout.tsx, page.tsx, globals.css)
│ ├── components/ (ChatInterface, ContextGraphView, DecisionTracePanel, DocumentBrowser, Provider)
│ ├── lib/config.ts, theme/index.ts
│ └── package.json, next.config.ts, tsconfig.json
├── cypher/ (schema.cypher, gds_projections.cypher)
├── data/ (ontology.yaml, _base.yaml, fixtures.json, documents/)
├── mcp/ # MCP server config (only if --with-mcp)
├── .env, .env.example, Makefile, docker-compose.yml, README.md, .gitignoreTesting
Unit Tests
pytest tests/ -v # Fast suite: 1,454 passing (full CI suite with connectors extra: 1,866 passing / 1,881 collected)
pytest tests/test_config.py # Config model + framework alias + google api key + crewai anthropic extra tests (26)
pytest tests/test_ontology.py # Ontology loading + all 27 domains validate + enum sanitization + color collision checks + Cypher query validation
pytest tests/test_renderer.py # Template rendering + all 8 frameworks + v0.3.0 features (64)
pytest tests/test_generator.py # Data generation pipeline (14)
pytest tests/test_cli.py # CLI integration + 8 domain/framework combos + neo4j types + validation + auto-slug + --neo4j-database + --ontology-file + Linear + Google Workspace + Claude Code connectors (84)
pytest tests/test_custom_domain.py # Custom domain generation with mocked LLM (17)
pytest tests/test_connectors.py # SaaS connectors with mocked APIs (125, includes 58 Linear + 28 Google Workspace + 38 Claude Code tests)
pytest tests/test_chat_import.py # Chat history import: Claude AI + ChatGPT parsers, connectors, CLI flags (78)
pytest tests/test_generated_project.py # Deep validation: Python/TS/Cypher syntax, memory, neo4j types, streaming, QA fixes, async bridging, thread safety, tool prompts, embeddings config, NEO4J_DATABASE + NAMS cypher + scenario-fallback pins (269)
pytest tests/test_fixtures.py # Cross-validation: schema alignment, agent tool property refs, data quality ranges (88)
pytest tests/test_security.py # Cypher injection prevention: parameterization across 27 domains, generated code static analysis, run_cypher tool safety
pytest tests/test_doc_snippets.py # Documentation validation: YAML examples parse, CLI flags exist, Cypher snippets valid, Make targets exist (8)
pytest tests/test_frontend_logic.py # Frontend logic: SSE event parsing, thinking/response split, backend/frontend event type contract (25)
pytest tests/test_routes_integration.py # Mounts the generated FastAPI app: NAMS/bolt route dispatch, /cypher on NAMS, 503 guards, /health memory surfacing (17)
pytest tests/test_generated_client_runtime.py # Executes rendered context_graph_client.py + memory.py against doubles: NAMS dispatch/coercion, database threading, store_message error state (26)
pytest tests/test_performance.py # Timed generation tests (slow, 27 domains)
pytest tests/test_generated_tests.py # Scaffold + install + run generated project test suite for 4 frameworks (slow, 5)
pytest tests/test_integration.py --integration # Neo4j integration: schema DDL, fixture ingestion, agent tool queries, domain scoping, explicit-database threading (10)Unit tests do NOT require Neo4j or any API keys. All tests use tmp_path fixtures for output. Integration tests require --integration flag and a running Neo4j instance (NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD).
E2E Smoke Tests
Full-stack integration tests that scaffold a project, install dependencies, start the backend, and send chat prompts. Requires a running Neo4j instance and LLM API keys.
make smoke-test # Run 3 key framework tests (pydanticai, google-adk, strands)
# Or run directly with more control:
python scripts/e2e_smoke_test.py --domain healthcare --framework pydanticai --quick
python scripts/e2e_smoke_test.py --all-domains --framework claude-agent-sdk --quick
python scripts/e2e_smoke_test.py --domain gaming --framework openai-agents # full mode (all prompts)Required env vars: NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD, plus ANTHROPIC_API_KEY and/or OPENAI_API_KEY and/or GOOGLE_API_KEY depending on framework.
Makefile Targets
| Target | Description |
|---|---|
make test | Fast unit tests (1,454 passing, no external deps) |
make test-slow | Full suite including matrix + perf + generated project + connector/functional tests (1,866 passing with connectors extra) |
make test-matrix | Domain × framework matrix only (176 combos) |
make test-coverage | Tests with HTML coverage report |
make test-functional | Functional test ingesting tests/fixtures/local_file_vault/ end-to-end through the local-file connector (see tests/fixtures/local_file_vault_TESTING.md for the edge-case checklist) |
make smoke-test | E2E smoke tests for 3 key frameworks (requires Neo4j + API keys) |
make lint | Run ruff linter on src/ and tests/ |
make scaffold | Scaffold a test project to /tmp/test-scaffold |
Adding a New Domain
Create
src/create_context_graph/domains/{domain-id}.yamlfollowing the schema aboveGenerate fixture data: run the CLI with
--demo-dataor usegenerator.pydirectlyCopy the fixture to
src/create_context_graph/fixtures/{domain-id}.jsonVerify:
pytest tests/test_ontology.py::TestLoadAllDomains -v
Adding a New Agent Framework
Create
src/create_context_graph/templates/backend/agents/{framework_key}/agent.py.j2(use underscores for directory name; hyphens in config key are auto-converted viafw_key = framework.replace("-", "_"))Add the framework key to
SUPPORTED_FRAMEWORKS,FRAMEWORK_DISPLAY_NAMES, andFRAMEWORK_DEPENDENCIESinconfig.pyTemplate must export
async def handle_message(message: str, session_id: str | None = None) -> dictreturning{"response": str, "session_id": str, "graph_data": dict | None, "entities_extracted": list, "preferences_detected": list}Import
store_message, get_context, resolve_session_idfromapp.memoryand call them inhandle_message()for multi-turn conversation support with entity extractionPass
tool_name=kwarg toexecute_cypher()calls for tool call visualizationUse
{% raw %}...{% endraw %}blocks for Python dict literals in the templateUse
{% for tool in agent_tools %}to generate domain-specific tools from ontologyThe template receives full ontology context:
domain,agent_tools,system_prompt,framework_display_name, etc.(Optional) Add
handle_message_stream()for text streaming: Importget_collectorfromcontext_graph_client, use the framework's streaming API to iterate text chunks, callcollector.emit_text_delta(chunk)for each, andcollector.emit_done(response_text, session_id)at the end. Tool call events fire automatically viaexecute_cypher. If not provided, the/chat/streamroute falls back tohandle_message()with tool events still streaming in real-time.Add tests to
TestAllFrameworksRenderintest_renderer.py,TestMultipleDomainScaffoldsintest_cli.py, andTestStreamingAgentTemplatesintest_generated_project.py
Current frameworks and their patterns
| Framework | Directory | Pattern | Streaming |
|---|---|---|---|
| PydanticAI | pydanticai/ | @agent.tool decorator + RunContext[AgentDeps] | Full (agent.run_stream()) |
| Claude Agent SDK | claude_agent_sdk/ | Dict-based TOOLS list + bounded agentic loop (max 15 iterations) | Full (client.messages.stream()) |
| OpenAI Agents SDK | openai_agents/ | @function_tool decorator + Runner.run() | Full (Runner.run_streamed()) |
| LangGraph | langgraph/ | @tool + create_react_agent() | Full (graph.astream_events()) |
| CrewAI | crewai/ | Agent + Task + Crew with @tool, run_coroutine_threadsafe bridging | Tools only |
| Strands | strands/ | Agent with @tool, Anthropic model, run_coroutine_threadsafe bridging | Tools only |
| Google ADK | google_adk/ | Agent + FunctionTool, Gemini model | Full (runner.run_async()) |
| Anthropic Tools | anthropic_tools/ | Modular @register_tool registry + bounded Anthropic API agentic loop (max 15 iterations) | Full (client.messages.stream()) |
Adding a New SaaS Connector
Create
src/create_context_graph/connectors/{service}_connector.pyimplementingBaseConnectorUse
@register_connector("service-id")decorator to register itImplement
authenticate(credentials),fetch(**kwargs) -> NormalizedData, andget_credential_prompts()Add the import to
connectors/__init__.pyCreate
src/create_context_graph/templates/backend/connectors/{service}_connector.py.j2(standalone version for generated projects)Update
import_data.py.j2to handle the new connectorAdd tests to
test_connectors.py
Current connectors
| Service | Connector ID | Auth | Dependencies |
|---|---|---|---|
| GitHub | github | Personal access token | PyGithub |
| Notion | notion | Integration token | notion-client |
| Jira | jira | API token | atlassian-python-api |
| Slack | slack | Bot OAuth token | slack-sdk |
| Gmail | gmail | gws CLI or OAuth2 | google-api-python-client, google-auth-oauthlib |
| Google Calendar | gcal | gws CLI or OAuth2 | google-api-python-client, google-auth-oauthlib |
| Salesforce | salesforce | Username/password | simple-salesforce |
| Linear | linear | Personal API key | (stdlib only — urllib.request) |
| Google Workspace | google-workspace | Google OAuth 2.0 | (stdlib only — urllib.request) |
| Claude Code | claude-code | None (local files) | (stdlib only — reads ~/.claude/projects/ JSONL) |
| Claude AI | claude-ai | None (local file) | (stdlib only — reads conversations.jsonl from export zip) |
| ChatGPT | chatgpt | None (local file) | (stdlib only — reads conversations.json from export zip) |
| Local File | local-file | None (local files) | markdown-it-py, mdit-py-plugins, pdf-oxide, pypdf, pdfplumber, beautifulsoup4, lxml, python-docx |
Dependencies
Core: click, questionary, rich, jinja2, pyyaml, pydantic, neo4j Optional: anthropic, openai (for LLM data generation), neo4j-agent-memory (for memory-aware ingestion) Connectors (optional): PyGithub, notion-client, atlassian-python-api, slack-sdk, google-api-python-client, google-auth-oauthlib, simple-salesforce (Linear connector uses stdlib only) Dev: pytest, pytest-cov, pytest-asyncio Build: hatchling (src layout, bundles YAML/JSON/Jinja2 files automatically)
CI Pipeline
GitHub Actions (.github/workflows/ci.yml) runs on push to main and all PRs:
| Job | Trigger | Description |
|---|---|---|
| test | All pushes + PRs | Fast unit tests on Python 3.11 and 3.12 (fail-fast: false so one version's failure doesn't cancel the other) |
| lint | All pushes + PRs | Ruff on src/ and tests/ (rule set pinned in [tool.ruff.lint], ruff version pinned in the dev extra) |
| full-suite | All pushes + PRs | Full test suite on 3.12: --slow --functional — 176 domain × framework matrix, perf tests, generated-project venv suites, local-file vault functional tests |
| smoke-test | Push to main only | Neo4j integration tests + E2E: scaffold → install → start → chat for all 8 frameworks (needs repository secrets, so it can't run on fork PRs) |
Every job installs from uv.lock via uv sync --locked --extra ... and runs commands with uv run --no-sync. Never mix uv pip install with a bare uv run in CI: uv run does an implicit lockfile sync that downgrades locked base deps underneath freshly-installed latest extras (this skew broke CI when a new anyio required a newer typing_extensions than the lock pinned). If --locked fails, run uv lock locally and commit the refreshed lockfile — dependency changes in pyproject.toml must ship with a matching uv.lock. The Makefile test/lint targets use uv run --extra dev ... so local runs resolve from the lock the same way.
The smoke-test job is gated behind vars.SMOKE_TESTS_ENABLED == 'true' (repository variable) and requires these repository secrets: NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD, ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY. It runs test_integration.py --integration before the E2E smoke tests. Uses fail-fast: false so one framework failure doesn't block others, and depends on the test job passing first.
A separate release workflow (release.yml) triggers on version tags (v*).
What's Not Yet Implemented
TypeScript compilation validation in CI (requires Node.js in test environment)
344 files · 334 not served here
- .github/workflows/ci.yml (not served here)
- .github/workflows/release.yml (not served here)
- .gitignore (not served here)
- .serena/.gitignore (not served here)
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CHANGELOG.md
- CLAUDE.md
- CONTRIBUTING.md
- LABS_DISCLAIMER.txt (not served here)
- LICENSE
- Makefile (not served here)
- README.md
- ROADMAP.md
- docs/.gitignore (not served here)
- docs/README.md
- docs/docs/explanation/ccg-edges.md (not served here)
- docs/docs/explanation/how-decision-traces-work.md (not served here)
- docs/docs/explanation/how-domain-ontologies-work.md (not served here)
- docs/docs/explanation/memory-backends.md (not served here)
- docs/docs/explanation/three-memory-types.md (not served here)
- docs/docs/explanation/why-context-graphs.md (not served here)
- docs/docs/how-to/add-custom-domain.md (not served here)
- docs/docs/how-to/configure-memory-providers.md (not served here)
- docs/docs/how-to/connect-claude-desktop.md (not served here)
- docs/docs/how-to/import-local-files.md (not served here)
- docs/docs/how-to/import-saas-data.md (not served here)
- docs/docs/how-to/switch-agent-frameworks.md (not served here)
- docs/docs/how-to/use-docker.md (not served here)
- docs/docs/how-to/use-nams.md (not served here)
- docs/docs/how-to/use-neo4j-aura.md (not served here)
- docs/docs/how-to/use-neo4j-local.md (not served here)
- docs/docs/intro.md (not served here)
- docs/docs/quick-start.md (not served here)
- docs/docs/reference/chat-import-schema.md (not served here)
- docs/docs/reference/claude-code-schema.md (not served here)
- docs/docs/reference/cli-options.md (not served here)
- docs/docs/reference/domain-catalog.md (not served here)
- docs/docs/reference/framework-comparison.md (not served here)
- docs/docs/reference/generated-project-structure.md (not served here)
- docs/docs/reference/google-workspace-schema.md (not served here)
- docs/docs/reference/ontology-yaml-schema.md (not served here)
- docs/docs/tutorials/claude-code-sessions.md (not served here)
- docs/docs/tutorials/customizing-domain-ontology.md (not served here)
- docs/docs/tutorials/first-context-graph-app.md (not served here)
- docs/docs/tutorials/google-workspace-decisions.md (not served here)
- docs/docs/tutorials/import-chat-history.md (not served here)
- docs/docs/tutorials/linear-context-graph.md (not served here)
- docs/docs/whats-new.md (not served here)
- docs/docusaurus.config.ts (not served here)
- docs/package-lock.json (not served here)
- docs/package.json (not served here)
- docs/sidebars.ts (not served here)
- docs/src/components/animations/AppPreview.module.css (not served here)
- docs/src/components/animations/AppPreview.tsx (not served here)
- docs/src/components/animations/ContextGraphExplainer.module.css (not served here)
- docs/src/components/animations/ContextGraphExplainer.tsx (not served here)
- docs/src/components/animations/DomainCarousel.module.css (not served here)
- docs/src/components/animations/DomainCarousel.tsx (not served here)
- docs/src/components/animations/FrameworkGrid.module.css (not served here)
- docs/src/components/animations/FrameworkGrid.tsx (not served here)
- docs/src/components/animations/HowItWorks.module.css (not served here)
- docs/src/components/animations/HowItWorks.tsx (not served here)
- docs/src/components/animations/TerminalAnimation.module.css (not served here)
- docs/src/components/animations/TerminalAnimation.tsx (not served here)
- docs/src/components/animations/TrustBar.module.css (not served here)
- docs/src/components/animations/TrustBar.tsx (not served here)
- docs/src/components/ui/BrowserFrame.module.css (not served here)
- docs/src/components/ui/BrowserFrame.tsx (not served here)
- docs/src/components/ui/Terminal.module.css (not served here)
- docs/src/components/ui/Terminal.tsx (not served here)
- docs/src/css/custom.css (not served here)
- docs/src/data/animation-config.ts (not served here)
- docs/src/pages/404.tsx (not served here)
- docs/src/pages/index.module.css (not served here)
- docs/src/pages/index.tsx (not served here)
- docs/src/theme/Root.tsx (not served here)
- docs/static/.nojekyll (not served here)
- docs/static/img/app-three-panel.excalidraw (not served here)
- docs/static/img/app-three-panel.png (not served here)
- docs/static/img/architecture-overview.excalidraw (not served here)
- docs/static/img/architecture-overview.png (not served here)
- docs/static/img/claude-code-data-flow.excalidraw (not served here)
- docs/static/img/claude-code-data-flow.png (not served here)
- docs/static/img/claude-code-data-pipeline.excalidraw (not served here)
- docs/static/img/claude-code-data-pipeline.png (not served here)
- docs/static/img/claude-code-decision-extraction.excalidraw (not served here)
- docs/static/img/claude-code-decision-extraction.png (not served here)
- docs/static/img/claude-code-graph-schema.excalidraw (not served here)
- docs/static/img/claude-code-graph-schema.png (not served here)
- docs/static/img/connector-data-flow.excalidraw (not served here)
- docs/static/img/connector-data-flow.png (not served here)
- docs/static/img/decision-trace-structure.excalidraw (not served here)
- docs/static/img/decision-trace-structure.png (not served here)
- docs/static/img/docusaurus-social-card.jpg (not served here)
- docs/static/img/docusaurus.png (not served here)
- docs/static/img/favicon.ico (not served here)
- docs/static/img/graph-vs-flat.excalidraw (not served here)
- docs/static/img/graph-vs-flat.png (not served here)
- docs/static/img/gws-decision-flow.excalidraw (not served here)
- docs/static/img/gws-decision-flow.png (not served here)
- docs/static/img/gws-graph-schema.excalidraw (not served here)
- docs/static/img/gws-graph-schema.png (not served here)
- docs/static/img/gws-linear-combined.excalidraw (not served here)
- docs/static/img/gws-linear-combined.png (not served here)
- docs/static/img/linear-data-flow.excalidraw (not served here)
- docs/static/img/linear-data-flow.png (not served here)
- docs/static/img/linear-graph-schema.excalidraw (not served here)
- docs/static/img/linear-graph-schema.png (not served here)
- docs/static/img/logo.svg (not served here)
- docs/static/img/memory-architecture.excalidraw (not served here)
- docs/static/img/memory-architecture.png (not served here)
- docs/static/img/ontology-pipeline.excalidraw (not served here)
- docs/static/img/ontology-pipeline.png (not served here)
- docs/static/img/screenshot-frontend.png (not served here)
- docs/static/img/undraw_docusaurus_mountain.svg (not served here)
- docs/static/img/undraw_docusaurus_react.svg (not served here)
- docs/static/img/undraw_docusaurus_tree.svg (not served here)
- docs/tsconfig.json (not served here)
- document-parsing-libraries.md
- npm-wrapper/README.md (not served here)
- npm-wrapper/bin/create-context-graph (not served here)
- npm-wrapper/package.json (not served here)
- pyproject.toml (not served here)
- scripts/e2e_smoke_test.py (not served here)
- scripts/regenerate_fixtures.py (not served here)
- src/create_context_graph/__init__.py (not served here)
- src/create_context_graph/__main__.py (not served here)
- src/create_context_graph/cli.py (not served here)
- src/create_context_graph/config.py (not served here)
- src/create_context_graph/connectors/__init__.py (not served here)
- src/create_context_graph/connectors/_chat_import/__init__.py (not served here)
- src/create_context_graph/connectors/_chat_import/models.py (not served here)
- src/create_context_graph/connectors/_chat_import/zip_reader.py (not served here)
- src/create_context_graph/connectors/_chatgpt/__init__.py (not served here)
- src/create_context_graph/connectors/_chatgpt/parser.py (not served here)
- src/create_context_graph/connectors/_claude_ai/__init__.py (not served here)
- src/create_context_graph/connectors/_claude_ai/parser.py (not served here)
- src/create_context_graph/connectors/_claude_code/__init__.py (not served here)
- src/create_context_graph/connectors/_claude_code/decision_extractor.py (not served here)
- src/create_context_graph/connectors/_claude_code/parser.py (not served here)
- src/create_context_graph/connectors/_claude_code/preference_extractor.py (not served here)
- src/create_context_graph/connectors/_claude_code/redactor.py (not served here)
- src/create_context_graph/connectors/_local_file/__init__.py (not served here)
- src/create_context_graph/connectors/_local_file/mapper.py (not served here)
- src/create_context_graph/connectors/_local_file/parser.py (not served here)
- src/create_context_graph/connectors/_local_file/parsers/__init__.py (not served here)
- src/create_context_graph/connectors/_local_file/parsers/asciidoc.py (not served here)
- src/create_context_graph/connectors/_local_file/parsers/docx.py (not served here)
- src/create_context_graph/connectors/_local_file/parsers/html.py (not served here)
- src/create_context_graph/connectors/_local_file/parsers/markdown.py (not served here)
- src/create_context_graph/connectors/_local_file/parsers/pdf.py (not served here)
- src/create_context_graph/connectors/chatgpt_connector.py (not served here)
- src/create_context_graph/connectors/claude_ai_connector.py (not served here)
- src/create_context_graph/connectors/claude_code_connector.py (not served here)
- src/create_context_graph/connectors/gcal_connector.py (not served here)
- src/create_context_graph/connectors/github_connector.py (not served here)
- src/create_context_graph/connectors/gmail_connector.py (not served here)
- src/create_context_graph/connectors/google_workspace_connector.py (not served here)
- src/create_context_graph/connectors/jira_connector.py (not served here)
- src/create_context_graph/connectors/linear_connector.py (not served here)
- src/create_context_graph/connectors/local_file_connector.py (not served here)
- src/create_context_graph/connectors/notion_connector.py (not served here)
- src/create_context_graph/connectors/oauth.py (not served here)
- src/create_context_graph/connectors/salesforce_connector.py (not served here)
- src/create_context_graph/connectors/slack_connector.py (not served here)
- src/create_context_graph/custom_domain.py (not served here)
- src/create_context_graph/domains/_base.yaml (not served here)
- src/create_context_graph/domains/agent-memory.yaml (not served here)
- src/create_context_graph/domains/conservation.yaml (not served here)
- src/create_context_graph/domains/cybersecurity.yaml (not served here)
- src/create_context_graph/domains/data-journalism.yaml (not served here)
- src/create_context_graph/domains/digital-twin.yaml (not served here)
- src/create_context_graph/domains/education.yaml (not served here)
- src/create_context_graph/domains/financial-services.yaml (not served here)
- src/create_context_graph/domains/gaming.yaml (not served here)
- src/create_context_graph/domains/genai-llm-ops.yaml (not served here)
- src/create_context_graph/domains/gis-cartography.yaml (not served here)
- src/create_context_graph/domains/golf-sports.yaml (not served here)
- src/create_context_graph/domains/government.yaml (not served here)
- src/create_context_graph/domains/healthcare.yaml (not served here)
- src/create_context_graph/domains/hospitality.yaml (not served here)
- src/create_context_graph/domains/legal.yaml (not served here)
- src/create_context_graph/domains/manufacturing.yaml (not served here)
- src/create_context_graph/domains/oil-gas.yaml (not served here)
- src/create_context_graph/domains/options-intelligence.yaml (not served here)
- src/create_context_graph/domains/personal-knowledge.yaml (not served here)
- src/create_context_graph/domains/product-management.yaml (not served here)
- src/create_context_graph/domains/real-estate.yaml (not served here)
- src/create_context_graph/domains/retail-ecommerce.yaml (not served here)
- src/create_context_graph/domains/scientific-research.yaml (not served here)
- src/create_context_graph/domains/software-engineering.yaml (not served here)
- src/create_context_graph/domains/trip-planning.yaml (not served here)
- src/create_context_graph/domains/vacation-industry.yaml (not served here)
- src/create_context_graph/domains/wildlife-management.yaml (not served here)
- src/create_context_graph/fixtures/agent-memory.json (not served here)
- src/create_context_graph/fixtures/conservation.json (not served here)
- src/create_context_graph/fixtures/cybersecurity.json (not served here)
- src/create_context_graph/fixtures/data-journalism.json (not served here)
- src/create_context_graph/fixtures/digital-twin.json (not served here)
- src/create_context_graph/fixtures/education.json (not served here)
- src/create_context_graph/fixtures/financial-services.json (not served here)
- src/create_context_graph/fixtures/gaming.json (not served here)
- src/create_context_graph/fixtures/genai-llm-ops.json (not served here)
- src/create_context_graph/fixtures/gis-cartography.json (not served here)
- src/create_context_graph/fixtures/golf-sports.json (not served here)
- src/create_context_graph/fixtures/government.json (not served here)
- src/create_context_graph/fixtures/healthcare.json (not served here)
- src/create_context_graph/fixtures/hospitality.json (not served here)
- src/create_context_graph/fixtures/legal.json (not served here)
- src/create_context_graph/fixtures/manufacturing.json (not served here)
- src/create_context_graph/fixtures/oil-gas.json (not served here)
- src/create_context_graph/fixtures/options-intelligence.json (not served here)
- src/create_context_graph/fixtures/personal-knowledge.json (not served here)
- src/create_context_graph/fixtures/product-management.json (not served here)
- src/create_context_graph/fixtures/real-estate.json (not served here)
- src/create_context_graph/fixtures/retail-ecommerce.json (not served here)
- src/create_context_graph/fixtures/scientific-research.json (not served here)
- src/create_context_graph/fixtures/software-engineering.json (not served here)
- src/create_context_graph/fixtures/trip-planning.json (not served here)
- src/create_context_graph/fixtures/vacation-industry.json (not served here)
- src/create_context_graph/fixtures/wildlife-management.json (not served here)
- src/create_context_graph/generator.py (not served here)
- src/create_context_graph/ingest.py (not served here)
- src/create_context_graph/name_pools.py (not served here)
- src/create_context_graph/neo4j_validator.py (not served here)
- src/create_context_graph/ontology.py (not served here)
- src/create_context_graph/renderer.py (not served here)
- src/create_context_graph/templates/backend/agents/anthropic_tools/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/agents/claude_agent_sdk/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/agents/crewai/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/agents/google_adk/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/agents/langgraph/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/agents/openai_agents/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/agents/pydanticai/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/agents/strands/agent.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/__init__.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/claude_code_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/gcal_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/github_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/gmail_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/google_workspace_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/import_data.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/jira_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/linear_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/local_file_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/notion_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/salesforce_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/connectors/slack_connector.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/agent_stub.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/config.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/constants.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/context_graph_client.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/gds_client.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/generate_data.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/main.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/memory.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/memory_adapter.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/models.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/pyproject.toml.j2 (not served here)
- src/create_context_graph/templates/backend/shared/routes.py.j2 (not served here)
- src/create_context_graph/templates/backend/shared/vector_client.py.j2 (not served here)
- src/create_context_graph/templates/backend/tests/test_routes.py.j2 (not served here)
- src/create_context_graph/templates/base/Dockerfile.backend.j2 (not served here)
- src/create_context_graph/templates/base/Dockerfile.frontend.j2 (not served here)
- src/create_context_graph/templates/base/Makefile.j2 (not served here)
- src/create_context_graph/templates/base/README.md.j2 (not served here)
- src/create_context_graph/templates/base/docker-compose.prod.yml.j2 (not served here)
- src/create_context_graph/templates/base/docker-compose.yml.j2 (not served here)
- src/create_context_graph/templates/base/dockerignore.j2 (not served here)
- src/create_context_graph/templates/base/dot_env.j2 (not served here)
- src/create_context_graph/templates/base/dot_env_example.j2 (not served here)
- src/create_context_graph/templates/base/gitignore.j2 (not served here)
- src/create_context_graph/templates/base/mcp/README.md.j2 (not served here)
- src/create_context_graph/templates/base/mcp/claude_desktop_config.json.j2 (not served here)
- src/create_context_graph/templates/cypher/gds_projections.cypher.j2 (not served here)
- src/create_context_graph/templates/cypher/schema.cypher.j2 (not served here)
- src/create_context_graph/templates/frontend/app/globals.css.j2 (not served here)
- src/create_context_graph/templates/frontend/app/layout.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/app/page.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/components/ChatInterface.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/components/ContextGraphView.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/components/DecisionTracePanel.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/components/DocumentBrowser.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/components/ErrorBoundary.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/components/Provider.tsx.j2 (not served here)
- src/create_context_graph/templates/frontend/e2e/app.spec.ts.j2 (not served here)
- src/create_context_graph/templates/frontend/lib/config.ts.j2 (not served here)
- src/create_context_graph/templates/frontend/next.config.ts.j2 (not served here)
- src/create_context_graph/templates/frontend/package.json.j2 (not served here)
- src/create_context_graph/templates/frontend/playwright.config.ts.j2 (not served here)
- src/create_context_graph/templates/frontend/theme/index.ts.j2 (not served here)
- src/create_context_graph/templates/frontend/tsconfig.json.j2 (not served here)
- src/create_context_graph/wizard.py (not served here)
- tests/__init__.py (not served here)
- tests/conftest.py (not served here)
- tests/fixtures/local_file_vault/README.md (not served here)
- tests/fixtures/local_file_vault/companies/acme-corp.md (not served here)
- tests/fixtures/local_file_vault/companies/betawidgets-inc.md (not served here)
- tests/fixtures/local_file_vault/daily-notes/2026-05-08.md (not served here)
- tests/fixtures/local_file_vault/daily-notes/2026-05-09.md (not served here)
- tests/fixtures/local_file_vault/decisions/2026-q2-thesis-call.md (not served here)
- tests/fixtures/local_file_vault/external/acme-10q-2026q1.pdf (not served here)
- tests/fixtures/local_file_vault/external/sector-report-q1-2026.html (not served here)
- tests/fixtures/local_file_vault/meetings/2026-05-07-portfolio-review.md (not served here)
- tests/fixtures/local_file_vault/memos/acme-investment-memo.docx (not served here)
- tests/fixtures/local_file_vault/methodology/dcf-framework.md (not served here)
- tests/fixtures/local_file_vault/methodology/dcf-spec.adoc (not served here)
- tests/fixtures/local_file_vault/people/dana-liu.md (not served here)
- tests/fixtures/local_file_vault/people/marcus-reyes.md (not served here)
- tests/fixtures/local_file_vault/people/sarah-chen.md (not served here)
- tests/fixtures/local_file_vault/people/tariq-osei.md (not served here)
- tests/fixtures/local_file_vault/people/yuki-tanaka.md (not served here)
- tests/fixtures/local_file_vault_TESTING.md (not served here)
- tests/test_bolt_ingest_parity.py (not served here)
- tests/test_chat_import.py (not served here)
- tests/test_cli.py (not served here)
- tests/test_config.py (not served here)
- tests/test_connectors.py (not served here)
- tests/test_custom_domain.py (not served here)
- tests/test_doc_snippets.py (not served here)
- tests/test_fixtures.py (not served here)
- tests/test_frontend_logic.py (not served here)
- tests/test_generated_client_runtime.py (not served here)
- tests/test_generated_project.py (not served here)
- tests/test_generated_tests.py (not served here)
- tests/test_generator.py (not served here)
- tests/test_ingest_nams.py (not served here)
- tests/test_integration.py (not served here)
- tests/test_local_file_connector.py (not served here)
- tests/test_local_file_vault.py (not served here)
- tests/test_matrix.py (not served here)
- tests/test_memory_adapter.py (not served here)
- tests/test_nams_adapter.py (not served here)
- tests/test_nams_ingest_parity.py (not served here)
- tests/test_neo4j_validator.py (not served here)
- tests/test_ontology.py (not served here)
- tests/test_performance.py (not served here)
- tests/test_renderer.py (not served here)
- tests/test_routes_integration.py (not served here)
- tests/test_security.py (not served here)
- tests/test_wizard.py (not served here)
- uv.lock (not served here)
- vercel.json (not served here)
Advantages
- Rapidly scaffolds full-stack applications with domain-specific ontologies and agent tools in under 5 minutes. evidence: README.md
- Provides flexible memory backend options, supporting both hosted NAMS and self-hosted Neo4j. evidence: README.md
Limitations
- The NAMS hosted memory backend has a narrower write surface compared to self-hosted Neo4j, limiting some Cypher-based operations. evidence: README.md
- Requires specific API keys and environment variables depending on the chosen agent framework and memory provider. evidence: README.md
Security
Risk level: Low risk
This brain runs
Agent instructions that run or fetch something (28)
CLAUDE.md:Invoked via `uvx create-context-graph` or `npx create-context-graph`.CLAUDE.md:(2) every document/body ingest write failed (`role="document"` rejected — only user/assistant/system allowed — plus the conversation-404), fixed across all three NAMS ingest implementations (`run_nams_ingest`, scaffolded `import_data.py`, `make seed`'s `ingest_fixtures_nams`) with `role …[+63 chars]CLAUDE.md:the old loop swallowed the AttributeError and printed "0 removed") — `--reset-database` and `make reset` now honestly report that no delete API exists and point at the NAMS dashboard.CLAUDE.md:**NAMS domain ontology activation (new)**: NAMS pre-registers a server-side ontology for every bundled domain but auto-binds workspaces to `nams-default` until one is activated — generated apps now bind on `connect_memory()` (activate catalog match by domain id, or create-from-`backend …[+359 chars]CLAUDE.md:**Carry-forward from v0.13.1 (feedback-report triage):** `create-context-graph --dry-run` no longer demands a NAMS API key (the credential gate is now scoped to non-dry-run flows in `cli.py:392`).CLAUDE.md:**Carry-forward from v0.13.0 (v0.12.0 feedback-report fixes):** Fixed the bolt async/sync mismatch in the scaffolded `import_data.py` (`_ingest_via_bolt()` is `async def` and both call sites wrap with `asyncio.run`);CLAUDE.md:uv venv && uv pip install -e ".[dev]"CLAUDE.md:# Run testsCLAUDE.md:**Data seeding** (`make seed`): Loads all four data types into Neo4j — entities, relationships, documents (as `:Document` nodes with `:MENTIONS` links to entities), and decision traces (as `:DecisionTrace` → `:HAS_STEP` → `:TraceStep` chains).CLAUDE.md:As tools execute, the collector emits `tool_start` and `tool_end` events (with graph data).CLAUDE.md:CrewAI and Strands are synchronous frameworks that run in worker threads via `asyncio.to_thread()`.CLAUDE.md:When `--with-mcp` is passed (or selected in the wizard), the scaffold generates `mcp/claude_desktop_config.json` (pre-configured for the project's Neo4j instance), `mcp/README.md` (setup instructions), and a `make mcp-server` Makefile target.CLAUDE.md:python-docx (Word).CLAUDE.md:Connectors run at scaffold time AND are generated into the project with `make import` / `make import-and-seed` targets.CLAUDE.md:pytest tests/test_generated_tests.py # Scaffold + install + run generated project test suite for 4 frameworks (slow, 5)CLAUDE.md:Full-stack integration tests that scaffold a project, install dependencies, start the backend, and send chat prompts.CLAUDE.md:make smoke-test # Run 3 key framework tests (pydanticai, google-adk, strands)CLAUDE.md:# Or run directly with more control:CLAUDE.md:python scripts/e2e_smoke_test.py --domain healthcare --framework pydanticai --quickCLAUDE.md:python scripts/e2e_smoke_test.py --all-domains --framework claude-agent-sdk --quickCLAUDE.md:python scripts/e2e_smoke_test.py --domain gaming --framework openai-agents # full mode (all prompts)CLAUDE.md:| Target | Description | |--------|-------------| | `make test` | Fast unit tests (1,454 passing, no external deps) | | `make test-slow` | Full suite including matrix + perf + generated project + connector/functional tests (1,866 passing with connectors extra) | | `make test-matrix` | …[+533 chars]CLAUDE.md:Generate fixture data: run the CLI with `--demo-data` or use `generator.py` directlyCLAUDE.md:| Framework | Directory | Pattern | Streaming | |-----------|-----------|---------|-----------| | PydanticAI | `pydanticai/` | `@agent.tool` decorator + `RunContext[AgentDeps]` | Full (`agent.run_stream()`) | | Claude Agent SDK | `claude_agent_sdk/` | Dict-based TOOLS list + bounded ag …[+787 chars]CLAUDE.md:| Job | Trigger | Description | |-----|---------|-------------| | **test** | All pushes + PRs | Fast unit tests on Python 3.11 and 3.12 (`fail-fast: false` so one version's failure doesn't cancel the other) | | **lint** | All pushes + PRs | Ruff on `src/` and `tests/` (rule set pinned …[+444 chars]CLAUDE.md:**Every job installs from `uv.lock` via `uv sync --locked --extra ...` and runs commands with `uv run --no-sync`.** Never mix `uv pip install` with a bare `uv run` in CI: `uv run` does an implicit lockfile sync that downgrades locked base deps underneath freshly-installed latest extras …[+94 chars]CLAUDE.md:If `--locked` fails, run `uv lock` locally and commit the refreshed lockfile — dependency changes in `pyproject.toml` must ship with a matching `uv.lock`.CLAUDE.md:The Makefile test/lint targets use `uv run --extra dev ...` so local runs resolve from the lock the same way.
Install scripts (1)
Makefile(make install):uv venv && uv pip install -e ".[dev]"
- Low risk: network-instructions (CLAUDE.md:15)
- Low risk: network-instructions (Makefile:10)
- Low risk: scripts-present (scripts/e2e_smoke_test.py)
- Low risk: scripts-present (scripts/regenerate_fixtures.py)
Attribution and licence
- Created by
- neo4j-labs
- Declared authors
- William Lyon (declared in pyproject.toml)
- Publisher
- neo4j-labs (Official neo4j-labs project)
- Source
- neo4j-labs/create-context-graph · commit 926e3b3
- Licence
- Apache License 2.0 (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by neo4j-labs.
Install from source
334 of its files are not served here, so there is no ZIP. neo4j-labs/create-context-graph at 926e3b3