agent-recipes.json — Pre-Built Workflow Recipes for AI Agents

Why It's Hand-Curated, How Its Machine-Readable Chaining Works, and a Real Drift Bug It Was Designed to Prevent

COMPLETE GUIDE

Building with the API? Open the developer docs

Finmagine API & MCP — free tier to test • Pro/Max for full access • REST + MCP

Open the Docs →
← API & Agent Integration Hub ← All Feature Guides
Published: July 29, 2026  |  9 min read  |  Developer Guide  |  API & Agent Integration Series

Multimedia Learning Hub

Master agent-recipes.json through a complete learning overview and interactive flashcards

What You Will Master

Every guide in this series so far has referenced agent-recipes.json in passing — the file behind the Agentic Workflow Explorer's 10 recipes, listed first alongside openapi.json in llms.txt. This guide goes inside the actual file — its real structure, the engineering discipline behind it, and a genuine drift bug its design was changed specifically to prevent.

What This Guide Covers:

  1. Why It's Hand-Curated — and how that differs fundamentally from openapi.json
  2. Recipe-Level Fields — id, tier, async, status, quota, and the computed llm_required field
  3. Step-Level Fields — tool, depends_on, input_map, transport, external_call, fixed_params
  4. The llm_required Drift Bug — a real bug this file's design was rewritten to prevent
  5. input_map's Dot-Path Syntax — wildcards, indices, and the array-passthrough rule
  6. fixed_params — the constant-value gap a live execution test actually caught
  7. The Validating Schema — why a hand-edited file needs one

Who This Is For:

  • Agent framework builders parsing agent-recipes.json programmatically to drive their own execution engine
  • Developers who used the Agentic Workflow Explorer and want to understand exactly what data structure powers it
  • Anyone curious how a hand-maintained file stays trustworthy as a platform's API surface keeps growing underneath it

Test Your Knowledge

Click any card to reveal the answer. Use the search box to find a specific topic.

Why It's Hand-Curated

openapi.json is mechanically generated from the actual handler code every time it runs — no human decides what goes in it beyond writing the handlers themselves. agent-recipes.json can't work that way, and its own generator script says exactly why in its header comment:

// Unlike openapi.json, this is NOT mechanically derived from routes.php — // there is no way to know which tool chains form a coherent workflow // just from enumerating endpoints. This file is hand-curated.

Knowing that screen_stocks and start_committee both exist as operations tells you nothing about whether chaining them together produces something useful — that judgment call has to come from a person who understands what the workflow is actually for. So every one of the 10 recipes was written by hand, then individually checked against the live openapi.json (tier, MCP tool name, response shape) before shipping — not assumed correct from memory of what was planned months earlier.

"Every recipe here is built ONLY from tools confirmed live in openapi.json as of generation time — none are aspirational." That's a direct quote from the generator's own docblock. It's a deliberate discipline against a specific, recurring failure mode this project has hit before: documentation describing a workflow that sounds right but was never actually verified to work against the real, current API.

Recipe-Level Fields

FieldTypeWhat it's for
idstringStable identifier, e.g. india_screen_to_committee
title, descriptionstringHuman-readable name and summary
marketindia | us | both | nullWhich market this recipe targets
required_tierfree | api_pro | api_maxMinimum tier needed — read directly from openapi.json's per-operation x-tier, not guessed
asyncbooleanWhether the recipe includes a start-then-poll step (Committee/Preset recipes)
llm_requiredbooleanComputed, not hand-typed — see the drift bug below
statuscomplete | partial | prerequisitecomplete = full working output; partial = a documented gap exists (see the recipe's own note); prerequisite = sets something up for other recipes rather than producing a research output itself
quotastring or nullFree-text quota description, e.g. "5 committee runs / 24h"
estimated_runtimestring or nullFree-text runtime estimate
max_symbolsinteger or nullSymbol cap where applicable
output_contractstringWhat the recipe's final output actually is
failure_fallback, guardrail, notestring or nullOptional extra context, e.g. gap disclosure on status: partial recipes

Step-Level Fields

Every recipe's steps array is where the real chaining logic lives. Here's a genuine step from india_screen_to_committee:

{ "id": "fast_scan", "tool": "fast_scan_committee", "description": "Free, zero-LLM deterministic pre-screen across 3 lenses...", "input_from": "$.companies[*].symbol — pick up to 10, e.g. top by rs_rating", "depends_on": ["screen"], "input_map": { "symbols": "screen.companies[*].symbol" }, "max_items": 10, "transport": "rest", "external_call": "none" }
FieldWhat it's for
idStable, recipe-local step identifier — referenced by other steps' depends_on/input_map. Unique within the recipe, not globally
toolMust match a real MCP tool name — verified against the live tool list before shipping
input_fromFree-text chaining hint for human/agent readability — kept alongside the structured fields, not replaced by them
depends_onStep ids this step's request is built from. Empty array = no dependency. More than one entry = a genuine multi-parent DAG node — see the Agentic Workflow Explorer guide's honest-connector coverage
input_mapMachine-readable chaining — see the dedicated section below
transportrest or mcp — kept explicit rather than assumed, since a future MCP-only tool shouldn't silently get treated as REST
external_callnone | finmagine_free_tier | byo_key — see below
max_itemsOptional cap when a wildcard would otherwise map an unbounded array
fixed_paramsConstant values — see the dedicated section below

external_call — the three real categories

ValueMeaning
noneDeterministic, no provider touched — e.g. screening, fast scan, risk audit
finmagine_free_tierCalls an LLM, but uses Finmagine's own key (e.g. the natural-language screener) — not the user's
byo_keyCalls the user's own saved provider key and may consume real tokens/quota
A REAL BUG

The llm_required Drift Bug

This is the concrete story behind why llm_required is computed rather than hand-typed. An earlier version of this file had a recipe-level llm_required boolean set directly by whoever wrote the recipe. The byo_key_setup recipe shipped with llm_required: false — even though one of its 3 steps, test_byo_key, makes a real, live call to an actual LLM provider to verify a saved key.

The bug was found during Explorer Upgrade planning, 2026-07-28 — not caught at write time. A hand-typed summary field and the step-level reality it was supposed to summarize had quietly drifted apart. Nobody edited llm_required incorrectly on purpose; it was simply a second place the same fact had to be kept true, and it wasn't.

The fix: llm_required is no longer a field anyone sets directly. It's computed — true if any step's external_call is anything other than none:

// From the generator, conceptually: $recipe['llm_required'] = collect($recipe['steps']) ->contains(fn($step) => $step['external_call'] !== 'none');
This is the general pattern behind most of this file's design decisions. Anywhere a summary fact could be derived mechanically from more granular, already-true data, it now is — rather than existing as a second, independently-editable copy of the same fact that could silently stop matching reality.

input_map's Dot-Path Syntax

input_map values follow one of two shapes, resolved by a small hand-rolled evaluator in developer/assets/explorer-core.js — deliberately not a full JSONPath library, since the actual need is narrow:

SyntaxMeaning
stepId.dot.path[*].fieldWildcard — maps every element of the array at that path
stepId.dot.path[N].fieldIndex — picks a specific element by position
// "symbols": "screen.companies[*].symbol" means: // take the "screen" step's response, walk to .companies, // and collect the .symbol field from every element
Array values are never comma-joined by the recipe format itself — they're passed through as real arrays. An MCP tool argument or a POST JSON body receives an actual array. The one exception is a REST GET query string, which coerces an array to comma-separated form — but that happens via URLSearchParams' own native array-to-string behavior in the execution engine, not by any manual joining logic in the recipe format. This distinction matters if you're writing your own executor: don't comma-join arrays yourself before building a POST body, or you'll send a string where the API expects a real array.

Empty input_map is not a mistake

Some steps genuinely need a human or agent judgment call that can't be mechanically derived from a prior response — which preset id to launch, which provider to use, what secret to save. Those steps have a deliberately empty input_map: {}, and the schema explicitly documents this as expected, not an oversight: they need an interactive form in the Workflow Explorer UI, not silent auto-fill.

fixed_params — a Gap a Live Execution Test Actually Caught

fixed_params maps a request param to a literal constant value, for params that must always be sent a fixed value rather than chained from a prior step's response — something input_map's dot-path syntax has no way to express, since it only resolves paths into previous step results, never arbitrary constants.

{ "fixed_params": { "market": "us" } }
This field was added after a real gap surfaced during live testing, not designed upfront. Both us_zero_cost_demo and us_trader_to_committee's fast_scan step describe "pass market:'us'" in prose (input_from), but before fixed_params existed, there was no mechanical field actually carrying that constant into the real request — the Workflow Explorer's first live execution of those recipes surfaced the gap directly, and fixed_params was added specifically to close it.

The Validating Schema

Because this file is hand-edited by a person, not machine-generated, it needed something machine-generated files don't: a schema to catch mistakes. agent-recipes.schema.json is a standard JSON Schema (draft 2020-12) added specifically to prevent field drift as recipes get edited over time — added per an external reviewer's suggestion.

It enforces the enums this guide has covered throughout — required_tier must be one of exactly 3 values, status one of exactly 3, external_call one of exactly 3, transport one of exactly 2 — plus structural requirements like every step needing a tool field and every recipe needing an output_contract.

Validate against this schema before every regeneration, not just once. A file that's hand-edited by design needs a hand-edit-time safety net, not a one-time check — the schema exists precisely because this file will keep changing as new recipes are added, and each edit is a fresh opportunity for a typo or an inconsistent field.

What's Next

The last 3 guides in this series cover specific named workflows built on everything covered so far:

See the API & Agent Integration hub for the full 12-guide roadmap.

Ready to Analyse Indian Stocks Like a Pro?

Finmagine gives you 30+ computed financial ratios, sector benchmarks, FII/DII flows, the Finmagine Score, and AI-powered analysis — all in one place.

Analyse a Stock → Create Free Account
← API & Agent Integration Hub ← All Feature Guides