An SDK for consuming Agent Fabric capabilities — governed model and tool access — from your own agent framework, in your own IDE, without adopting Mule.
Project status — alpha. This is an early release (
Development Status :: 3 - Alpha). The LLM data plane is live-verified; most other surfaces are verification-gated (see What's verified below). Install it from PyPI withpip install donkey-kit— see Install. Unofficial: an independent project, not affiliated with or endorsed by Salesforce or MuleSoft.
Already integrated the pre-rebrand SDK? The move to Donkey Development Kit is a clean break — no import shims, env fallbacks, or OpenTelemetry dual-emit. The migration guide maps every renamed import, class, CLI, config key, and environment variable, and calls out the breaking OpenTelemetry attribute-namespace change.
"Agent Fabric" is a MuleSoft (Salesforce) product name, not a generic term.
MuleSoft,Anypoint,Omni Gateway, andAgent Fabricare Salesforce trademarks.Maintainer & support. This is an independent, community-maintained project, published under the org-scoped
Donkey-Development-Kitname — it is not affiliated with, endorsed by, or supported by Salesforce or MuleSoft. It is provided as-is, without warranty of any kind; the maintainers triage issues and pull requests on a best-effort basis, with no SLA. Because it ships under a distinct, org-scoped name, only the descriptive form ("an SDK for MuleSoft Agent Fabric") appears in prose — the package does not represent itself as a first-party, official-status SDK.Licensed under Apache-2.0. See
docs/unsupported-boundary.mdfor exactly which platform APIs this SDK calls and their support classification.Security. Report vulnerabilities privately, never in a public issue. See
SECURITY.mdfor supported versions and how to report.Python versions. CPython 3.10–3.12, each tested in CI; a version is dropped in the first minor release after its end of life. See
docs/python-support.md.
Two audiences, two doc sets:
- Use the SDK → the documentation site: https://docs.donkey-kit.dev/. Install and configure, per-framework model access, the governed error taxonomy, and what to trust today — everything you need to point your agent at a governed proxy.
- See it run → runnable demos live in the companion repo donkey-development-kit-demos: the framework-free client, native framework objects, the governed error taxonomy, and the screen-recording scripts.
- Understand or contribute to the repo:
ARCHITECTURE.md— how the SDK is built: the layered stack, the framework-free core, verification discipline, the error taxonomy, and framework tiering.CONTRIBUTING.md— how to work in the repo: the branch/PR/release workflow, the testing strategy, coding conventions, and the docs-sync rule.docs/verified-apis.md— the verification ledger: the single source of truth for what is confirmed against a real sandbox and what is still blocked.
pip install "donkey-kit[llm,langgraph]" # base + raw client + one frameworkTo work on the SDK itself, install from source with the contributor tooling
(the dev dependency group needs pip 25.1 or later):
git clone https://github.com/Donkey-Development-Kit/donkey-development-kit.git
cd donkey-development-kit/python
pip install -e ".[llm,cli]" --group devExtras are one per framework (langgraph, adk, strands, agent_framework,
openai-agents, anthropic, crewai, llamaindex) plus otel, cli, local,
test (the conformance pytest plugin —
pytest --donkey-conformance --donkey-agent=my_app.agent:build), and all. all is
everything a user runs that installs together — llm, langgraph, otel, cli,
local — with no test runner, so add test for the conformance plugin:
donkey-kit[all,test]. It leaves out the seven other framework extras, whose current
upstream releases cannot all be installed together. Add the one framework you use:
donkey-kit[all,crewai].
Configuration and first-agent walkthroughs live on the
documentation site.
The roster is deliberately one deep, seven shallow (BG §1.8): one adapter
held to the full conformance bar, the rest supported through the three-line
connection_kwargs() escape hatch. Every framework below returns its framework's
own native object — never a wrapper.
| Tier | Frameworks | Status (docs/verified-apis.md §8) |
|---|---|---|
| Deep | The raw client (donkey.llm.client()) and LangGraph |
Conformance-tested against the simulator in CI. LangGraph's ChatOpenAI constructor is signature-confirmed offline; it has had no live round-trip. |
Supported via connection_kwargs() |
Google ADK, Strands, Microsoft Agent Framework, OpenAI Agents SDK, Anthropic SDK, CrewAI, LlamaIndex | Signature-confirmed offline: each factory builds its native object against the installed framework (scripts/verify_frameworks.py), with no live round-trip and no conformance run. The exception is ADK's gemini(), which is live-verified through a Format=Gemini proxy. |
connection_kwargs() works for all eight; a second deep adapter is promoted from
demand evidence, one at a time (#223/#244) — never guessed up front. See the
framework pages
for each.
The LLM data plane — governed model access through the Omni Gateway proxy —
is live-verified against a real Anypoint sandbox. The framework-free client and
the framework adapters are wired to that contract, but the adapters themselves
are not live-verified: the raw client and LangGraph are conformance-tested
against the simulator, ADK's gemini() is live-verified, and every other
adapter constructor is signature-confirmed offline (see
Framework support).
Everything still gated raises NotImplementedError("blocked on verification: …")
rather than guessing at an unverified endpoint, header, or class name — that
currently includes Exchange→MCP tool discovery and Exchange publication; their
types live in donkey_kit.experimental, outside the stable namespace. The SDK
does not ship a provisioning control plane (ADR 0008 in docs/adr/). The adapters build their framework's native object directly; they
refuse only when the installed framework version lacks the class or field the
adapter depends on.
The discipline behind this is documented in
ARCHITECTURE.md → Verification discipline;
the row-by-row worklist is docs/verified-apis.md.
The conformance plugin
holds the SDK to the same bar it asks of your agent. Where a framework
legitimately cannot satisfy a scenario, the reason is asserted in code
(KNOWN_LIMITATIONS) and published here as credibility — never a silent skip
(the conformance kit):
| Framework | Scenario | Why it's exempt |
|---|---|---|
| CrewAI | correlation ID propagated | CrewAI's native OpenAI provider builds both its sync OpenAI and its AsyncOpenAI from one client_params dict, and with an interceptor set it replaces http_client with its own httpx client, so the SDK's async client cannot be injected and the correlation ID ends up per-client, not per-run. ADK (model() and gemini()), LlamaIndex and Microsoft Agent Framework send through the SDK's shared client and record no exemption (#691, #740). |
| CrewAI | gateway identity observed | For the same reason, no response reaches the SDK's _on_response hook. When every resolved adapter is non-observing, donkey.last_call reports UNAVAILABLE and names them in surface. |
| CrewAI | JWT refreshed per send | CrewAI's native OpenAI provider owns the transport and builds its own clients, so the rotating JWT the SDK adds per send never reaches its requests. donkey.crewai.llm() and connection_kwargs() raise ConfigError in jwt mode; use client-id auth with CrewAI. ADK's model() and gemini(), LlamaIndex and Microsoft Agent Framework send through the SDK's client and carry the rotating JWT on async calls (jwt mode). |
| CrewAI | budget refusal not retried | CrewAI wraps every LLM call in its own rate-limit retry (3 attempts) and treats any 429 as a rate limit, so a TokenBudgetExceeded refusal is sent 3 times. CrewAI has no setting to turn it off; the OpenAI client underneath has max_retries=0. Every other adapter sends a budget refusal once (#734). |
ADK model(), CrewAI |
typed refusal bridged | The framework owns the transport (LiteLLM for ADK's model(), CrewAI's native OpenAI provider for CrewAI) and raises its own errors for a call the SDK never saw, so donkey.run() and typed_refusals() cannot tell a gateway refusal from any other failure there and pass those errors through. ADK's gemini() sends through the SDK's client and is bridged (#724). |
Each exemption matches what the adapter reports in donkey.<framework>.capabilities() (a frozen AdapterCapabilities per factory), and a unit test keeps the two in step (#726).
