DEV Community

Shubham Vernekar
Shubham Vernekar

Posted on

Stop AI Agents from Hallucinating Infrastructure: Building a Docker Compose Connector for Cognee

Autonomous AI DevOps and coding agents such as Claude Code, Devin, Cursor, and GitHub Copilot are increasingly trusted to troubleshoot deployment failures, configure CI/CD pipelines, and manage local multi-container development environments.

Yet, when developers ask an agent to "write an end-to-end test script" or "debug the backend network connection", they can encounter a common problem: container topology hallucination.

For example:

  • Hallucinating service hostnames: Calling localhost:5432 instead of the internal network alias db:5432.
  • Port confusion: Guessing incorrect host-to-container port mappings, such as assuming Redis is exposed on 6380 when the Compose file maps 6379:6379.
  • Missing volume mounts: Assuming persistent file paths that do not match the configured mounts.
  • Dependency blind spots: Missing depends_on relationships or health-check conditions such as service_healthy.

Why Does This Happen?

Large language models (LLMs) generate responses based on learned patterns and the context available to them. Without reliable access to an application's actual infrastructure configuration, they may generate plausible-looking but incorrect commands and deployment scripts.

In containerized development, compose.yaml or docker-compose.yml defines services, networks, volumes, port mappings, and environment configuration.

What if AI agents could retrieve this infrastructure information instead of guessing?

As part of Mergetober, I worked on a Docker Compose data-source connector for Cognee, intended to make container configuration available through a structured knowledge graph and retrieval pipeline.

In this article, I'll explain why infrastructure context matters, outline the connector architecture, and demonstrate the intended workflow for ingesting Docker Compose configuration into Cognee.


1. Why Docker Compose Topology Matters

In a multi-container application, services communicate through configured networks, expose ports, mount volumes, and depend on other services.

A typical Docker Compose file defines several important components:

  • Services and images: Container images such as postgres:16-alpine and redis:7, along with build contexts and Dockerfiles.
  • Port bindings: Host-to-container mappings such as "8080:80" and "5432:5432".
  • Service dependencies: depends_on relationships and conditions such as service_healthy.
  • Environment variables: Connection strings, credentials, and service URLs.
  • Volumes and networks: Named volumes, bind mounts, and custom networks such as app-network.

When an AI DevOps agent attempts to run migrations, seed a database, write integration tests, or debug network connectivity without this context, it may make incorrect assumptions.

Pasting an entire 500-line Compose file into every prompt is one possible workaround, but it can consume context-window space and make relevant configuration harder to find.

A better approach is to ingest, structure, index, and retrieve infrastructure topology on demand.


2. Introducing Cognee: Infrastructure Memory for AI Agents

Cognee is an open-source framework for building AI memory systems using structured knowledge and retrieval.

The idea behind combining Docker Compose with Cognee is to make infrastructure configuration easier for AI agents to retrieve when needed:

  • Service entities: Represent services and their configuration as searchable information.
  • Dependency relationships: Preserve relationships between services where supported by the ingestion pipeline.
  • Semantic retrieval: Let developers ask natural-language questions about ports, volumes, networks, and dependencies.
  • Grounded DevOps workflows: Provide configuration context before an agent generates commands, tests, or deployment scripts.

For example, a developer could ask:

What services depend on PostgreSQL, which ports are published, and what health-check conditions are configured?

A retrieval system can provide relevant Compose configuration as context for the agent's response. The quality of the result depends on how completely the configuration is parsed, represented, and retrieved.


3. Architectural Overview: The Docker Compose Connector

The intended data flow looks like this:

docker-compose.yml / compose.yaml
              |
              v
   Docker Compose Connector
              |
              v
Parse Services, Ports, Volumes, Networks and Dependencies
              |
              v
       Cognee Ingestion
              |
              v
Knowledge Graph + Vector Retrieval
              |
              v
       AI DevOps Agent
              |
              v
Infrastructure-Grounded Commands
Enter fullscreen mode Exit fullscreen mode

3.1. Stable Service Identifiers

A connector can assign stable identifiers to individual services:

docker_compose:service:{service_name}
Enter fullscreen mode Exit fullscreen mode

Stable identifiers help distinguish services across repeated imports. Whether they prevent duplicate nodes depends on how the connector and the ingestion pipeline handle entity identity.

3.2. Full-Snapshot Synchronization

Infrastructure configurations evolve as services are added, removed, or modified.

A snapshot-based synchronization strategy can help keep indexed infrastructure information aligned with the current Compose file. However, a setting such as write_disposition="replace" only provides the expected replacement behavior if the connector and the underlying ingestion pipeline explicitly support it.

Removed services must be handled by the synchronization process; simply ingesting an updated file does not necessarily delete stale entities from existing memory.

3.3. Rich, Agent-Friendly Service Representations

A connector can represent each service in a structured, human-readable format:

Service: api
Image: my-org/api:v1.2.0
Ports:
  - "8000:8000"
Environment:
  - DATABASE_URL: postgres://<user>:<password>@db:5432/app
Depends On:
  - db:
      condition: service_healthy
  - cache
Volumes:
  - ./logs:/var/log/api
Enter fullscreen mode Exit fullscreen mode

This is an illustrative representation of a service, not a complete Docker Compose file. In a real implementation, sensitive environment values should be redacted or excluded before configuration is stored or exposed to an AI agent.


4. Step-by-Step: Ingesting Docker Compose into Cognee

Step 1: Install Dependencies

The intended installation command is:

pip install cognee cognee-community-connector-docker-compose
Enter fullscreen mode Exit fullscreen mode

Confirm that the connector package is published and that its installation instructions match the implementation you are using.

Step 2: Prepare Your Directory

Locate your Docker Compose configuration and create a Python script for ingestion:

infrastructure-project/
├── docker-compose.yml
└── ingest_topology.py
Enter fullscreen mode Exit fullscreen mode

Step 3: Ingest and Query Infrastructure Memory

The following example illustrates the intended workflow. Verify the connector's actual import path, function signature, and Cognee API against the repository before running it.

import asyncio
import cognee

from cognee_community_connector_docker_compose import (
    docker_compose_source,
)


async def main():
    # Step 1: Load the Docker Compose configuration
    print("Loading Docker Compose configuration...")

    source = docker_compose_source(
        compose_path="./docker-compose.yml"
    )

    # Step 2: Ingest the configuration into Cognee
    await cognee.remember(
        source,
        dataset_name="infrastructure_topology",
    )

    # Step 3: Build the knowledge representation
    print("Processing infrastructure knowledge...")

    await cognee.cognify(
        dataset_name="infrastructure_topology",
    )

    # Step 4: Search infrastructure memory
    print("Searching container architecture...")

    results = await cognee.search(
        "What services depend on PostgreSQL, and which ports are published?",
        dataset_name="infrastructure_topology",
    )

    for result in results:
        print(result)


if __name__ == "__main__":
    asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

This example demonstrates the intended sequence:

  1. Load the Compose configuration through the connector.
  2. Submit the source to Cognee.
  3. Process the ingested information into a searchable representation.
  4. Query the resulting infrastructure context.

The exact behavior depends on the connector implementation and the Cognee version being used.


5. Result: More Reliable, Topology-Grounded DevOps Workflows

With infrastructure-aware retrieval, an agent can consult the relevant configuration before recommending commands.

For example, a Compose file might define a service named db and an application service named api. Depending on the configuration and the commands supported by the application, the resulting workflow might include:

docker compose exec db pg_isready -U postgres
docker compose run --rm api python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

These commands are examples, not universal solutions. The service names, database user, executable, and migration command must match the actual project.

The objective is to help AI agents make better-informed decisions about service names, ports, dependencies, and execution contexts.

Retrieval can reduce configuration-related guesswork, but it does not guarantee hallucination-free output. Agents should still validate commands against the current configuration and test them in an appropriate environment before using them in production.


6. Open-Source Pull Request and References


Top comments (0)