Agents written in code don’t show up in any admin console. Static analysis can list them, with their models and tools, without running a line of the code.
An agent built in Copilot Studio at least appears in Copilot Studio’s admin pages. An agent written in Python appears nowhere. It’s a constructor call in some module, with its model name in a config file, its prompt in a text file and its tools in three other modules. It changes with every commit, and it may be one of a dozen across your repositories.
If someone asks which of your services run agents, which models they call and which functions they can invoke, the answer is often a grep and a guess. I wrote a reader for Marshal, an open-source AI agent inventory, that answers it from the code instead. In an earlier article I covered the inventory for agents built on platforms. This one is about agents in code.
Marshal parses Python files with Python’s own ast module, the way a linter does. Nothing is imported or executed, so it's safe to point at any repository, and it needs no API keys.
Each call to an agent constructor is one agent:
Code that calls a model API directly and passes it tools is an agent loop too, even without a framework. Marshal records those calls to the OpenAI, Anthropic, Google GenAI, LiteLLM and Bedrock Runtime APIs as agents, marked as inferred.
A small evaluator resolves what can be known without running anything: string literals, f-strings, names in the same module, imports between the project’s own modules, and prompt files read from disk. Anything else, such as a model name read from an environment variable, is recorded as unknown with the reason. Marshal doesn’t fill in a value it can’t see in the code.
I ran it on four public example repositories: OpenAI’s Agents SDK examples, Google’s ADK samples, CrewAI’s project template and Anthropic’s quickstarts.
$ for repo in */; do marshal collect "$repo" --event shipped --environment prod; done$ marshal lsAGENT PLATFORM LATEST SHIPPED FRESHNESS COMPLETEanthropic-quickstarts/sampling-loop anthropic-api v1 prod v1 prod: manual 0d 25%crewai-template/reporting-analyst crewai v1 prod v1 prod: manual 0d 30%crewai-template/researcher crewai v1 prod v1 prod: manual 0d 30%google-adk/critic-agent google-adk v1 prod v1 prod: manual 0d 37%google-adk/reviser-agent google-adk v1 prod v1 prod: manual 0d 25%openai-agents/faq-agent openai-agents v1 prod v1 prod: manual 0d 20%openai-agents/seat-booking-agent openai-agents v1 prod v1 prod: manual 0d 20%openai-agents/triage-agent openai-agents v1 prod v1 prod: manual 0d 10%# 14 more openai-agents rows
That’s 22 agents across four frameworks. The Anthropic one has no framework at all: it’s the computer-use demo’s sampling loop, found because it calls the Messages API with tools.
The COMPLETE column says how much of each agent the code states. A low number is information too. It tells you which agents depend on values that only exist at run time.
Here is part of the record for the FAQ agent in OpenAI’s customer service example:
agent: customer_service/faq-agentplatform: openai-agentssource: format: python artifact: main.py locator: agents.Agent at line 94spec: display_name: value: FAQ Agent provenance: declared model: requested: provenance: unknown basis: the SDK's default model is used provider: value: openai provenance: derived basis: the OpenAI Agents SDK's default client instructions: provenance: derived basis: 'main.py:94; unresolved parts in braces: RECOMMENDED_PROMPT_PREFIX' tools: - ref: tool/python.customer_service/main:faq_lookup_tool name: faq_lookup_tool description: Lookup frequently asked questions.
Every value says where it came from. The name is declared in the code. The provider is derived from a documented rule, because the SDK uses OpenAI’s client unless you pass another. The model is unknown, because the agent relies on the SDK’s default, which a new SDK release can change. The instructions are recorded with the one part that couldn’t be resolved, a prefix imported from the SDK package, left in braces.
For an audit, that unknown model is a finding. It means the agent’s model changes when someone upgrades a dependency, without any change to the agent’s own code.
The inventory gets more useful once it runs on every pull request. Here is a one-line change to the same example that gives the FAQ agent the seat-booking agent’s tool:
- tools=[faq_lookup_tool],+ tools=[faq_lookup_tool, update_seat],
Marshal compares the proposed agents with what’s shipped and ranks the change:
customer_service/faq-agent (openai-agents) prod: v1 → v2
HIGH + tool tool/python.customer_service/main:update_seat (scope unknown, reversible unknown)
Completeness 15%
It’s HIGH because the code doesn’t say whether update_seat only reads or also writes, and Marshal doesn't guess from a function's name. A new tool whose effect is unknown gets the same rank as a new write tool. In CI, the GitHub Action posts this as a pull request comment, and the GitLab CI template does the same on a merge request.
The reverse question matters before you change a function that agents call:
$ marshal deps "tool/python.*:update_seat"AGENT VERSION WHERE RELATION REFcustomer_service/faq-agent v2 latest tool tool/python.customer_service/main:update_seatcustomer_service/seat-booking-agent v1 prod (latest) tool tool/python.customer_service/main:update_seat
Tool references include the project, so two copies of the same template in different repositories stay two different tools.
Static analysis has limits, and the records say where they are. A model name from an environment variable or a function parameter is unknown. Tools assembled at run time are reported with a warning; the Anthropic sampling loop builds its tool list at run time, so its record says so. Custom LangGraph StateGraph workflows aren't read yet, only the prebuilt agent constructors, and neither are model calls whose arguments arrive through **kwargs.
When a framework changes its API, a weekly job in Marshal’s repository runs the tests against each framework’s latest public examples and opens an issue when they fail.
Find every AI agent in your Python code: OpenAI Agents SDK, LangGraph, CrewAI and Google ADK was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.