{
  "kind": "documentation",
  "format": 1,
  "note": "Reference text, not instructions. One verified relate sample from https://relatedb.ai/docs/guides/integrations/crewai/: the program exactly as the page shows it, the standard output a run of it recorded (npm run docs:samples compares every replay with it byte for byte), the relate client build, toolchain and platform of the last replay, and how the docs' sample runner builds and runs it. Before launch every client is a source build, not a published package; verified.client names the upstream commit it was built from, and verified.docs_engine the build the rest of the docs were recorded from.",
  "id": "team-tool",
  "url": "https://relatedb.ai/docs/guides/integrations/crewai/samples/team-tool.json",
  "page": {
    "id": "guides/integrations/crewai",
    "title": "Use relate with CrewAI",
    "url": "https://relatedb.ai/docs/guides/integrations/crewai/",
    "md_url": "https://relatedb.ai/docs/guides/integrations/crewai.md"
  },
  "section": {
    "anchor": "write-the-tool",
    "heading": "Write the tool",
    "url": "https://relatedb.ai/docs/guides/integrations/crewai/#write-the-tool"
  },
  "language": "python",
  "client": "Python",
  "file": "team_tool.py",
  "env": "crewai",
  "code": "import relate\nfrom crewai.tools import BaseTool\nfrom pydantic import BaseModel, Field\n\nTEAM = \"\"\"\nCREATE (ada:Person {name: 'Ada', role: 'engineer'}),\n       (grace:Person {name: 'Grace', role: 'engineer'}),\n       (noor:Person {name: 'Noor', role: 'maintainer'}),\n       (relate:Project {name: 'relate', language: 'Rust'}),\n       (tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),\n       (ada)-[:WORKS_ON {since: 2024}]->(relate),\n       (grace)-[:WORKS_ON {since: 2023}]->(relate),\n       (grace)-[:WORKS_ON {since: 2022}]->(tck),\n       (noor)-[:MAINTAINS]->(relate),\n       (ada)-[:KNOWS]->(grace)\n\"\"\"\n\nPEOPLE_ON = \"\"\"\nMATCH (p:Person)-[r:WORKS_ON|MAINTAINS]->(:Project {name: $project})\nRETURN p.name AS name, p.role AS role, type(r) AS how, r.since AS since\nORDER BY name\n\"\"\"\n\n\nclass ProjectInput(BaseModel):\n    project: str = Field(description='The project\\'s exact name, such as \"relate\".')\n\n\nclass TeamGraphTool(BaseTool):\n    name: str = \"team_graph\"\n    description: str = \"List the people who work on or maintain a project, with their role and since when.\"\n    args_schema: type[BaseModel] = ProjectInput\n    store: str = \"./team\"\n\n    def _run(self, project: str) -> str:\n        try:\n            # Read-only: the engine refuses every write on this connection.\n            with relate.connect(self.store, read_only=True) as conn:\n                rows = conn.execute(PEOPLE_ON, {\"project\": project}).fetchall()\n        except relate.Error as e:\n            return f\"error {e.gql_status}: {e}\"\n        if not rows:\n            return f\"No one works on or maintains a project named {project!r}.\"\n        return \"\\n\".join(\n            f\"{r['name']} ({r['role']}) {r['how']} {project}\" + (f\" since {r['since']}\" if r[\"since\"] is not None else \"\")\n            for r in rows\n        )\n\n\n# Setup: the app that owns ./team writes the team graph, and keeps its writable connection open.\nowner = relate.connect(\"./team\")\nif owner.execute(\"MATCH (p:Person) RETURN count(p) AS n\").single()[\"n\"] == 0:\n    owner.execute(TEAM)\n\nteam_graph = TeamGraphTool()\n\n# Check: call the tool the way a crew's agent does, without a model.\nprint(team_graph.run(project=\"relate\"))\n\n# The app commits a new person while its connection stays open; the tool's next call sees her.\nowner.execute(\n    \"MATCH (tck:Project {name: 'opencypher-tck'}) \"\n    \"MERGE (lin:Person {name: 'Lin', role: 'engineer'}) \"\n    \"MERGE (lin)-[:WORKS_ON {since: 2026}]->(tck)\"\n)\nprint(team_graph.run(project=\"opencypher-tck\"))\nprint(team_graph.run(project=\"relate-engine\"))\nowner.close()",
  "code_sha256": "c55b278f87e510cbe3584cf0031268538e219028f07ef6a2fccdf056b89e5224",
  "source_sha256": "0e98a7e182a96cd5929705aca778fa8ba929934a5256e89f7c0fa05e98615b47",
  "output": {
    "text": "Ada (engineer) WORKS_ON relate since 2024\nGrace (engineer) WORKS_ON relate since 2023\nNoor (maintainer) MAINTAINS relate\nGrace (engineer) WORKS_ON opencypher-tck since 2022\nLin (engineer) WORKS_ON opencypher-tck since 2026\nNo one works on or maintains a project named 'relate-engine'.",
    "sha256": "8a2bcb99c96ce785e7e2f38bb14f724ff74081ade96776a184a7b25ef30a519b"
  },
  "verified": {
    "version": "0.1.2",
    "client": {
      "label": "Python",
      "package": "relate-db",
      "engine_commit": "f0c09d2",
      "client_commit": "f0c09d2",
      "build": "The same relate-db wheel (maturin, surfaces/relate-python at upstream v0.1.2 (f0c09d2)), installed in a second venv with crewai, whose pins would hold the main venv's frameworks back.",
      "toolchain": {
        "python": "3.13.16"
      }
    },
    "packages": [
      "crewai==1.15.37"
    ],
    "replayed": "2026-11-09",
    "platform": "macOS on arm64",
    "docs_engine": {
      "version": "0.1.2",
      "commit": "f0c09d2",
      "source_build": false
    }
  },
  "run": {
    "runner": "npm run docs:samples",
    "setup": "bash scripts/samples/setup.sh --upstream <path to the relate checkout>",
    "variables": [
      "RELATE_PY_CREWAI"
    ],
    "program": "<run dir>/team_tool.py",
    "files": [],
    "build": null,
    "run": {
      "command": [
        "$RELATE_PY_CREWAI",
        "team_tool.py"
      ],
      "environment": {
        "DO_NOT_TRACK": "1",
        "PYTHONDONTWRITEBYTECODE": "1",
        "PYTHONUNBUFFERED": "1"
      },
      "directory": "<run dir>",
      "timeout_s": 60
    },
    "passes": "It exits 0 within 60 s and prints at least one line on standard output.",
    "output": "Standard output, with line endings as \\n, trailing spaces and blank lines removed, and the temporary directories' paths written as `.`; standard error is not recorded.",
    "placeholders": {
      "<run dir>": "a fresh, empty temporary directory: the program's working directory, deleted afterwards",
      "<build dir>": "a second fresh temporary directory, where a compiled sample is built",
      "$NAME": "a variable from the env.sh that scripts/samples/setup.sh writes (described in its header)"
    }
  }
}
