Building a policy‑governed multi‑agent financial research workflow with Omnigent
Picture a tiny supervised research team running inside a Colab notebook: a lead analyst fetches a live USD→EUR quote, writes a client-ready two‑sentence note, and passes that draft to an auditor agent that checks clarity and length. Runtime policies quietly limit tool calls and API spend. You can set this up in Google Colab using Omnigent, a couple of local Python modules, and an Anthropic API key provided at runtime rather than saved to disk.
What this setup does, in plain terms
- Create an isolated Python 3.12 environment (folder: .venv) and install Omnigent plus a couple of small packages.
- Expose two local Python functions in agent_tools.py as agent-callable tools: get_exchange_rate (calls an FX endpoint) and word_count (returns len(text.split())).
- Define a main agent (fx_research_lead) and a sub-agent (text_auditor) in fx_research_lead.yaml. The lead uses the Claude SDK harness (executor: claude-sdk) to fetch rates, draft the note, then delegate for auditing.
- Apply two Omnigent policies at runtime: cap_calls (limit: 20) and budget (max_cost_usd: 1.00).
- Run the workflow non‑interactively from Colab with the Omnigent CLI (–no-session), so no interactive terminal is required for this particular SDK-based flow.
Quick reproducible environment notes
Key names and paths used in the example:
- Working directory: /content/omnigent_tutorial
- Virtual environment: Python 3.12 → folder .venv
- Packages installed inside the venv: omnigent, requests, and uv
- Omnigent CLI variable: OMNI (points to .venv/bin/omnigent)
- Anthropic credential environment variable: ANTHROPIC_API_KEY
- Local tool module: agent_tools.py
- YAML config: fx_research_lead.yaml
How to create the venv (two practical options)
Colab can be picky about which Python and pip are available. Omnigent’s docs recommend a helper called uv for bootstrapping Python 3.12 in ephemeral environments like Colab, but you can often use the standard venv flow if Python 3.12 is present. Two workable command sequences:
-
Standard venv (if Python 3.12 is available):
python3.12 -m venv .venv
source .venv/bin/activate
pip install omnigent requests uv -
Follow Omnigent docs with uv:
Install uv inside the active interpreter per Omnigent’s quickstart, then use the uv workflow the docs show to create a 3.12 venv. The Omnigent repository describes uv as a recommended bootstrap tool for Colab, use the doc page to copy the exact uv commands for your environment.
If you follow the first path, installing uv in the venv is harmless and aligns you with Omnigent’s recommended tooling. If you prefer to strictly follow Omnigent’s quickstart, consult the Omnigent repo for the exact uv invocation.
Minimal YAML guidance, where to pin the model
Pin your Claude/Anthropic model in the YAML so cost estimates and behavior stay stable. A short YAML-like example to show placement (trimmed for readability):
executor: claude-sdk
model: claude-2.1
Check your Anthropic account for available model names before deployment; model availability and pricing change over time, and that directly affects budget estimates.
Verbatim role prompts from the YAML
Keeping the agent prompts explicit is key to predictable behavior. These are the exact prompts embedded in the example YAML:
YAML agent prompt (fx_research_lead):
“You are a financial research lead. For any question about currency
movements: call get_exchange_rate to fetch the live rate, then hand
your draft summary to the text_auditor sub-agent for a clarity and
length check before giving your final answer to the user.”
YAML sub-agent prompt (text_auditor):
“You audit short pieces of financial writing. Call word_count to
report its length, flag any unexplained jargon, and suggest one
concrete clarity improvement.”
Tools, expected I/O, and the FX endpoint
- get_exchange_rate, calls a public FX API and returns a JSON-like structure. The example expects data shaped like: base, date, and rates (e.g., {“base”:”USD”, “date”:”2026-07-30″, “rates”:{“EUR”:0.92}}).
- word_count, returns an integer (len(text.split())). The auditor uses this to enforce length constraints.
- The tutorial example calls https://api.frankfurter.app/latest. Frankfurter’s docs, however, emphasize the v2 API under https://api.frankfurter.dev/v2/. For production use prefer a v2 call that requests only the pair you need, for example:
https://api.frankfurter.dev/v2/latest?base=USD&symbols=EUR
Frankfurter’s v2 endpoints provide provider attribution and other features that help with provenance; check their docs before you switch a production integration.
Execution flow, step by step
- Start the Omnigent runner with the claude-sdk harness.
- The lead agent calls get_exchange_rate (which queries Frankfurter and returns base, date, rates).
- The lead drafts a concise two‑sentence client note.
- The draft is passed to the text_auditor, which calls word_count, flags jargon, and suggests a single clarity improvement.
- The final answer is returned to the user; Omnigent policies enforce call and cost limits during the run.
Run commands and a clear debug example
From inside the activated venv set OMNI to the omnigent binary and run non-interactively. Example:
OMNI=.venv/bin/omnigent
$OMNI run fx_research_lead.yaml -p “What is the current USD to EUR exchange rate? Give me a two-sentence summary I could paste into a client note.” –no-session
If you need verbose logs, try this explicit debug command (adjust WORKDIR):
OMNI=.venv/bin/omnigent
$OMNI –debug –log-to-stderr run /content/omnigent_tutorial/fx_research_lead.yaml -p “What is the current USD to EUR exchange rate? Give me a two-sentence summary I could paste into a client note.” –no-session
The example output also prints a “Next steps” block. The tutorial includes this exact text as guidance for further exploration:
“Next steps:
• Explore the CLI: !{OMNI} run –help
• Bundled demo agents:
!{OMNI} polly -p \”review this repo\” –no-session
!{OMNI} debby -p \”brainstorm 3 names for a coffee shop\” –no-session
• YAML schema: https://github.com/omnigent-ai/omnigent/blob/main/docs/AGENT_YAML_SPEC.md
• Policies: https://github.com/omnigent-ai/omnigent/blob/main/docs/POLICIES.md”
Governance: what the policies mean (and what they probably don’t)
- cap_calls, implemented via omnigent.policies.builtins.safety.max_tool_calls_per_session with limit: 20. This restricts how many tool invocations the session may attempt.
- budget, implemented via omnigent.policies.builtins.cost.cost_budget with max_cost_usd: 1.00. This is a runtime budget enforced by Omnigent’s estimator.
Important nuance: the budget policy uses an internal cost estimator (model/token pricing and the chosen model matter) rather than talking to your cloud billing system. This estimator is approximate, so do not expect it to match your provider invoice exactly. Verify behavior by experiment: set an intentionally tiny cap (for example max_cost_usd: 0.001) and see whether Omnigent halts the run, raises an error, or emits warning logs. Do the same with a low tool-call limit (for example limit: 1) to observe how the runner enforces the cap.
Secrets handling, safer practical guidance
Colab notebooks are convenient but they are not a secrets manager. The example reads the Anthropic key from the environment variable ANTHROPIC_API_KEY and avoids writing it to disk. That is better than persisting secrets in files, but environment variables and notebook outputs can still leak secrets if you print them or share the notebook.
Safer options:
- Use an ephemeral input (getpass) to inject the key at runtime without saving it to a file, for example using Python’s getpass to populate os.environ[‘ANTHROPIC_API_KEY’].
- Use Google Secret Manager or another secrets store and fetch the credential at runtime with short-lived access.
- Never print the key, clear cell outputs before sharing, and revoke keys after experiments.
Node.js and harnesses, when you do and don’t need it
The example avoids Node.js because it uses an SDK-based, non-interactive harness (claude-sdk) that runs from Python. Omnigent supports other harnesses (coding-harness CLIs, web UI tooling) that do require Node.js, pnpm/npm, tmux, or additional system tooling. Check the Omnigent docs for the specific harness prerequisites before switching harnesses or using interactive features.
Hardening checklist before you trust this for client use
- Pin the exact Anthropic/Claude model in YAML (example: model: claude-2.1) and verify availability in your account.
- Harden get_exchange_rate with retries/backoff, explicit 4xx/5xx handling, and provider/date provenance in the returned data.
- Test policy enforcement by running tiny experiments (max_cost_usd very low, and max_tool_calls_per_session set to 1) and inspect logs at ~/.omnigent/logs/runner/.
- Keep human-in-the-loop signoff for any client-facing financial text; agent output is not a regulatory or fiduciary substitute.
- Prefer a paid FX feed (Bloomberg, Refinitiv, Xignite) when SLAs, auditability, and accuracy are required.
Where to find the full example
The complete Colab-style notebook for the example is published on GitHub here:
https://github.com/MARKTECHPOST-AI-MEDIA-INC/AI-Agents-Projects-Tutorials/blob/main/Agentic%20AI%20Codes/omnigent_multi_agent_fx_research_Marktechpost.ipynb
For Omnigent reference material you’ll use frequently, see the YAML schema and policies docs in the Omnigent repo:
- AGENT YAML schema: https://github.com/omnigent-ai/omnigent/blob/main/docs/AGENT_YAML_SPEC.md
- Policies: https://github.com/omnigent-ai/omnigent/blob/main/docs/POLICIES.md
Key takeaways, quick questions you’ll ask (and direct answers)
- Can I run an Omnigent multi-agent workflow inside Colab without Node.js?
Yes, for an SDK-based, non-interactive harness (example: claude-sdk) you can run from Python in Colab without Node.js. Other Omnigent harnesses and interactive features may require Node.js, pnpm/npm, or tmux; check the harness docs before switching modes.
- How are live FX rates fetched in this example?
The local tool get_exchange_rate calls Frankfurter (the tutorial uses https://api.frankfurter.app/latest) and expects JSON with rates and date. For production, prefer Frankfurter’s v2 endpoints (for example https://api.frankfurter.dev/v2/latest?base=USD&symbols=EUR) and request only the currency pair you need.
- How does the example keep Anthropic credentials secure?
The Anthropic API key is supplied via the environment variable ANTHROPIC_API_KEY and not written to disk. That is safer than saving keys in files, but environment variables and notebook outputs can leak secrets; use getpass or a secrets manager, avoid printing keys, and clear outputs before sharing.
- What governance is in place to prevent runaway calls or spend?
Two Omnigent policies are applied: a tool-call cap (limit: 20) via max_tool_calls_per_session, and a cost budget (max_cost_usd: 1.00) via cost_budget. These act as runtime guardrails but rely on internal estimators; run small, deliberate tests to confirm enforcement semantics before relying on them.
- Is Omnigent production-ready?
Omnigent is currently marked “alpha” in its GitHub repository. It is suitable for experimentation and prototyping, but validate policy enforcement, cost accounting, and harness requirements carefully before using it in production workflows.
A short, actionable 3-step quickstart
- Clone the example notebook and create a Python 3.12 venv (or follow Omnigent’s uv-based quickstart).
- Set ANTHROPIC_API_KEY at runtime (use getpass or a secrets manager), pin a Claude model in YAML (e.g., model: claude-2.1), and set policies to conservative caps (e.g., max_cost_usd: 0.01, limit: 1) for testing.
- Run the agent non-interactively, inspect ~/.omnigent/logs/runner/, and confirm policy behavior and tool I/O (check the Frankfurter JSON, generated text, and auditor output). If behavior matches expectations, iteratively relax caps and harden the tools (retries, provenance, and human signoff).
Multi-agent patterns, deterministic local tools for data, a role-focused generator, and a compact auditor, are a practical way to build auditable, testable automation for financial workflows. Add conservative runtime policies, pin models, and keep a human in the loop for client-facing output.