Skip to content

001 cgc plugin extension#1

Open
ductiletoaster wants to merge 7 commits intomainfrom
001-cgc-plugin-extension
Open

001 cgc plugin extension#1
ductiletoaster wants to merge 7 commits intomainfrom
001-cgc-plugin-extension

Conversation

@ductiletoaster
Copy link
Member

No description provided.

ductiletoaster and others added 7 commits March 14, 2026 19:50
…xtension)

Implements the full plugin extension system allowing third-party packages to
contribute CLI commands and MCP tools to CGC via Python entry points.

Core infrastructure:
- PluginRegistry: discovers cgc_cli_plugins/cgc_mcp_plugins entry-point groups,
  validates PLUGIN_METADATA, enforces version constraints, isolates broken plugins
- CLI integration: plugin commands attached to Typer app at import time; `cgc plugin list`
- MCP server integration: plugin tools merged into tools dict; handlers routed at call time

Plugins implemented:
- cgc-plugin-stub: minimal reference fixture for testing and authoring examples
- cgc-plugin-otel: gRPC OTLP receiver, Neo4j writer (Service/Trace/Span nodes,
  CORRELATES_TO links to static Method nodes), MCP query tools
- cgc-plugin-xdebug: DBGp TCP listener, call-stack parser, dedup writer
  (StackFrame nodes, CALLED_BY chains, RESOLVES_TO Method links), dev-only
- cgc-plugin-memory: MCP knowledge store (Memory/Observation nodes, DESCRIBES
  edges to Class/Method, FULLTEXT search, undocumented code queries)

CI/CD and deployment:
- GitHub Actions: plugin-publish.yml (matrix build/smoke-test/push via services.json),
  test-plugins.yml (PR plugin unit+integration tests)
- Docker: docker-compose.plugin-stack.yml (self-contained full stack with Neo4j
  healthcheck + init.cypher), plugin/dev overlays, all plugin Dockerfiles
- Kubernetes: otel-processor and memory plugin Deployment+Service manifests
- Fixed docker-compose.template.yml: neo4j healthcheck was missing (broke all
  overlay depends_on: service_healthy conditions), init.cypher now mounted

Tests (74 passing, 17 skipped pending plugin installs):
- Unit: PluginRegistry, OTEL span processor, Xdebug DBGp parser
- Integration: OTEL neo4j_writer, memory MCP handlers, plugin load isolation
- E2E: full plugin lifecycle, broken plugin isolation, MCP server routing

Documentation:
- docs/plugins/authoring-guide.md: step-by-step plugin authoring with examples
- docs/plugins/cross-layer-queries.md: 5 canonical cross-layer Cypher queries (SC-005)
- docs/plugins/manual-testing.md: Docker and Python testing paths, per-plugin
  verification sequences, troubleshooting table
- docs/plugins/examples/send_test_span.py: synthetic OTLP span sender for OTEL testing
- .env.example: documented all plugin environment variables
- CLAUDE.md: updated with plugin directories, entry-point groups, test commands

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CI/CD workflow fixes:
- e2e-tests.yml: add FalkorDB service container with health check, bump
  checkout@v3->v4 and setup-python@v4->v5, add cache: pip, expose
  FALKORDB_HOST/FALKORDB_PORT/DATABASE_TYPE env vars for test runner
- macos.yml: replace || true shell suppression with continue-on-error: true
  on Install system deps, Run index, and Try find steps
- test-plugins.yml: remove silent pip fallback from core install step so
  broken installs fail fast instead of silently proceeding with partial deps
- test.yml: add cache: pip to setup-python step

Application fixes (from python-pro):
- cgc.spec: PyInstaller frozen binary fixes
- tests/integration/plugin/test_otel_integration.py: asyncio fix
- tests/integration/plugin/test_memory_integration.py: importorskip guards
- tests/unit/plugin/test_otel_processor.py: importorskip guards
- tests/unit/plugin/test_xdebug_parser.py: importorskip guards
- plugins/cgc-plugin-{stub,otel,xdebug,memory}/README.md: plugin READMEs
- pyinstaller_hooks/: PyInstaller runtime hooks for plugin discovery

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…39+ compatibility

falkordblite requires glibc 2.39+, which is not available in the
manylinux2014_x86_64 image (glibc 2.17). Switch the Linux PyInstaller
docker build to quay.io/pypa/manylinux_2_39_x86_64.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s to __init__.py

All four plugin pyproject.toml files declared entry points with a
module:attribute suffix (e.g. cgc_plugin_stub.cli:get_plugin_commands),
causing ep.load() to return a function rather than the module. The
PluginRegistry calls ep.load() and reads PLUGIN_METADATA,
get_plugin_commands, get_mcp_tools, and get_mcp_handlers off the
returned object as module attributes — so loading always failed.

Fix: remove the colon-attribute suffix so each entry point resolves to
the package module (e.g. cgc_plugin_stub). Add re-exports of
get_plugin_commands, get_mcp_tools, and get_mcp_handlers from the
cli/mcp_tools submodules into each plugin's __init__.py so the registry
finds them on the loaded module.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dblite glibc 2.39 requirement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r Linux frozen binary

The Linux manylinux_2_39_x86_64 falkordblite wheel (produced by auditwheel)
installs vendored shared libraries into a `falkordblite.libs/` directory
(libcrypto, libssl, libgomp) that is not a Python package.  collect_all() and
collect_dynamic_libs() only walk the importable top-level packages listed in
top_level.txt ('dummy', 'redislite') and therefore silently miss falkordblite.libs/,
causing runtime linker failures inside the PyInstaller one-file executable.

Changes:
- Add explicit search_paths scan for falkordblite.libs/*.so* and register each
  file as a binary with destination 'falkordblite.libs'
- Collect dummy.cpython-*.so (auditwheel sentinel extension) from site-packages
  roots and register it at the bundle root
- Add 'dummy' to hidden_imports (non-Windows) to cover the importable top-level
  package declared in falkordblite's top_level.txt

pyproject.toml dependency marker (sys_platform != 'win32' and python_version >= '3.12')
is correct — no change needed there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant