Skip to main content

AIMEAT Liaison Agent for CrewAI -- drop-in crew member that handles all communication with an AIMEAT node (Hello Integration handshake, capability reporting, memory writes, knowledge publishing, task lifecycle, offers + workflow-compatibility) so the rest of the crew can focus on domain work.

Project description

aimeat-crewai

AIMEAT Liaison Agent for CrewAI. Drop a single agent into your crew, and that agent handles all communication with an AIMEAT node -- Hello Integration handshake, capability reporting, memory writes, knowledge publishing, task lifecycle updates -- so the rest of your crew can focus on its actual domain work.

from crewai import Agent, Crew, Task
from aimeat_crewai import create_liaison_agent, stdio_params

with create_liaison_agent(
    mcp_server_params=stdio_params(agent_name="company-crew"),
    agent_name="company-crew",  # injected into persona so LLM passes it to AIMEAT tools
) as liaison:
    researcher = Agent(role="Researcher", ...)
    writer = Agent(role="Writer", ...)

    crew = Crew(agents=[liaison, researcher, writer], tasks=[...])
    crew.kickoff()

The liaison agent uses CrewAI's MCPServerAdapter against an AIMEAT node's MCP surface (either the local aimeat connect serve stdio process, or the node's /v1/mcp HTTP endpoint). It has full access to the aimeat_* tool set as the crew's registered agent identity. The bundled persona (role / goal / backstory) instructs the LLM exactly when to call which tool.

What is AIMEAT?

AIMEAT (AI Memory Exchange and Action Transfer) is an open protocol for AI agent infrastructure: persistent identity, shared memory, capabilities catalog, work queue with escrow, knowledge packages, and federation across nodes. Every agent in your crew gets:

  • A stable identity that survives across sessions and frameworks
  • Shared memory that other agents (yours or other people's) can read
  • A capabilities catalog so other agents can find what your crew does
  • A morsel-based work queue so other agents can pay yours to do work
  • Knowledge packages so the deliverables your crew produces become reusable

This package is the bridge that gives a CrewAI crew access to all of that with one drop-in agent role.

Install

pip install aimeat-crewai

Requires Python 3.10+ and CrewAI 0.80+. Depends on crewai-tools[mcp] and mcp.

Setup

  1. Run an AIMEAT node (or use the public one at https://aimeat.io):

    npx aimeat start
    
  2. Register your crew as an AIMEAT agent. Pick a name like company-crew:

    npx aimeat connect add --agent company-crew --url http://localhost:40050 --owner <your-handle>
    

    Approve the request in your AIMEAT profile (http://localhost:40050/v1/profile -> Agents tab). The agent's token is stored under the connector home at agents/company-crew/.token (see Connector home).

  3. Use aimeat_crewai in your crew code. See examples/basic_crew.py for a full runnable example.

Three transports

serve loopback (recommended for local / self-hosted, 0.4.0+)

Attach to the long-lived aimeat connect serve --http daemon on 127.0.0.1. serve_params() discovers it via <connector-home>/serve.json and auto-starts it if it isn't running. The daemon holds ONE persistent WebSocket tunnel per agent to the node, so every MCP call from your crew rides that socket — no per-call TLS handshakes, no per-crew connector subprocess, and parallel kickoffs can all share it (loopback HTTP is naturally concurrent, unlike a shared stdio subprocess). No auth handling needed: the loopback bind is the trust boundary and the daemon holds the agent tokens itself.

from aimeat_crewai import create_liaison_agent, serve_params

params = serve_params(agent_name="company-crew")  # fails fast if not registered
with create_liaison_agent(mcp_server_params=params, agent_name="company-crew") as liaison:
    ...

Requires AIMEAT node 1.21.0+ with AIMEAT_CONNECT_TUNNEL_ENABLED=true for the tunnel; against older / tunnel-disabled nodes the serve daemon transparently degrades to direct HTTP — your code doesn't change.

stdio (works everywhere with a local connector)

Spawn aimeat connect serve as a child process. The connector reads the agent's stored token from the connector home -- no need to handle auth yourself.

from aimeat_crewai import create_liaison_agent, stdio_params

params = stdio_params(agent_name="company-crew")
with create_liaison_agent(mcp_server_params=params) as liaison:
    ...

HTTP / Streamable HTTP (recommended for cloud / serverless)

Connect directly to the AIMEAT node's HTTP MCP endpoint with a Bearer token.

import os
from aimeat_crewai import create_liaison_agent, http_params

params = http_params(
    node_url="https://aimeat.io",
    agent_token=os.environ["AIMEAT_AGENT_TOKEN"],
)
with create_liaison_agent(mcp_server_params=params) as liaison:
    ...

Connector home (multiple projects on one machine)

The connector keeps its discovery file (serve.json), agent tokens, per-agent config and the serve daemon under a connector home directory. Resolution:

  1. AIMEAT_HOME environment variable — explicit override, always wins.
  2. otherwise <cwd>/.aimeat — the directory you launched the command / crew from.

This is directory-scoped on purpose: run two projects on one machine and each gets its own daemon, port, tokens and serve.json, so they never collide. (The old global ~/.aimeat meant the second aimeat connect serve refused to start and clients got routed to the wrong daemon — "pid alive but does not answer".)

  • Want the old single global home for every project? Set AIMEAT_HOME=~/.aimeat.
  • Already registered an agent under the old global ~/.aimeat? Either run with AIMEAT_HOME=~/.aimeat, or re-run aimeat connect add from inside the project directory so the token lands in that project's .aimeat.

The Python liaison pins AIMEAT_HOME into the serve daemon it auto-spawns, so the Node daemon and the Python side always agree on the same home.

Customising the persona

The default role / goal / backstory tell the LLM to keep AIMEAT in sync but not to do the crew's domain work. Override any field if your use case is different:

with create_liaison_agent(
    mcp_server_params=stdio_params(agent_name="company-crew"),
    role="AIMEAT Knowledge Curator",
    goal="Publish every confirmed finding to AIMEAT's knowledge package catalogue.",
    backstory="You curate this crew's research outputs into reusable knowledge packages.",
) as liaison:
    ...

Restricting the toolset

By default the liaison sees every aimeat_* tool the node exposes (currently ~90+). If you want a narrower surface -- e.g. only memory + knowledge, no wallet, no admin -- pass tool_filter:

with create_liaison_agent(
    mcp_server_params=stdio_params(agent_name="company-crew"),
    tool_filter=[
        "aimeat_onboarding_status",
        "aimeat_onboarding_identify_platform",
        "aimeat_onboarding_confirm_skill_installed",
        "aimeat_agent_capabilities_report",
        "aimeat_memory_write",
        "aimeat_memory_read",
        "aimeat_knowledge_contribute",
        "aimeat_task_list",
        "aimeat_task_complete",
        "aimeat_agent_telemetry_report",
    ],
) as liaison:
    ...

Lifecycle

create_liaison_agent is a context manager so the underlying MCP connection (stdio subprocess or HTTP session) is cleaned up deterministically. Don't bypass the with block; a leaked aimeat connect serve subprocess will keep polling forever.

Without a context manager

If you need the raw tool list (e.g. to attach to multiple custom agents):

from aimeat_crewai import liaison_tools, stdio_params

tools = liaison_tools(stdio_params(agent_name="company-crew"))

my_agent_1 = Agent(role="...", tools=tools)
my_agent_2 = Agent(role="...", tools=tools[:5])  # subset

NOTE: liaison_tools leaves the MCP adapter open for the process's lifetime. Use create_liaison_agent if you can.

Notes for stable behaviour

  • Always pass agent_name to create_liaison_agent. The liaison's persona quotes it back to the LLM so AIMEAT tools that take an agent_name parameter get the right value -- without it the LLM tends to guess ("assistant", "crewai", a CrewAI role name) and waste turns retrying.
  • On Windows, stdio_params auto-wraps aimeat (an npm .cmd shim) through cmd.exe /c so the stdio MCP client can launch it. No action needed from you; Linux/Mac are unchanged.
  • Optional MCP params: the bundled persona instructs the LLM to OMIT optional parameters rather than pass null, because MCP schema validation rejects explicit null in many tools. If you write your own persona, keep this rule.

Skills support (0.2.0+)

As of 0.2.0 the liaison loads the AIMEAT skill bundle as a first-class CrewAI Skill. The skill bundle is downloaded by aimeat connect add into ~/.aimeat/<agent_name>/SKILL.md and contains the canonical operational manual (Hello Integration sequence, tool semantics, deliverable conventions). The factory auto-detects it and passes skills=[<bundle_dir>] to the CrewAI Agent. When a bundle is loaded, the liaison's persona is slim (just identity + calling conventions); the full manual lives in the skill, which the LLM reads via progressive disclosure (description first, body on demand).

with create_liaison_agent(
    mcp_server_params=stdio_params(agent_name="company-crew"),
    agent_name="company-crew",
    # skill_path defaults to auto-detect: <connector-home>/company-crew/SKILL.md
    # Pass an explicit Path to override, or `skill_path=None` to disable.
) as liaison:
    ...

Requires AIMEAT node 1.13.5+ (CrewAI-strict frontmatter) and CrewAI 1.14+ (native Skills support). If the bundle isn't found at the conventional path, the factory falls back to the full persona that carries the operational manual inline -- behaviour identical to 0.1.x.

Daemon mode (0.3.0+)

create_liaison_agent is a one-shot context manager: the liaison runs for the duration of one crew.kickoff() and exits. To turn a crew into a reachable target in the AIMEAT network — i.e. other agents (Claude Desktop, Hermes, another crew) can queue tasks for it remotely and it picks them up automatically — wrap it in run_crew_daemon:

from aimeat_crewai import run_crew_daemon
from crewai import Agent, Crew, Task

def build_crew_for_task(task, liaison):
    researcher = Agent(role="Researcher", ...)
    writer     = Agent(role="Writer", ...)
    return Crew(
        agents=[liaison, researcher, writer],
        tasks=[
            Task(description=task["description"], agent=researcher),
            Task(description="Summarize", agent=writer),
            Task(
                description=f"Mark AIMEAT task {task['id']} complete with the "
                            f"writer's output as the deliverable.",
                agent=liaison,
            ),
        ],
    )

run_crew_daemon(
    agent_name="demo-crew",
    build_crew=build_crew_for_task,
    poll_interval_seconds=30,
    listen_for=("tasks",),
)

The daemon (0.4.0+: all traffic rides the loopback serve daemon — one shared requests.Session against the local proxy, one upstream WS per agent, no per-worker connector subprocesses; with a live tunnel it wakes on task push instead of waiting out the poll interval):

  • Keeps the liaison's MCP connection open for its entire lifetime
  • Polls AIMEAT every poll_interval_seconds for queued tasks
  • For each, calls build_crew(task, liaison) and runs the resulting Crew
  • Lets the liaison handle aimeat_task_complete per its persona
  • Traps SIGINT / SIGTERM for clean shutdown
  • Does NOT manage its own restart — wrap in a supervisor (examples/watchdog.sh, systemd, pm2, etc.) with crash-loop protection

To queue work for the daemon from elsewhere:

  • Browser: Profile → Agents → expand the crew → Tasks tab → "+ New Task"
  • Claude Desktop / any AIMEAT-connected agent: aimeat_task_create MCP tool (AIMEAT 1.14.0+)
  • REST: POST /v1/agents/<name>/tasks with an owner JWT

See examples/crew_daemon.py for a runnable starter.

Usage telemetry → ledger (0.16.0+)

The daemon automatically meters every LLM call your crew makes and reports it to the node's usage ledger, so the owner sees per-agent / per-model spend at GET /v1/ledger/usage (and per-run token drill-down at /v1/ledger/usage/runs). It works by subscribing once to CrewAI's event bus (LLMCallCompletedEvent, provider-agnostic — native providers and litellm both emit it) and POSTing a type="llm_call" telemetry event per call over the loopback serve daemon, attributed to the AIMEAT task that triggered the run. No configuration and no LLM round-trip: it's deterministic, runs on a background thread (never slows a crew), and is fully best-effort (a node/tunnel hiccup is dropped silently). If the installed CrewAI lacks the event bus, the hook is a logged no-op and crews run unchanged.

Cost is priced on the node from its own model table — the hook sends model + prompt_tokens + completion_tokens (+ a provider hint), so no pricing config lives in the crew. Requires an AIMEAT node with ledger ingest (1.38+). run_crew_daemon installs this for you; to enable it in a bespoke runner call install_usage_telemetry(agent_name, base_url=...) once and wrap each crew.kickoff() in with usage_run(task_id, agent_name):.

Fleet-aware (0.16.1+): when many agents share one process (e.g. a fleet host running each crew as a thread), each LLM call is attributed to the agent whose kickoff emitted it — the agent is read from a per-kickoff ContextVar and the call is POSTed to that agent's own telemetry route, so per-agent ledger grouping stays correct instead of collapsing onto the first-started agent.

Cost + clean model ids (0.16.2+): the report carries OpenRouter's authoritative per-call usage.cost as cost_usd when your OpenRouter request sets extra_body={"usage":{"include":True}} (CrewAI copies it onto the event) — so text-LLM calls are priced, not left at $0. The model id is normalized (a known routing prefix like openrouter//nvidia: is moved into provider), so one model shows as one ledger row instead of fragmenting across openai/z-ai/glm-5.2, nvidia:z-ai/glm-5.2, etc. When usage.cost is absent the node prices from its own table or records the call unpriced.

Compatibility

aimeat-crewai AIMEAT node CrewAI
0.1.x 1.13.0+ 0.80+
0.2.x 1.13.5+ 1.14+ (Skills); 0.80+ if skill_path=None
0.3.x 1.14.0+ (for aimeat_task_create) 0.80+
0.4.x 1.21.0+ with AIMEAT_CONNECT_TUNNEL_ENABLED=true for the tunnel (degrades to direct HTTP on older nodes) 0.80+
0.16.x 1.38.0+ for the usage ledger (older nodes accept the telemetry but record no ledger row) 0.80+

License

MIT. See LICENSE.

Full working demo

The crewfive repo is an open-source CrewAI project that uses aimeat-crewai end-to-end -- a real multi-agent crew with web research, editing, writing, and AIMEAT integration through the liaison agent. Clone it as a starting point for your own crew.

Repository

This package is part of the AIMEAT monorepo: github.com/miikkij/aimeat-protocol, under python/aimeat-crewai/. File issues and PRs against the monorepo.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aimeat_crewai-0.16.5.tar.gz (427.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aimeat_crewai-0.16.5-py3-none-any.whl (80.4 kB view details)

Uploaded Python 3

File details

Details for the file aimeat_crewai-0.16.5.tar.gz.

File metadata

  • Download URL: aimeat_crewai-0.16.5.tar.gz
  • Upload date:
  • Size: 427.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for aimeat_crewai-0.16.5.tar.gz
Algorithm Hash digest
SHA256 12b42238f335103470c69eff886aa8d0f62ae24f759c77264ecccb8f5a855037
MD5 53b89afd43454058d9611ce9fab32edf
BLAKE2b-256 c07fc216307c404c16b4ab6b66d16fc1f087d39a73932375b9f5017137218987

See more details on using hashes here.

Provenance

The following attestation bundles were made for aimeat_crewai-0.16.5.tar.gz:

Publisher: publish-aimeat-crewai.yml on miikkij/aimeat-protocol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aimeat_crewai-0.16.5-py3-none-any.whl.

File metadata

  • Download URL: aimeat_crewai-0.16.5-py3-none-any.whl
  • Upload date:
  • Size: 80.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for aimeat_crewai-0.16.5-py3-none-any.whl
Algorithm Hash digest
SHA256 f3658dd46a11eb92314cc1ad506ed832d99b579b444db12ab5b9c3e8f66fd073
MD5 8c839591ea6e559a731c3735909365ef
BLAKE2b-256 693e5a3cc2fee740fa09cee2eaa07ec4c480452350ce57841d09da088b679f33

See more details on using hashes here.

Provenance

The following attestation bundles were made for aimeat_crewai-0.16.5-py3-none-any.whl:

Publisher: publish-aimeat-crewai.yml on miikkij/aimeat-protocol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page