# CrewAI

> Give a CrewAI crew a memory of each of your users, with what is known in the agent's backstory, or a recall tool the agent calls.

Give a CrewAI crew a memory of each of your users. What is known goes into the agent's backstory as a
kickoff input, or the agent looks it up with a tool bound to the user; either way, the crew's answer is
saved with the question after the kickoff.

## Install

```bash
pip install "crewai[anthropic]" geniffy
```

```bash
uv add "crewai[anthropic]" geniffy
```

Set `ANTHROPIC_API_KEY`, and `GENIFFY_API_KEY` from **API keys** in the Geniffy app. Any LLM CrewAI supports
works the same way.

## Remember each user

```python
from crewai import Agent, Crew, Task
from geniffy import Geniffy

geniffy = Geniffy()                      # reads GENIFFY_API_KEY


def assistant_crew() -> Crew:
    assistant = Agent(
        role="Assistant",
        goal="Answer the user's question",
        backstory="You help one person. What is known about them:\n"
                  "<memory>\n{memory}\n</memory>",
        llm="anthropic/claude-opus-5-5",
    )
    answer = Task(description="{question}", expected_output="A short, direct answer.",
                  agent=assistant)
    return Crew(agents=[assistant], tasks=[answer])


def chat(user_id: str, message: str) -> str:
    mem = geniffy.space(f"user_{user_id}")
    inputs = {"question": message, "memory": mem.context(message)}
    reply = assistant_crew().kickoff(inputs=inputs).raw
    mem.memories.add(messages=[{"role": "user", "content": message},
                               {"role": "assistant", "content": reply}])
    return reply
```

The agent sees what is known about this user, each line with where it came from. When nothing is known, the
block says so in one sentence, so the agent says it doesn't know instead of guessing. The crew is built for
each request, so two users never share one.

## Let the agent look things up

To let the agent decide when to look something up, give it a `recall` tool bound to the user. The model
never sees or chooses whose memory it reads.

```python
from crewai import Agent, Crew, Task
from crewai.tools import tool
from geniffy import Geniffy

geniffy = Geniffy()


def assistant_crew(user_id: str) -> Crew:
    mem = geniffy.space(f"user_{user_id}")

    @tool("recall")
    def recall(query: str) -> str:
        """Look up what is known about the user, with where it came from."""
        return mem.context(query)

    assistant = Agent(
        role="Assistant",
        goal="Answer the user's question",
        backstory="You help one person. Use recall before answering anything "
                  "that depends on what they said before.",
        tools=[recall],
        llm="anthropic/claude-opus-5-5",
    )
    answer = Task(description="{question}", expected_output="A short, direct answer.",
                  agent=assistant)
    return Crew(agents=[assistant], tasks=[answer])


def chat(user_id: str, message: str) -> str:
    reply = assistant_crew(user_id).kickoff(inputs={"question": message}).raw
    geniffy.space(f"user_{user_id}").memories.add(messages=[
        {"role": "user", "content": message},
        {"role": "assistant", "content": reply},
    ])
    return reply
```

CrewAI's own memory can stay off: it runs a model over each task to extract its own records, and Geniffy
already keeps what each user said, with where it came from.

Source: https://docs.geniffy.com/integrations/crewai
