Implement a production-ready LLM query loop / agent loop for AI applications. Use this skill whenever the user wants to add tool calling, ReAct-style reasoning-action-observation cycles, function calling loops, query engines, agent runtimes, tool_result feedback, max-turn exits, or Claude Code-like Agent Loop behavior to their own product or codebase.
npx skills add https://github.com/simbajigege/book2skills --skill query-loop-implementation
Build the loop as product infrastructure, not prompt glue:
ConversationManager -> QueryLoop -> ToolRuntime
ConversationManager owns durable state: session id, messages, user settings, budget, persistence.QueryLoop owns one task turn: call model, detect tool calls, execute tools, append tool results, repeat.ToolRuntime owns registered tools: schemas, permission checks, execution, error formatting.Use ReAct as the mental model:
Thought -> Action -> Observation -> Thought -> Answer
Implement it as structured API traffic:
model thinking/text -> tool_call -> tool_result -> next model call -> final text
Find where messages are built, where the model is called, and whether tool/function calling is already configured.
Keep the first version narrow: one model call function, one tool registry, explicit exit conditions.
Use the provider's structured tool-call format when available. Avoid parsing free-form Action: text unless the provider has no function/tool-calling API.
Validate tool input against a schema, apply permission checks for risky tools, wrap failures as tool results, and log every call.
Always include maxTurns, timeout/cancel support, token/cost budget checks, and a fatal-error path.
Accept messages as loop input and return updated messages, but leave trimming, retrieval, summarization, and compaction to a separate context-management layer.
Adapt this shape to the user's language and SDK:
async function runQueryLoop({
initialMessages,
model,
tools,
maxTurns = 10,
signal,
}: {
initialMessages: Message[]
model: ModelClient
tools: ToolRegistry
maxTurns?: number
signal?: AbortSignal
}) {
let messages = [...initialMessages]
for (let turn = 1; turn <= maxTurns; turn++) {
if (signal?.aborted) return { status: "aborted", messages }
const response = await model.generate({
messages,
tools: tools.definitions(),
signal,
})
messages.push(response.message)
const toolCalls = extractToolCalls(response.message)
if (toolCalls.length === 0) {
return {
status: "completed",
finalMessage: response.message,
messages,
}
}
for (const call of toolCalls) {
const result = await tools.execute(call, { signal, messages })
messages.push(makeToolResultMessage(call.id, result))
}
}
return { status: "max_turns", messages }
}
The "model continues judging" step is not a separate function. It happens when the loop calls the model again after appending tool_result messages.
Implement these before shipping:
Prefer returning structured terminal reasons:
type TerminalReason =
| "completed"
| "max_turns"
| "aborted"
| "timeout"
| "permission_denied"
| "budget_exceeded"
| "fatal_tool_error"
Each tool should define:
type Tool = {
name: string
description: string
inputSchema: unknown
risk: "read" | "write" | "execute" | "external"
validate(input: unknown): ValidatedInput
canUse(input: ValidatedInput, ctx: ToolContext): Promise<PermissionDecision>
call(input: ValidatedInput, ctx: ToolContext): Promise<ToolResult>
}
Execution order:
find tool by name
-> schema validate model input
-> run tool-specific validation
-> check permission
-> call tool
-> format success or error as tool_result
Return tool errors to the model when it can plausibly recover, for example invalid arguments, file not found, empty search result, or transient API errors. Stop the loop for security violations, repeated failures, missing credentials, or budget exhaustion.
Keep "intelligence" in the model and "reliability" in code:
For simple AI apps, avoid subagents, worktrees, and streaming tool execution at first. Add them only when the product actually needs parallel work, isolation, or long-running tasks.
Read references/query-loop-patterns.md when designing a new query engine, reviewing an existing implementation, or explaining ReAct-to-query-loop architecture to another engineer.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.
Build agentic applications with GitHub Copilot SDK. Use when embedding AI agents in apps, creating custom tools, implementing streaming responses, managing sessions, connecting to MCP servers, or creating custom agents. Triggers on Copilot SDK, GitHub SDK, agentic app, embed Copilot, programmable agent, MCP server, custom agent.
Coding Agent Session Search - unified CLI/TUI to index and search local coding agent history from Claude Code, Codex, Gemini, Cursor, Aider, ChatGPT, Pi-Agent, Factory, and more. Purpose-built for AI agent consumption with robot mode.
Destructive Command Guard - High-performance Rust hook for Claude Code that blocks dangerous commands before execution. SIMD-accelerated, modular pack system, whitelist-first architecture. Essential safety layer for agent workflows.
Makepad UI development skills for Rust apps: setup, patterns, shaders, packaging, and troubleshooting.
Secure environment variable management ensuring secrets are never exposed in Claude sessions, terminals, logs, or git commits
Prompt for generating an AGENTS.md file for a repository
Take simbajigege/query-loop-implementation from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.