Skip to Content
DocsRecipesLong-running research agent

Long-running research agent with durable replay

The agent runs a multi-step research task. If the process crashes or the host reboots, restart with the same session ID and pick up where you left off.

import asyncio from datetime import timedelta from loomflow import Agent, tool from loomflow.governance.budget import BudgetConfig, StandardBudget from loomflow.mcp import MCPRegistry, MCPServerSpec from loomflow.model.anthropic import AnthropicModel from loomflow.runtime import SqliteRuntime @tool async def web_search(query: str) -> str: """Search the web.""" ... @tool async def fetch(url: str) -> str: """Fetch a URL.""" ... mcp_servers = MCPRegistry([ MCPServerSpec.stdio("git", "uvx", ["mcp-server-git", "--repo", "."]), MCPServerSpec.stdio("fs", "uvx", ["mcp-server-filesystem", "--root", "."]), ]) async def main(): runtime = SqliteRuntime("./research_journal.db") agent = Agent( "You are a research assistant. Plan a multi-step research task, " "execute each step with the available tools, then summarize.", model=AnthropicModel("claude-opus-4-7"), runtime=runtime, tools=[web_search, fetch, *mcp_servers.list_tools_sync()], budget=StandardBudget(BudgetConfig( max_tokens=500_000, max_cost_usd=20.0, max_wall_clock=timedelta(hours=2), )), ) result = await agent.run("Research the state of agent harnesses in 2026.") print(result.output) asyncio.run(main())

Every model call and every tool dispatch is journaled by (session_id, step_name). On a process restart, instantiating a new SqliteRuntime against the same DB file with the same session ID returns cached values for completed steps and only re-executes the un-completed work.

Last updated on