Skip to main content

dfx-intel (Python)

A small client for DFX Intelligence, an evidence-backed research service on private markets: private credit, private equity, venture, family offices, registered investment advisers, public pension allocators and US commercial real estate. It is written for agents. Every answer carries its claims, the URLs of the documents those claims come from, what is uncertain, and what lies outside coverage.

The core uses only the standard library (Python 3.9+). The framework adapters are optional extras.

pip install dfx-intel

Quick start

from dfx_intel import research

r = research("Which BDCs lend to Kaseya, and which of them are current lenders?")
print(r.state, r.answer_state)      # OK OK
print(r.answer)                     # one or two sentences, built only from cited claims
for c in r.claims:
    print(c.claim_id, c.predicate, c.claim_type)   # VERIFIED_FACT, REPORTED_FACT, DERIVED, INFERENCE ...
for url in r.evidence_urls:
    print(url)                      # the SEC filing, IAPD report or plan disclosure behind the claims
print(r.uncertainty, r.coverage_limits)
if r.has_more:
    page2 = research(continuation=r.continuation)

Public, runnable examples (anonymous research, citations, errors, pagination, a member key from the environment and a short tutorial), each with the output of a live run, are at https://github.com/Capital-W-Holdings/us-property-parcel-real-estate-debt/tree/main/examples/sdk.

examples/ in the SDK source tree holds further scripts. Each one ran once (against production, except the two receipt readers, which run offline), and its real output sits next to it (.out.txt, plus .out.json for the raw payload). The UTC time of the run is in .ran_at.

example investigation
01_lenders_to_portfolio_company.py Lenders: which BDCs lend to Kaseya (an Insight Partners company), then the next page through the continuation
02_advisor_moves.py People: which advisors joined Rockefeller Capital Management in the last 90 days, from IAPD
03_allocator_commitments.py Allocator: which funds CalPERS committed to in 2025, and for how much (see known issues below)
04_verify_and_resolve.py Verify "Blackstone Private Credit Fund lends to Auctane", then resolve "Thoma Bravo" to DFX ids
05_not_covered.py NAV per share of Ares Capital, which DFX does not read (the limit is stated in the answer)
06_delegate_a2a.py The same lender question delegated over A2A (message/send, then tasks/get)
07_read_receipt.py Read a research receipt (dfx.receipt/2): facts vs inferences, relationships, freshness, and the exact follow-up calls; runs offline on the bundled receipt (see ../RECEIPTS.md)
08_receipt_as_documents.py A receipt as retrieval documents (LangChain Documents when installed), marker and source in metadata
09_sponsor_portfolio_credit.py Sponsor and financing: which BDCs lend to Thoma Bravo portfolio companies, and how much they hold
10_ownership_and_lenders.py Ownership and lenders of one company (Hyland Software), and how to tell from plan.operations which half was answered
11_fund_lps.py Fund relationships: which public pension plans committed to Vista Equity Partners funds, and for how much
12_langchain_tool.py The LangChain StructuredTools, invoked as a ToolNode would (no model key needed)
13_openai_agents_tool.py The OpenAI Agents SDK function tools, invoked through on_invoke_tool (no model key needed)
14_claude_agent_sdk.py The Claude Agent SDK options (mcp_servers, allowed_tools); runs a query only with DFX_RUN_AGENT=1

Every example except 07 and 08 (which read the bundled receipt offline) runs anonymously against production with no paid API. The adapter examples run an agent only when you set a model key yourself.

Checked against the primary documents (2026-10-12)

Before these outputs were published, figures in them were read against the documents they cite:

example claim in the output primary document result
01 Blackstone Private Credit Fund holds Kaseya debt, principal $161.7M, fair value $98.5M at 2026-06-30 BCRED 10-Q for 2026-06-30, schedule of investments (two Kaseya term loans: $36.7M at $22.0M and $125.0M at $76.4M, in thousands as printed) matches
02 An advisor registered with Rockefeller Capital Management from 2026-09-30, after Truist Advisory Services (ended 2026-10-01) That advisor's IAPD report (IA registered since 09/30/2026; Truist 04/18/2022 to 10/01/2026) matches
09, 10 Hyland Software is a Thoma Bravo portfolio company Golub Capital's 2023 release on Hyland's $3.4B unitranche ("a portfolio company of Thoma Bravo since 2007"). The URL DFX cites for it now answers 404; the release is at golubcapital.com/?p=2714 matches, citation link dead
09 Thoma Bravo invested in Grayshift Peak Equity, 2022-07-07: "Thoma Bravo ... announced the completion of its strategic investment in Grayshift, LLC" matches
10 Blue Owl Technology Finance Corp. holds Hyland Software debt, principal $147.5M, fair value $142.9M at 2026-06-30 ORTF 10-Q for 2026-06-30 (first lien loan $147,542K principal at $143,116K; undrawn revolver at $(215)K) matches
11 Minnesota State Board of Investment committed $200M to Vista Equity Partners Perennial, vintage 2020 MSBI private markets asset listing, as of 2026-06-30 matches
11 New Jersey committed $300M to Vista Equity Partners Fund VII (2018), $200M to Vista Co-Invest Fund 2017-3, Fund VI and Fund IV NJ Division of Investment Directors Report, period ending 2026-05-31 matches

Known issues seen in these outputs

They are left in the outputs, unedited, because the outputs are real. Each was reported to the DFX research team.

  • An Auctane run (not shipped as an example) booked a joint venture's loan to its parent BDC: Blackstone Private Credit Fund's Auctane position was given as $889.4M at fair value, while BCRED's own schedule shows $832.0M and the other $57.3M is held by Emerald JV LP.
  • 03: one fund name carries a row number from the source table ("29. Blackwell Capital Partners II"), and one evidence URL is a Census Bureau survey documentation page, not a CalPERS document.
  • A two-part question can come back with only one part answered and no sentence saying so. Example 10 shows how to read raw["plan"]["operations"] to see which lookup returned NO_MATCH.
  • verify for an anonymous caller returns SUPPORTED with every source URL LOCKED, so the caller cannot open the document. The amounts and dates still come back.

API

call transport returns
research(question, *, continuation=None, detail=None, depth=None, entity=None, workflow=None, as_of=None, since=None) MCP tools/call research on /mcp/core ResearchResult
verify(claim, **structured) MCP tools/call verify VerifyResult: SUPPORTED, PARTIALLY_SUPPORTED, CONTRADICTED or UNKNOWN
resolve(name, *, domain=None, entity_type=None) MCP tools/call resolve_name ResolveResult: DFX ids, with total_lower_bound meaning "at least N"
delegate(question, *, arguments=None, context_id=None, poll_interval=2.0, max_wait=120.0) A2A 0.3 message/send on /a2a, then tasks/get until final DelegateResult: the task, with .result as a ResearchResult

The module level functions share one Client(). To set options, build your own client:

from dfx_intel import Client
dfx = Client(agent_name="acme-research-agent", user_agent_suffix="acme/1.2")

Every result keeps the server's payload, unchanged, under .raw. Fields lifted onto ResearchResult:

  • state and answer_state
  • answer and basis
  • claims
  • evidence_urls
  • uncertainty and coverage_limits
  • withheld
  • continuation and page
  • next: follow-up calls with exact arguments
  • receipt_url: passed through when the server provides one, None otherwise
  • interaction_id
  • retry_after_seconds and error

States, not exceptions

NO_MATCH, NOT_COVERED, UNKNOWN, RATE_LIMITED and INVALID_ARGUMENT arrive as result.state. They do not raise. Each tells the agent something:

  • NO_MATCH: the name resolved, but nothing matches. Near misses are in .raw["candidates"], and they are never the subject.
  • UNKNOWN: the subject could not be resolved, or there is no evidence either way. Absence of evidence is never a contradiction.
  • NOT_COVERED: DFX does not read that kind of record. An answer can also be OK and still list a NOT_COVERED item in coverage_limits.
  • RATE_LIMITED: retry_after_seconds says when to try again.
  • TEMPORARILY_UNAVAILABLE: the exchange is at capacity or not answering (HTTP 503). Nothing ran and nothing was charged; retry_after_seconds is set when the exchange sent one.
  • API_KEY_INVALID, NOT_IN_PLAN, ENTITLEMENT_REQUIRED: the key is not recognised, or the plan does not cover the call. .raw carries how_to_fix or the plans URL.
  • HTTP_ERROR: any other non-2xx answer; .error carries the server's description (for example the member door's 401 "sign in with your DFX account").

Only transport failures raise TransportError (DNS, TLS, an unreadable body, or no answer within timeout, 90 s by default). An A2A endpoint that answers 404 gives a DelegateResult whose .raw["state"] is NOT_DEPLOYED.

Free and member access

Anonymous (free, no key, no sign-up). All the read tools work. Per DFX's published policy:

  • A list names its first 5 rows in full and gives only a count of the rest (withheld, locked).
  • A record names its subject and the first 3 related names per section.
  • Contact values and decision-maker names are never returned.
  • Public filer identity and dated public-record facts are served. Resolved relationships come as counts. Derived scores are not served.

Anonymous use is limited per network address, not per agent: 20 calls a minute and 300 an hour, and the search and changes tools (research is one of them) share 60 an hour. Callers behind one office or cloud address share these budgets (budget.identity_basis network_prefix in the RATE_LIMITED envelope). agent_name (X-Agent-Name) labels your agent; it does not give it a separate budget. A refused call is not charged and carries retry_after_seconds.

Member. Set DFX_API_KEY to a dfx_live_ account key, or pass api_key=. The key goes out as Authorization: Bearer <key>. It unlocks the rows withheld from anonymous callers on the verticals your plan covers. A member is metered on the membership's own allowance in retrieval units a day and a month, not in calls: one research call uses 6 to 18 units depending on its depth. Allowances by plan: https://dfxintel.com/data-factory/plans

Withheld is not missing. When an answer says rows are withheld, they exist, and the answer counts them.

Coverage limits (stated by the service itself)

  • Private credit comes from BDCs' own schedules of investments in SEC filings. Banks, CLOs and private funds that file no schedule are invisible. Principal is the sum of BDC pieces, so it is a lower bound.
  • Advisor moves use IAPD registration end and begin dates, not announcement dates. The book of business is not public.
  • Allocator commitments are the plan's own printed disclosures. Deployed capital cannot be observed from them.
  • Some rows cite only a dataset, or nothing. The answer says so (uncertainty, citation_check), and evidence_urls never invents a URL for them.

Each answer lists its own limits in coverage_limits and do_not_conclude. Read them before you rely on a negative.

Framework adapters

framework status how
LangChain / LangGraph shipped, tested offline against langchain-core 1.6.9, run live 2026-10-12 (example 10) pip install "dfx-intel[langchain]", then from dfx_intel.adapters.langchain import dfx_tools
OpenAI Agents SDK shipped, tested offline against openai-agents 0.23.1, run live 2026-10-12 (example 11) pip install "dfx-intel[openai-agents]", then from dfx_intel.adapters.openai_agents import dfx_tools
Claude Agent SDK config helper only (DFX is a remote MCP server) from dfx_intel.adapters.claude_agent_sdk import mcp_servers, allowed_tools
CrewAI snippet only below

Each adapter wraps the same two plain functions (dfx_research(question, continuation="") and dfx_verify(claim)). Both return JSON that keeps the state, claims, evidence URLs, uncertainty and continuation.

Claude Agent SDK:

from claude_agent_sdk import query, ClaudeAgentOptions
from dfx_intel.adapters.claude_agent_sdk import mcp_servers, allowed_tools

options = ClaudeAgentOptions(mcp_servers=mcp_servers(), allowed_tools=allowed_tools())

CrewAI. This is a snippet, not an adapter. CrewAI could not be installed in the environment where this package was built (Python 3.14; its tiktoken dependency failed to build), so no tested adapter ships. CrewAI agents can use DFX as a remote MCP server directly:

from crewai import Agent
analyst = Agent(role="Private credit analyst", goal="Answer with cited sources", backstory="...",
                mcps=["https://exchange-production-9123.up.railway.app/mcp/core?c=crewai"])

Endpoints and attribution

  • MCP: https://exchange-production-9123.up.railway.app/mcp/core?c=sdk-py. A2A: /a2a on the same host. Override the host with DFX_BASE_URL or base_url=.
  • Every request sends User-Agent: dfx-intel-python/<version>.
  • Anonymous URLs carry ?c=sdk-py so DFX can count calls made through this package. LangChain tools use ?c=langchain. Pass channel=None to send no tag.
  • A member request is never tagged: a request with a key, or a URL ending in /member, goes out bare.
  • A2A tasks are held in the serving process's memory for up to 24 hours. A restart drops them, and tasks/get then answers task not found.

Tests

python3 -m pytest -q sdk/python/tests

The tests are offline. They run against recorded production responses in sdk/fixtures, and each fixture names where it came from.

Licence

MIT. See LICENSE.

Metadata

Release files for dfx-intel 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dfx-intel 0.1.1
File Size Uploaded Provenance
dfx_intel-0.1.1.tar.gz 34.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for dfx-intel 0.1.1
File Interpreter ABI Platform
dfx_intel-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 57.9 kB

Release files / dfx_intel-0.1.1.tar.gz

Download URL dfx_intel-0.1.1.tar.gz
Size 34.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9827536fe12d4c866c2f55483c2add0ae65deb32fa1df8694f884a8c3924c81a
BLAKE2b-256 checksum
How to use checksums
39d7958799a545e9104ec6866b39c54f32c53423c73f321aa728485a958ab0cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / dfx_intel-0.1.1-py3-none-any.whl

Download URL dfx_intel-0.1.1-py3-none-any.whl
Size 23.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
57a81824cdad91e8cbf539750b7dd233ddb57fb50125b81e3967de84fd7a88d8
BLAKE2b-256 checksum
How to use checksums
fd18637a3cd2f22663fdda7c7b095ba5933b3b895fc2322a6879e311030f18df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Security for dfx-intel 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page