Intercept & Control AI Requests
Section titled “Intercept & Control AI Requests”Hoody AI requests are ordinary HTTP calls, so you can put hoody-exec in front of the gateway as a MITM (Man-In-The-Middle) proxy and read or rewrite every request and response.
Because the traffic is HTTP (see The HTTP Revolution), it is observable and modifiable the same way any other HTTP call is. AI requests carry nothing special at the transport layer.
A MITM script can log, transform, cache, or reroute every AI interaction in a few lines of JavaScript.
Deploy a MITM script once (see Deploy the MITM script below), then change the base URL in your AI client. The base_url swap shown in the next section is the on-demand toggle, not the whole setup.
Without MITM: https://ai.hoody.com/api/v1With MITM: https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1
Switching between them is a base URL change.Enable MITM on demand
Section titled “Enable MITM on demand”Turning MITM on and off is a client setting, not a code change: point the AI client’s base URL at hoody-exec instead of at the gateway.
hoody-agent uses Hoody AI automatically. The AI gateway (base URL, key, model) is configured on the session or agent, not passed per request. To route the agent through your MITM proxy, point its configured AI base URL at hoody-exec:
- Normal Hoody AI:
https://ai.hoody.com/api/v1 - With MITM enabled:
https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1
Then dispatch turns exactly as before; only the configured base URL changed:
curl -X POST "https://{projectId}-{containerId}-agent-1.{node}.containers.hoody.com/api/v1/agent/sessions/{sessionId}/prompt:sync" \ -d '{ "text": "Build an app" }'Everything else stays the same.
Normal Hoody AI:
- Base URL:
https://ai.hoody.com/api/v1 - API Key:
container-{containerName}
With MITM enabled:
- Base URL:
https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1 - API Key:
container-{containerName}(same)
Switch between these two URLs to enable/disable MITM features.
Normal Hoody AI:
- Base URL:
https://ai.hoody.com/api/v1 - API Key:
container-{containerName} - Provider: Custom (OpenAI-compatible)
With MITM enabled:
- Base URL:
https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1 - API Key:
container-{containerName}(same) - Provider: Custom (OpenAI-compatible)
Toggle the URL to switch modes.
// Normal Hoody AIconst AI_URL = 'https://ai.hoody.com/api/v1';
// With MITM enabledconst AI_URL = 'https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1';
// Rest of your code unchangedconst response = await fetch(`${AI_URL}/chat/completions`, { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ model, messages })});Use an environment variable to switch modes without editing code.
To test with MITM, point the client at the hoody-exec URL; to bypass it, point back at https://ai.hoody.com/api/v1. Neither direction needs a redeploy or a config file edit.
What interception makes possible
Section titled “What interception makes possible”HTTP as the interception point
Section titled “HTTP as the interception point”A typical AI integration is a black box: you send a prompt and get a response, and everything in between is hidden.
With Hoody’s HTTP architecture:
- Each AI request is a visible HTTP call
- Responses flow back through your infrastructure
- Tool calls arrive as JSON you can inspect and modify
- Agent decisions are HTTP endpoints you can intercept
Your code can sit anywhere in that path. It can log requests, hold them for human approval, transform prompts, cache responses, route to different models, chain agents together, replace tool calls, and inject context.
Capabilities
Section titled “Capabilities”Observability:
- Log every prompt and response for debugging
- Track token usage per project automatically
- Analyze AI decision patterns
- Monitor for prompt injection attempts
- Build audit trails for compliance
Human-in-the-loop review:
- Intercept high-stakes decisions for human approval
- Pause AI execution for review before deployment
- Add confirmation steps for sensitive operations
- Let the AI draft and leave the decision to a person
Cost optimization:
- Compress prompts to reduce token usage (20-40% savings)
- Cache responses to eliminate duplicate calls (100% on cache hits)
- Route to cheaper models for simple tasks (40-70% savings)
- Auto-optimize based on complexity analysis
Prompt and response enrichment:
- Add context from your knowledge base automatically
- Inject custom instructions per use case
- Transform responses to match your style
- Chain multiple AI calls
Tool call manipulation:
- Intercept and modify AI tool calls before execution
- Add safety checks to file operations
- Reroute dangerous commands to sandbox
- Replace file paths, command arguments, or entire operations
- Log all tool usage for audit trails
Agent orchestration:
- Cascade AI requests across multiple agent instances
- Coordinate multi-agent workflows via HTTP
- Distribute tasks across agent swarms
- Build self-improving agent networks
The MITM script template
Section titled “The MITM script template”The basic pattern for an AI MITM proxy built on hoody-exec:
// This catch-all route handles /api/v1/* (matching OpenAI API structure)// @mode worker// @log-level standard
// Handle all /api/v1/* endpoints (chat/completions, embeddings, images, etc.)const apiPath = metadata.parameters.path.join('/'); // e.g., "chat/completions"
const response = await fetch(`https://ai.hoody.com/api/v1/${apiPath}`, { method: req.method, headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: req.method === 'POST' ? JSON.stringify(req.body) : undefined});
const data = await response.json();
// YOUR CUSTOM LOGIC HERE// - Modify prompts// - Add context// - Check cache// - Log for audit// - Request human approval// - Optimize model selection// - Intercept tool calls// - Trigger other agents
return res.json(data);Script file layout
Section titled “Script file layout”Option 1: catch-all route (recommended, handles all AI endpoints)
/hoody/storage/hoody-exec/scripts/default/1/api/v1/[...path].jsThis handles:
POST /api/v1/chat/completionsPOST /api/v1/embeddingsGET /api/v1/models- Any other OpenAI-compatible endpoint
Option 2: specific endpoint (for targeted control)
/hoody/storage/hoody-exec/scripts/default/1/api/v1/chat/completions.jsThis only handles POST /api/v1/chat/completions
Accessing your MITM proxy:
https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1/chat/completionsHow to use:
- Deploy the script (see deployment section below)
- Change base URL in your AI client:
- Normal:
https://ai.hoody.com/api/v1 - With MITM:
https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1
- Normal:
- All requests now flow through your MITM proxy.
Toggle between the two URLs to enable or disable MITM; the client code does not change.
Deploy the MITM script
Section titled “Deploy the MITM script”Prerequisite: container identity token. The examples below use Bearer container-1. Hoody-minted containers are reachable under both a name-derived form (container-<name>) and a numbered form (container-<N>). Replace container-1 with the identifier that matches the container running the script; both forms are equivalent identity tokens, not copyable API keys.
Deploy with the hoody-files API
Section titled “Deploy with the hoody-files API”# Deploy the catch-all MITM proxy (handles all /api/v1/* endpoints)curl -X PUT "https://PROJECT_ID-CONTAINER_ID-files-1.node-us.containers.hoody.com/api/v1/files/hoody/storage/hoody-exec/scripts/default/1/api/v1/%5B...path%5D.js" \ -H "Content-Type: application/octet-stream" \ --data-binary @- << 'EOF'// File: scripts/default/1/api/v1/[...path].js// Catch-all MITM proxy for all OpenAI-compatible endpoints// @mode worker// @log-level standard
// Handle all /api/v1/* endpointsconst apiPath = metadata.parameters.path.join('/');
const response = await fetch(`https://ai.hoody.com/api/v1/${apiPath}`, { method: req.method, headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: req.method === 'POST' ? JSON.stringify(req.body) : undefined});
const data = await response.json();
// YOUR MITM LOGIC HERE// Example: Log all requestsconsole.log(`AI Request: ${req.method} /api/v1/${apiPath}`);console.log(`Model: ${req.body?.model || 'N/A'}`);console.log(`Tokens: ${data.usage?.total_tokens || 'N/A'}`);
return res.json(data);EOFThe proxy is now live at:
https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1/chat/completionsDeploy with the hoody-exec scripts API (recommended)
Section titled “Deploy with the hoody-exec scripts API (recommended)”# Create the script using hoody-exec's script management APIcurl -X POST "https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1/exec/scripts/write" \ -H "Content-Type: application/json" \ -d @- << 'EOF'{ "path": "default/1/api/v1/[...path].js", "content": "// @mode worker\n// @log-level standard\n\nconst apiPath = metadata.parameters.path.join('/');\n\nconst response = await fetch(`https://ai.hoody.com/api/v1/${apiPath}`, {\n method: req.method,\n headers: {\n 'Authorization': 'Bearer container-1',\n 'Content-Type': 'application/json'\n },\n body: req.method === 'POST' ? JSON.stringify(req.body) : undefined\n});\n\nconst data = await response.json();\nconsole.log(`AI Request: ${req.method} /api/v1/${apiPath}`);\n\nreturn res.json(data);"}EOFVerify the deployment
Section titled “Verify the deployment”# Test your MITM proxycurl -X POST "https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1/chat/completions" \ -H "Authorization: Bearer container-1" \ -H "Content-Type: application/json" \ -d '{ "model": "anthropic/claude-haiku-4.0", "messages": [{"role": "user", "content": "Hello!"}] }'A completion response plus log output confirms the proxy is in the path.
Worked examples
Section titled “Worked examples”Human-in-the-loop gating
Section titled “Human-in-the-loop gating”Stop AI from executing high-stakes operations without human approval:
// @mode worker// @log-level standard
const lastMessage = req.body.messages[req.body.messages.length - 1].content;
// Detect high-stakes operationsconst isHighStakes = /deploy|delete|drop|production|payment|transfer/.test( lastMessage.toLowerCase());
if (isHighStakes) { // Store request for approval workflow const requestId = crypto.randomUUID();
// Send notification to human via hoody-notifications await fetch('https://PROJECT_ID-CONTAINER_ID-n-1.node-us.containers.hoody.com/api/v1/notifications/notify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ display: ':1', summary: 'AI Needs Approval', body: `High-stakes operation detected:\n${lastMessage}\nRequest ID: ${requestId}`, urgency: 'critical' }) });
if (!shared.pendingApprovals) shared.pendingApprovals = new Map(); shared.pendingApprovals.set(requestId, req.body);
return res.json({ status: 'pending_approval', requestId, message: 'High-stakes operation detected. Awaiting human approval.', estimatedWait: '2-10 minutes' });}
// Normal flow for safe operationsconst response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
return res.json(await response.json());Agents keep working on their own for routine requests, and the operations matched by the pattern above stop for review. That puts you in the approval path rather than the execution path.
With dozens of agents running across your containers, your work becomes answering the requests they raise: deploy to production, delete this database. You confirm; they execute.
Tool call guardrails
Section titled “Tool call guardrails”AI agents act on the world through tool calls: file operations, command execution, and so on. A MITM script can rewrite those tool calls before the client executes them.
Redirect file operations to sandbox:
// @mode worker
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();
// Intercept tool calls before they executeif (data.choices[0].message.tool_calls) { data.choices[0].message.tool_calls = data.choices[0].message.tool_calls.map(call => { // Redirect dangerous file operations to sandbox if (call.function.name === 'write_file') { const args = JSON.parse(call.function.arguments);
// Force all writes into /sandbox/ directory if (!args.path.startsWith('/sandbox/')) { args.path = '/sandbox' + args.path; call.function.arguments = JSON.stringify(args); } }
// Add safety checks to delete operations if (call.function.name === 'delete_file') { const args = JSON.parse(call.function.arguments);
// Prevent deletion of critical files if (args.path.match(/config|production|\.env|package\.json/)) { // Replace with confirmation tool call.function.name = 'confirm_delete'; call.function.arguments = JSON.stringify({ ...args, warning: 'Critical file deletion requires confirmation' }); } }
// Intercept command execution if (call.function.name === 'execute_command') { const args = JSON.parse(call.function.arguments);
// Block or modify dangerous commands if (args.command.match(/rm -rf|sudo|chmod 777/)) { call.function.name = 'blocked_command'; call.function.arguments = JSON.stringify({ original: args.command, reason: 'Dangerous command intercepted' }); } }
return call; });}
return res.json(data);Net effect:
- The AI can code freely, but file writes are rewritten into the sandbox
- Dangerous operations require explicit confirmation
- Critical files are protected from accidental deletion
- Command injection is prevented
The agent still picks its own tool calls; the proxy decides what those calls are allowed to reach. The script above is about 50 lines.
Agent cascades
Section titled “Agent cascades”Because every service is HTTP, a MITM script can trigger other agents while it handles a request.
Multi-agent coordination:
// @mode worker
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();const aiResponse = data.choices[0].message.content;
// Detect when AI wants to delegate workif (aiResponse.includes('DELEGATE:')) { const taskMatch = aiResponse.match(/DELEGATE: (.+)/); const delegatedTask = taskMatch[1];
// Cascade to another hoody-agent via HTTP (one-shot headless run) const agentResponse = await fetch( 'https://PROJECT_ID-CONTAINER_ID-agent-2.node-us.containers.hoody.com/api/v1/agent/headless/runs', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: delegatedTask, model: 'anthropic/claude-sonnet-4.5' }) } );
const agentData = await agentResponse.json();
// Modify response to indicate delegation data.choices[0].message.content = `Task delegated to Agent-2: ${delegatedTask}\n` + `Job ID: ${agentData.job_id}\n` + `Status: In progress...`;}
// Detect when AI needs specialized capabilitiesif (aiResponse.includes('ANALYZE_CODE:')) { // Trigger code analysis agent await fetch('https://PROJECT_ID-CONTAINER_ID-agent-1.node-us.containers.hoody.com/api/v1/agent/headless/runs', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: 'Analyze codebase for security issues' }) });}
return res.json(data);What this enables:
- Agent swarms: one agent spawns and coordinates ten others
- Specialized agents: route tasks to expert agents (code, security, design)
- Parallel execution: distribute work across several agents at once
- Self-organizing systems: agents discover and coordinate with each other
Example: you ask Agent A to “build a complete SaaS app”. Agent A analyzes, then cascades to:
- Agent B (frontend specialist)
- Agent C (backend specialist)
- Agent D (database specialist)
- Agent E (security auditor)
All of them coordinate over HTTP and report back, orchestrated from one MITM script.
Request stalling with notifications
Section titled “Request stalling with notifications”Pause the AI request until a person reviews and approves it.
// @mode worker// @log-level standard
// Initialize shared stateif (!shared.pendingRequests) { shared.pendingRequests = new Map();}
if (req.body.urgent === true) { const requestId = crypto.randomUUID();
// Store request shared.pendingRequests.set(requestId, { request: req.body, timestamp: Date.now(), status: 'pending' });
// Notify human via hoody-notifications await fetch('https://PROJECT_ID-CONTAINER_ID-n-1.node-us.containers.hoody.com/api/v1/notifications/notify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ display: ':1', summary: 'AI Awaiting Approval', body: `${req.body.messages[req.body.messages.length - 1].content}\nApprove: /api/approve?id=${requestId} — Reject: /api/reject?id=${requestId}`, urgency: 'critical' }) });
// Poll for approval (or use webhook callback) for (let i = 0; i < 300; i++) { // 5 minutes max await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second
const request = shared.pendingRequests.get(requestId); if (request.status === 'approved') { break; } else if (request.status === 'rejected') { return res.status(403).json({ error: 'Request rejected by human' }); } }
// Timeout if no response if (shared.pendingRequests.get(requestId).status === 'pending') { return res.status(408).json({ error: 'Approval timeout' }); }}
// Proceed with AI requestconst response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
return res.json(await response.json());Sequence:
- AI agent wants to deploy to production
- MITM detects high-stakes operation
- Notification sent to the container’s display
- AI request pauses (stalls)
- You review and approve/reject
- AI continues or stops based on your decision
Dozens of agents can run at once while you approve only the decisions that need a person.
Tool call replacement
Section titled “Tool call replacement”A tool call can be replaced outright, so the operation the agent asked for is not the operation that runs.
Example: route every file write through version control:
// @mode worker
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();
// Intercept and replace tool callsif (data.choices[0].message.tool_calls) { for (const call of data.choices[0].message.tool_calls) { // Replace write_file with version-controlled write if (call.function.name === 'write_file') { const args = JSON.parse(call.function.arguments);
// Create git commit for this change await fetch('https://PROJECT_ID-CONTAINER_ID-terminal-1.node-us.containers.hoody.com/api/v1/terminal/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command: `git add ${args.path} && git commit -m "AI: ${args.description || 'auto-save'}"` }) });
// Modify the tool call to include git metadata call.function.arguments = JSON.stringify({ ...args, git_tracked: true, commit_message: `AI: ${args.description || 'auto-save'}` }); }
// Replace read_file to inject AI-generated documentation if (call.function.name === 'read_file') { const args = JSON.parse(call.function.arguments);
// Read actual file via hoody-files const fileResponse = await fetch( `https://PROJECT_ID-CONTAINER_ID-files-1.node-us.containers.hoody.com/api/v1/files${args.path}`, { method: 'GET' } ); const fileContent = await fileResponse.text();
// Ask AI to add inline documentation const docResponse = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'anthropic/claude-haiku-4.0', messages: [{ role: 'user', content: `Add inline documentation to this code:\n${fileContent}` }] }) });
const documented = await docResponse.json();
// Return documented version instead call.function.arguments = JSON.stringify({ ...args, enhanced: true, content: documented.choices[0].message.content }); } }}
return res.json(data);Result:
- Every file write is version controlled
- Every file read comes back with AI-generated documentation
- The agent sees the annotated code context
- You get a full audit trail of the changes
The agent sees no difference. The tool call it issued still returns, but it now runs against version-controlled writes and annotated reads.
Model routing by complexity
Section titled “Model routing by complexity”Route the simpler requests to cheaper models:
// @mode worker
const lastMessage = req.body.messages[req.body.messages.length - 1].content;
// Analyze complexityconst wordCount = lastMessage.split(/\s+/).length;const hasCode = /```|function|class|import|async|await/.test(lastMessage);const hasMultiStep = /step|then|after|finally|workflow/.test(lastMessage);const isDeployment = /deploy|production|release/.test(lastMessage);
// Intelligent model selectionlet selectedModel = req.body.model;
if (isDeployment) { // Critical operations get best model selectedModel = 'anthropic/claude-opus-4.1';} else if (wordCount < 50 && !hasCode && !hasMultiStep) { // Simple question → cheapest model selectedModel = 'anthropic/claude-haiku-4.0';} else if (hasCode || hasMultiStep) { // Complex reasoning → balanced model selectedModel = 'anthropic/claude-sonnet-4.5'; // $3.00/M tokens} else { // General tasks → fast model selectedModel = 'openai/gpt-4o'; // $2.50/M tokens}
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ ...req.body, model: selectedModel // Override with optimal model })});
return res.json(await response.json());Savings: 40-70% when cheaper models handle the simpler requests. Simple tasks do not need an expensive model.
Context injection from a knowledge base
Section titled “Context injection from a knowledge base”Add your own documentation to every prompt:
// @mode worker
// Modules auto-installed on first requireconst { createClient } = require('@supabase/supabase-js');
const supabase = createClient( process.env.SUPABASE_URL, process.env.SUPABASE_KEY);
const userPrompt = req.body.messages[req.body.messages.length - 1].content;
// Semantic search in your knowledge baseconst { data: context } = await supabase .from('documentation') .select('content, source, relevance') .textSearch('content', userPrompt) .order('relevance', { ascending: false }) .limit(3);
// Inject context into system promptconst enhancedMessages = [ { role: 'system', content: `You have access to our internal knowledge base. Relevant context for this request:\n\n${ context.map(c => `**${c.source}**:\n${c.content}`).join('\n\n') }\n\nUse this context to provide accurate, company-specific answers.` }, ...req.body.messages];
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ ...req.body, messages: enhancedMessages })});
return res.json(await response.json());Result: each request carries context retrieved from your own store at call time, whether that store holds documentation, internal wikis, company policies, or codebase notes. The retrieval runs inside the MITM script, so there is no separate RAG service to operate.
Response caching
Section titled “Response caching”Serve repeat requests from cache:
// @mode worker
const { createClient } = require('@supabase/supabase-js');const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY);
// Create cache key from requestconst cacheKey = JSON.stringify({ model: req.body.model, messages: req.body.messages});
// Check cache (using hoody-sqlite for persistence)const { data: cached } = await supabase .from('ai_cache') .select('response') .eq('cache_key', cacheKey) .single();
if (cached) { return res.json({ ...cached.response, cached: true, savings: '100% (from cache)' });}
// Call AIconst response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();
// Store in cacheawait supabase .from('ai_cache') .insert({ cache_key: cacheKey, response: data, created_at: new Date().toISOString() });
return res.json(data);Savings: a cache hit makes no upstream call, so it costs nothing. Useful for:
- Repeated questions (documentation, support)
- Code reviews (similar code patterns)
- Content generation (similar prompts)
Prompt compression
Section titled “Prompt compression”Strip filler before forwarding the prompt:
// @mode worker
function compressPrompt(text) { return text .replace(/\s+/g, ' ') // Normalize whitespace .replace(/\b(the|a|an)\b/gi, '') // Remove articles .replace(/\b(please|kindly|could you)\b/gi, '') // Remove pleasantries .trim();}
// Compress verbose promptsconst compressedMessages = req.body.messages.map(msg => ({ ...msg, content: compressPrompt(msg.content)}));
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ ...req.body, messages: compressedMessages })});
return res.json(await response.json());Savings: 20-40% on verbose inputs, without changing what the prompt means.
Advanced patterns
Section titled “Advanced patterns”Request and response logging
Section titled “Request and response logging”Write every call to a log table:
// @mode worker
const { createClient } = require('@supabase/supabase-js');const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY);
const requestId = crypto.randomUUID();const startTime = Date.now();
// Log requestawait supabase.from('ai_logs').insert({ request_id: requestId, container: metadata.executionId, model: req.body.model, prompt: req.body.messages[req.body.messages.length - 1].content, timestamp: new Date().toISOString()});
// Make AI requestconst response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();const duration = Date.now() - startTime;
// Log responseawait supabase.from('ai_logs').update({ response: data.choices[0].message.content, tokens_used: data.usage?.total_tokens, duration_ms: duration, cost: (data.usage?.total_tokens || 0) * 0.000003 // Example cost calculation}).eq('request_id', requestId);
return res.json(data);This gives you:
- A full audit trail of AI interactions
- Token usage per container and project
- Cost tracking
- Request latency
- Records for a compliance review
Multi-provider failover
Section titled “Multi-provider failover”Fall back to your own vendor keys when the gateway fails:
// @mode worker
// Try Hoody AI firstlet response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
// Fallback to direct OpenAI if Hoody AI failsif (!response.ok && response.status >= 500) { response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.OPENAI_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify(req.body) });}
// Fallback to Anthropic if OpenAI failsif (!response.ok && response.status >= 500) { response = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'x-api-key': process.env.ANTHROPIC_KEY, 'anthropic-version': '2023-06-01', 'Content-Type': 'application/json' }, body: JSON.stringify({ model: req.body.model.replace('anthropic/', ''), max_tokens: req.body.max_tokens || 1024, messages: req.body.messages }) });}
return res.json(await response.json());Resilience: a 5xx from one provider moves the request to the next one in the chain.
Response enrichment
Section titled “Response enrichment”Append a plain-language explanation to generated code:
// @mode worker
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();let content = data.choices[0].message.content;
// Detect code blocksif (content.includes('```')) { // Ask another AI to explain the code const explanation = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'anthropic/claude-haiku-4.0', // Cheap model for simple task messages: [{ role: 'user', content: `Explain this code in simple terms:\n${content}` }] }) });
const explainData = await explanation.json();
// Append explanation content += '\n\n**How this works:**\n' + explainData.choices[0].message.content; data.choices[0].message.content = content;}
return data;Desktop alerts on a container display
Section titled “Desktop alerts on a container display”Raise desktop notifications about AI activity on a container display with hoody-notifications:
// @mode worker
const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();
// Detect significant eventsconst aiResponse = data.choices[0].message.content;const isCodeGeneration = aiResponse.includes('```') && aiResponse.length > 500;const isError = data.error || data.choices[0].finish_reason === 'error';
if (isCodeGeneration) { // Notify about large code generation await fetch('https://PROJECT_ID-CONTAINER_ID-n-1.node-us.containers.hoody.com/api/v1/notifications/notify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ display: ':1', summary: 'AI Generated Code', body: `AI just wrote ${aiResponse.length} characters of code`, urgency: 'normal', icon: 'code' }) });}
if (isError) { // Alert about AI errors await fetch('https://PROJECT_ID-CONTAINER_ID-n-1.node-us.containers.hoody.com/api/v1/notifications/notify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ display: ':1', summary: 'AI Request Failed', body: data.error?.message || 'Unknown error', urgency: 'critical', icon: 'warning' }) });}
// Track token usage and alert on thresholdif (data.usage?.total_tokens > 50000) { await fetch('https://PROJECT_ID-CONTAINER_ID-n-1.node-us.containers.hoody.com/api/v1/notifications/notify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ display: ':1', summary: 'High Token Usage', body: `Request used ${data.usage.total_tokens} tokens`, urgency: 'normal' }) });}
return res.json(data);What this covers:
- Notification when the AI generates a large amount of code
- Alerts on AI errors or rate limits
- High token usage, reported as it happens
- Agent activity visible from any open display session
- Confirmation when a critical operation completes
Alerts land on the container displays you already have open, so nothing has to sit and watch the logs.
Prompt history in SQLite
Section titled “Prompt history in SQLite”Store every AI interaction in a database, using Bun’s built-in SQLite under /hoody/databases/ for concurrent-write safety:
// @mode worker
// Use Bun's built-in sqlite3 (no npm install needed with Bun)const { Database } = require('bun:sqlite');
// A database in /hoody/databases/ is concurrent-write safe: the SQLite Drive// FUSE mount coordinates writes and prevents corruption from concurrent writersconst db = new Database('/hoody/databases/ai-history.db');
// Create table on first runif (!shared.initialized) { db.run(` CREATE TABLE IF NOT EXISTS prompts ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, container TEXT, model TEXT, prompt TEXT, response TEXT, tokens INTEGER, cost REAL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `);
db.run('CREATE INDEX IF NOT EXISTS idx_timestamp ON prompts(timestamp DESC)'); db.run('CREATE INDEX IF NOT EXISTS idx_model ON prompts(model)'); db.run('CREATE INDEX IF NOT EXISTS idx_container ON prompts(container)');
shared.initialized = true;}
// Make AI requestconst response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer container-1', 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
const data = await response.json();
// Store complete interaction in database (concurrent-write safe)db.run(` INSERT INTO prompts (timestamp, container, model, prompt, response, tokens, cost) VALUES (?, ?, ?, ?, ?, ?, ?)`, [ new Date().toISOString(), metadata.executionId || 'default', req.body.model, req.body.messages[req.body.messages.length - 1].content, data.choices[0].message.content, data.usage?.total_tokens || 0, (data.usage?.total_tokens || 0) * 0.000003 // Example cost calc]);
return res.json(data);Why /hoody/databases/ matters here:
- Multiple containers can log simultaneously without corruption
- AI agents making parallel requests all write safely
- FUSE mount coordinates writes automatically
- Zero locking errors even under heavy concurrent load
See: SQLite Drive for full details on concurrent-write safety.
Query your AI history:
# View recent promptsbun -e 'const db = require("bun:sqlite").Database("/hoody/databases/ai-history.db"); console.log(db.query("SELECT model, prompt, tokens FROM prompts ORDER BY created_at DESC LIMIT 10").all())'
# Total tokens used per modelbun -e 'const db = require("bun:sqlite").Database("/hoody/databases/ai-history.db"); console.log(db.query("SELECT model, SUM(tokens) as total FROM prompts GROUP BY model").all())'
# Most expensive queriesbun -e 'const db = require("bun:sqlite").Database("/hoody/databases/ai-history.db"); console.log(db.query("SELECT prompt, cost FROM prompts ORDER BY cost DESC LIMIT 5").all())'
# Usage by containerbun -e 'const db = require("bun:sqlite").Database("/hoody/databases/ai-history.db"); console.log(db.query("SELECT container, COUNT(*) as requests, SUM(tokens) as tokens FROM prompts GROUP BY container").all())'What the history is good for:
- Audit trails: a complete record of AI interactions
- Cost analytics: spending by model, container, and time period
- Pattern analysis: frequently repeated prompts worth caching
- Debugging: the exact prompt and response behind an issue
- Compliance: detailed logs for regulatory requirements
- Training data: prompt history as a corpus for fine-tuning
Route to any provider
Section titled “Route to any provider”The script runs on your infrastructure, so nothing forces the upstream to be Hoody AI.
// @mode worker
// Route to OpenAI directlyconst response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.OPENAI_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify(req.body)});
return res.json(await response.json());
// Or use any other provider:// - Anthropic directly// - Together AI// - Your own self-hosted models (Ollama, LM Studio)// - Multiple providers with custom routing logicYou decide:
- Which provider for which tasks
- When to use Hoody AI vs your own keys
- How to distribute load
- Where costs should go
Use Cases
Section titled “Use Cases”Guardrails for Vibe Coding
Section titled “Guardrails for Vibe Coding”Let the AI generate whole applications, with guardrails around what it can touch:
// Sandbox all AI file operationsif (call.function.name === 'write_file') { args.path = '/sandbox' + args.path;}
// Block dangerous commandsif (call.function.name === 'execute_command') { if (args.command.match(/rm -rf|sudo|chmod 777/)) { return blocked(); }}Multi-tenant AI SaaS
Section titled “Multi-tenant AI SaaS”Each customer’s AI access runs through the same proxy:
const customer = getCustomerFromContainer(metadata.parameters.tenant);
// Customer-specific quota enforcementif (customer.tokensUsedToday > customer.quota) { return res.status(429).json({ error: 'Quota exceeded' });}
// Customer-specific model restrictionsif (!customer.allowedModels.includes(req.body.model)) { req.body.model = customer.defaultModel;}Per-environment rules
Section titled “Per-environment rules”Different MITM rules for development and production:
// Development: Log everything, use cheap models// (pass ?env=dev / ?env=prod — surfaced via metadata.parameters)if (metadata.parameters.env === 'dev') { console.log('Request:', req.body); req.body.model = 'anthropic/claude-haiku-4.0';}
// Production: Route to best model, alert on errorsif (metadata.parameters.env === 'prod') { req.body.model = 'anthropic/claude-opus-4.1'; // monitorForErrors() implementation}Best Practices
Section titled “Best Practices”Layer the MITM logic
Section titled “Layer the MITM logic”Chain several MITM proxies rather than doing everything in one script:
App → MITM Layer 1 (logging) → MITM Layer 2 (caching) → MITM Layer 3 (model routing) → Hoody AIEach layer does one thing, so you can add or remove a layer without touching the others.
Store state in hoody-sqlite
Section titled “Store state in hoody-sqlite”Store caches, approval requests, logs in hoody-sqlite:
// Persistent cache across restartsawait fetch('https://PROJECT_ID-CONTAINER_ID-sqlite-1.node-us.containers.hoody.com/api/v1/sqlite/kv/batch/set?db=ai-cache.db', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ items: [{ key: cacheKey, value: aiResponse }] })});Measure the added latency
Section titled “Measure the added latency”A MITM proxy adds latency to every call. Measure it:
const start = Date.now();const response = await fetch('https://ai.hoody.com/api/v1/chat/completions', { /* ... */ });const latency = Date.now() - start;
if (latency > 1000) { console.warn('MITM proxy slow:', latency, 'ms');}Add layers incrementally
Section titled “Add layers incrementally”- Log requests.
- Add caching.
- Add model routing.
- Add human approval for high-stakes operations.
- Add the agent cascade.
Troubleshooting
Section titled “Troubleshooting”MITM proxy is not called
Section titled “MITM proxy is not called”Problem: Requests bypass your proxy
Solution: Ensure apps point to your hoody-exec endpoint:
https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1NOT: https://ai.hoody.com/api/v1Tool call changes have no effect
Section titled “Tool call changes have no effect”Problem: Modifications to tool_calls don’t take effect
Solution: Return the modified data before the tool executes:
// Correct: Modify in response, before tool executiondata.choices[0].message.tool_calls = modified;return res.json(data);
// Wrong: Trying to modify after executionCached responses are stale
Section titled “Cached responses are stale”Problem: Cached responses are stale
Solution: Add cache invalidation:
const cacheKey = `${model}:${JSON.stringify(messages)}:${Math.floor(Date.now() / 3600000)}`;// Key changes every hour, auto-invalidatesApproval requests time out
Section titled “Approval requests time out”Problem: Stalled requests time out before a person responds
Solution: Increase timeout or implement webhook callback:
// Webhook approach (better):// 1. Store request// 2. Send notification with callback URL// 3. Return immediately with "pending" status// 4. Human approves via webhook// 5. Agent polls or receives eventWhat’s Next
Section titled “What’s Next”Build a proxy:
- hoody-exec Documentation → - Deploy custom MITM proxy scripts
- Script Execution → - API reference for hoody-exec
Related concepts:
- The HTTP Revolution → - Why HTTP enables MITM capabilities
- Security Model → - How MITM fits into Hoody’s security
- Hoody AI Overview → - Understanding the AI gateway architecture