You have a CrewAI agent to review documents, but the information it needs is not in a local folder, and not in a vector store.
It is in Alfresco.
The usual first attempt is to call the Alfresco REST API directly. Then the application starts to know about nodes, content, metadata, search syntax, site folders, authentication, maybe CMIS, and all the other details that are not really part of the agent task.
The example below shows a narrower integration:
CrewAI agent
-> LangChain tools
-> OpenDMA REST API
-> Alfresco adaptor
-> Alfresco
The CrewAI agent gets tools. OpenDMA handles the document-management side.
CrewAI provides an adapter for LangChain tools, so this example reuses the existing OpenDMA LangChain toolkit.
This article uses CrewAI’s Python/YAML project structure.
The example in this article is available as a runnable Python project in the CrewAI Alfresco–LangChain Sample Repository. You can clone the repository and follow along with the examples below.
Demo scenario
Assume an Alfresco site with title Project Apollo and short name project-apollo:
Project Apollo
Contracts/
Supplier Agreement.pdf
Service Agreement.pdf
Reports/
Status Report September.docx
Status Report October.docx
Risks/
Risk Register.xlsx
The user asks:
Review the Project Apollo documents and identify the three most
important project risks. Cite the documents supporting each finding.
The important part is what does not happen. We do not first ingest the complete site into a local vector database. The documents remain in Alfresco. The CrewAI agent searches and reads them through tools.
The article assumes that you already have:
- an Alfresco deployment;
- an OpenDMA REST endpoint for Alfresco, for example
http://localhost:7070/opendma/alf; - credentials that can access the
Project Apollosite.
The setup of the OpenDMA endpoint is separate from this article. Instructions are included in the README of the repository containing the sample code.
Install dependencies
Install CrewAI and the OpenDMA LangChain integration:
pip install crewai langchain-opendma
pip install "langchain-opendma[docling]"
The second line installs the optional Docling content handler dependencies. The toolkit uses a content handler when the agent reads binary documents such as PDF, DOCX or XLSX and needs text chunks.
Create Alfresco tools
langchain-opendma provides an AlfrescoToolkit. It creates LangChain tools for repository operations such as listing Alfresco sites, searching documents, reading metadata and reading text.
The important code is just the toolkit setup:
from langchain_opendma import AlfrescoToolkit
from langchain_opendma.content_handlers import DoclingLoaderContentHandler
from crewai.tools.base_tool import Tool
toolkit = AlfrescoToolkit(
endpoint="http://localhost:7070/opendma/alf",
username="admin",
password="admin",
repository_id="Alfresco",
content_handlers=[DoclingLoaderContentHandler()],
)
alfresco_tools = [
Tool.from_langchain(tool)
for tool in toolkit.get_tools()
]
The endpoint and credentials are fixed when the toolkit is created. The agent does not receive credentials as tool input.
For Alfresco, the relevant tools are:
-
alfresco_list_sites: list Alfresco sites with short name, title, description and root folder ID; -
opendma_search: search Alfresco documents through OpenDMA; -
opendma_list_children: list the folders and documents within a folder; -
opendma_get_metadata: inspect metadata for one repository object; -
opendma_read_text: read transformed text chunks from a document.
That is already the main integration. Alfresco has become a set of tools an agent can use.
Configure the agents
The researcher is the only agent that needs repository access. Its job is to find evidence and keep source references.
The key CrewAI line is tools=alfresco_tools:
from crewai import Agent
researcher = Agent(
role="Enterprise Content Researcher",
goal=(
"Find authoritative documents in Alfresco that are relevant "
"to the requested project question."
),
backstory=(
"You search Alfresco through OpenDMA tools. You keep document "
"names and object IDs with every factual claim."
),
tools=alfresco_tools,
verbose=True,
)
analyst = Agent(
role="Project Risk Analyst",
goal="Rank project risks using only the evidence found in Alfresco.",
backstory=(
"You turn repository evidence into concise project risk briefings. "
"Every risk must cite the supporting Alfresco documents."
),
verbose=True,
)
The analyst does not need Alfresco tools. It receives the research result as task context.
In the sample repository these role, goal and backstory values can live in config/agents.yaml. The OpenDMA tools still have to be created in Python and attached to the researcher agent.
Define the tasks
The first task tells the researcher how to use the repository tools. It should also tell it to keep document IDs, not just prose summaries.
from crewai import Task
research_task = Task(
description="""
Search the Alfresco site "Project Apollo" (short name: project-apollo).
Find evidence of significant project risks in contracts,
status reports and risk documents.
Use alfresco_list_sites to identify the site and its root folder.
Use opendma_search to find candidate documents.
Use opendma_get_metadata to inspect promising results.
Use opendma_read_text only for documents that are likely to contain
supporting evidence.
When opendma_read_text returns has_more, continue with the returned
chunk_continuation_token if more text is needed.
Keep every relevant document name and object ID with the evidence.
Look for corroborating evidence in other repository documents when available.
""",
expected_output=(
"A list of evidence-backed findings with document names, object IDs, "
"and short supporting evidence."
),
agent=researcher,
)
analysis_task = Task(
description="""
Using the research findings, identify the three most important project risks.
Explain each risk briefly and cite the Alfresco documents that support it.
""",
expected_output="A concise risk briefing with three ranked risks and citations.",
agent=analyst,
context=[research_task],
)
Finally, run the crew sequentially:
from crewai import Crew, Process
crew = Crew(
agents=[researcher, analyst],
tasks=[research_task, analysis_task],
process=Process.sequential,
verbose=True,
)
result = crew.kickoff()
print(result)
What the agent does at runtime
The verbose trace is the interesting part of this demo. A good run should look roughly like this:
Repository Researcher:
I need the Project Apollo site and its root folder.
alfresco_list_sites
Found:
- project-apollo: Project Apollo [node:0f7...]
Repository Researcher:
Search for likely risk material in the project site.
opendma_search
full_text="delay schedule risk supplier"
in_folder="node:0f7..."
include_subfolder_in_folder=true
Found:
- Status Report October.docx [node:4aa...]
- Supplier Agreement.pdf [node:a13...]
- Risk Register.xlsx [node:c91...]
Repository Researcher:
The October status report mentions a supplier delay.
I should inspect the supplier agreement and the risk register.
opendma_read_text
object_id="node:a13..."
opendma_read_text
object_id="node:c91..."
The execution tree of a run might look like this:
This is different from asking a vector store for chunks similar to project risk.
The agent is using Alfresco as a working information system:
- discover the relevant site;
- search inside the site;
- inspect search results;
- read selected documents;
- follow leads from one document to another;
- keep document IDs with the evidence.
That is the reason to use tools here rather than only a retriever. Repository structure and metadata matter. The document name, object ID, path, site and checked-out state may be as important as the extracted text.
Example Result
One run produced the following abbreviated briefing. Alfresco object IDs will differ between repositories.
### 1. Production hardware delay
The six-week hardware delay blocks the production cutover and is rated
high severity and high probability.
Sources:
- `Risk Register.xlsx` — `node:...`
- `Status Report October.docx` — `node:...`
### 2. Cutover support unavailable
A changed weekend cutover requires at least ten business days' notice
to secure support.
Sources:
- `Risk Register.xlsx` — `node:...`
- `Status Report October.docx` — `node:...`
### 3. Retention-rule sign-off delayed
Production migration cannot be approved until business owners complete
the retention-rule sign-off.
Sources:
- `Risk Register.xlsx` — `node:...`
- `Status Report September.docx` — `node:...
The exact searches, tool calls, and wording vary by model and run. The important result is that the findings retain their Alfresco document names and object IDs.
Why not ingest the site first?
There are cases where an indexing pipeline and a vector store are the right design. The OpenDMA LangChain Integration has document loaders for that as well.
This example deliberately does not start there.
In an enterprise Alfresco repository, copying content into a second knowledge base creates a new system that must be kept current. Documents change. Permissions change. Site membership changes. A status report that was readable yesterday might not be readable tomorrow for the same user.
With the OpenDMA toolkit, the CrewAI agent can search Alfresco and read selected documents when it needs them. That keeps Alfresco in the active path instead of treating it only as an ingestion source.
Why OpenDMA instead of calling Alfresco directly?
You could call the Alfresco REST API directly and work with nodes, content, metadata and search endpoints yourself. You could also look at CMIS for some repository operations.
That is fine for a small script.
Calling Alfresco directly from a CrewAI application couples the agent code to Alfresco-specific APIs. The researcher task should not care whether content is stored in Alfresco, Documentum, FileNet P8, OnBase, SharePoint or CMOD. It should care that it can search, inspect metadata, read a document and cite the source.
OpenDMA moves the product-specific API work behind an adaptor. The CrewAI application depends on repository tools exposed through OpenDMA. The OpenDMA framework in between allows to inject capabilities such as auditing, token forwarding, identity correlation, SIEM, RBAC, and more between Alfresco and your crew of agents.
This does not make every prompt and every repository structure magically portable. Site names, folder layouts, metadata models and search behavior still matter. But it changes where the product-specific code lives.
For a CrewAI developer, the useful part is concrete:
find the site
search the repository
inspect metadata
read the document
cite the source
Those are the operations the agent needs. OpenDMA provides them without making the CrewAI application become an Alfresco REST API client.
Further reading
- Runnable sample project: https://github.com/xaldon/opendma-demo-alfresco-crewai-langchain
- OpenDMA: https://opendma.org/
- ECI Server: https://xaldon.com/products/eci-server
- LangChain OpenDMA integration: https://github.com/OpenDMA/langchain-opendma
- Tutorials: https://github.com/OpenDMA/langchain-opendma/tree/main/docs/tutorials
- Toolkit documentation: https://github.com/OpenDMA/langchain-opendma/blob/main/docs/Toolkit.md
- Connecting LangChain to Alfresco Without Writing Another REST Loader

Top comments (0)