Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
A comprehensive collection of Agent Skills for context engineering, multi-agent architectures, and production agent systems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
skills/hosted-agents/references/infrastructure-patterns.md
1# Infrastructure Patterns for Hosted Agents23This reference provides detailed implementation patterns for building hosted agent infrastructure. These patterns are derived from production systems at scale.45## Sandbox Architecture67### Modal Integration Pattern89Modal provides the sandbox infrastructure with near-instant startup and filesystem snapshots.1011```python12import modal1314# Define the base image with all dependencies15image = modal.Image.debian_slim().pip_install([16"opencode",17"gitpython",18"psycopg2-binary",19])2021# Create the app22app = modal.App("coding-agent")2324# Sandbox class with snapshot support25@app.cls(image=image, timeout=3600)26class AgentSandbox:27def __init__(self, repo_url: str, snapshot_id: str = None):28self.repo_url = repo_url29self.snapshot_id = snapshot_id3031@modal.enter()32def setup(self):33if self.snapshot_id:34# Restore from snapshot35modal.Sandbox.restore(self.snapshot_id)36else:37# Fresh setup from image38self._clone_and_setup()3940def _clone_and_setup(self):41"""Clone repo and run initial setup."""42token = self._get_github_app_token()43os.system(f"git clone https://x-access-token:{token}@github.com/{self.repo_url}")44os.system("npm install")45os.system("npm run build")4647@modal.method()48def execute_prompt(self, prompt: str, user_identity: dict) -> dict:49"""Execute a prompt in the sandbox."""50# Update git config for this user51os.system(f'git config user.name "{user_identity["name"]}"')52os.system(f'git config user.email "{user_identity["email"]}"')5354# Run the agent55result = self.agent.run(prompt)5657return {58"result": result,59"snapshot_id": modal.Sandbox.snapshot()60}61```6263### Image Build Pipeline6465Build images on a schedule to keep them fresh:6667```python68import schedule69import time70from datetime import datetime7172class ImageBuilder:73def __init__(self, repositories: list[str]):74self.repositories = repositories75self.images = {}7677def build_all_images(self):78"""Build images for all repositories."""79for repo in self.repositories:80try:81image = self._build_image(repo)82self.images[repo] = {83"image": image,84"built_at": datetime.utcnow(),85"commit": self._get_latest_commit(repo)86}87except Exception as e:88# Log but continue with other repos89log.error(f"Failed to build image for {repo}: {e}")9091def _build_image(self, repo: str) -> str:92"""Build a single repository image."""93sandbox = modal.Sandbox.create()9495# Clone with app token96token = get_app_installation_token(repo)97sandbox.exec(f"git clone https://x-access-token:{token}@github.com/{repo} /workspace")9899# Install dependencies100sandbox.exec("cd /workspace && npm install")101102# Run build103sandbox.exec("cd /workspace && npm run build")104105# Warm caches106sandbox.exec("cd /workspace && npm run dev &")107time.sleep(5) # Let dev server start108sandbox.exec("cd /workspace && npm test -- --run")109110# Create snapshot111return sandbox.snapshot()112113def get_latest_image(self, repo: str) -> str:114"""Get the most recent image for a repository."""115if repo not in self.images:116raise ValueError(f"No image available for {repo}")117return self.images[repo]["image"]118119# Schedule builds every 30 minutes120builder = ImageBuilder(["org/frontend", "org/backend", "org/shared"])121schedule.every(30).minutes.do(builder.build_all_images)122```123124### Warm Pool Management125126Maintain pre-warmed sandboxes for instant session starts:127128```python129from collections import defaultdict130from dataclasses import dataclass131from datetime import datetime, timedelta132133@dataclass134class WarmSandbox:135sandbox_id: str136repo: str137created_at: datetime138image_version: str139is_claimed: bool = False140141class WarmPoolManager:142def __init__(self, target_pool_size: int = 3):143self.target_size = target_pool_size144self.pools = defaultdict(list) # repo -> [WarmSandbox]145self.max_age = timedelta(minutes=25) # Expire before next image build146147def get_warm_sandbox(self, repo: str) -> WarmSandbox | None:148"""Get a pre-warmed sandbox if available."""149pool = self.pools[repo]150151for sandbox in pool:152if not sandbox.is_claimed and self._is_valid(sandbox):153sandbox.is_claimed = True154return sandbox155156return None157158def _is_valid(self, sandbox: WarmSandbox) -> bool:159"""Check if sandbox is still valid."""160age = datetime.utcnow() - sandbox.created_at161current_image = self.image_builder.get_latest_image(sandbox.repo)162163return (164age < self.max_age and165sandbox.image_version == current_image166)167168def maintain_pool(self, repo: str):169"""Ensure pool has target number of warm sandboxes."""170# Remove expired sandboxes171self.pools[repo] = [s for s in self.pools[repo] if self._is_valid(s)]172173# Add new sandboxes to reach target174current_count = len([s for s in self.pools[repo] if not s.is_claimed])175needed = self.target_size - current_count176177for _ in range(needed):178sandbox = self._create_warm_sandbox(repo)179self.pools[repo].append(sandbox)180181def _create_warm_sandbox(self, repo: str) -> WarmSandbox:182"""Create a new warm sandbox from latest image."""183image = self.image_builder.get_latest_image(repo)184sandbox_id = modal.Sandbox.create(image=image)185186# Sync to latest (runs in background)187self._sync_to_latest(sandbox_id, repo)188189return WarmSandbox(190sandbox_id=sandbox_id,191repo=repo,192created_at=datetime.utcnow(),193image_version=image194)195```196197## API Layer Patterns198199### Cloudflare Durable Objects for Session State200201Each session gets its own Durable Object with isolated SQLite:202203```typescript204// Session Durable Object205export class SessionDO implements DurableObject {206private storage: DurableObjectStorage;207private sql: SqlStorage;208private connections: Map<string, WebSocket> = new Map();209210constructor(ctx: DurableObjectState) {211this.storage = ctx.storage;212this.sql = ctx.storage.sql;213this.initializeSchema();214}215216private initializeSchema() {217this.sql.exec(`218CREATE TABLE IF NOT EXISTS messages (219id INTEGER PRIMARY KEY,220role TEXT NOT NULL,221content TEXT NOT NULL,222author_id TEXT,223author_name TEXT,224created_at TEXT DEFAULT CURRENT_TIMESTAMP225);226227CREATE TABLE IF NOT EXISTS artifacts (228id INTEGER PRIMARY KEY,229type TEXT NOT NULL,230path TEXT,231content TEXT,232created_at TEXT DEFAULT CURRENT_TIMESTAMP233);234235CREATE TABLE IF NOT EXISTS events (236id INTEGER PRIMARY KEY,237type TEXT NOT NULL,238data TEXT,239created_at TEXT DEFAULT CURRENT_TIMESTAMP240);241`);242}243244async fetch(request: Request): Promise<Response> {245const url = new URL(request.url);246247if (request.headers.get("Upgrade") === "websocket") {248return this.handleWebSocket(request);249}250251switch (url.pathname) {252case "/message":253return this.handleMessage(request);254case "/status":255return this.getStatus();256default:257return new Response("Not found", { status: 404 });258}259}260261private handleWebSocket(request: Request): Response {262const pair = new WebSocketPair();263const [client, server] = Object.values(pair);264265const connectionId = crypto.randomUUID();266this.connections.set(connectionId, server);267268server.accept();269server.addEventListener("close", () => {270this.connections.delete(connectionId);271});272273return new Response(null, { status: 101, webSocket: client });274}275276private broadcast(message: object) {277const data = JSON.stringify(message);278for (const ws of this.connections.values()) {279ws.send(data);280}281}282283async handleMessage(request: Request): Promise<Response> {284const { content, author } = await request.json();285286// Store message287this.sql.exec(288`INSERT INTO messages (role, content, author_id, author_name) VALUES (?, ?, ?, ?)`,289["user", content, author.id, author.name]290);291292// Broadcast to all connected clients293this.broadcast({294type: "message",295role: "user",296content,297author,298});299300// Forward to sandbox for processing301const result = await this.forwardToSandbox(content, author);302303return Response.json(result);304}305}306```307308### Real-Time Event Streaming309310Stream events from sandbox to all connected clients:311312```typescript313class EventStream {314private sessionDO: DurableObjectStub;315316async streamFromSandbox(sandboxId: string, sessionId: string) {317const sandbox = await modal.Sandbox.get(sandboxId);318319// Subscribe to sandbox events320for await (const event of sandbox.events()) {321// Forward to Durable Object for broadcast322await this.sessionDO.fetch(323new Request(`https://internal/event`, {324method: "POST",325body: JSON.stringify({326type: event.type,327data: event.data,328}),329})330);331}332}333}334```335336## Client Integration Patterns337338### Slack Bot with Repository Classification339340```python341from slack_bolt import App342from slack_bolt.adapter.socket_mode import SocketModeHandler343344app = App(token=os.environ["SLACK_BOT_TOKEN"])345346# Repository descriptions for classification347REPO_DESCRIPTIONS = [348{349"name": "frontend-monorepo",350"description": "React frontend application with dashboard, user portal, and admin interfaces",351"hints": ["dashboard", "UI", "component", "page", "frontend"]352},353{354"name": "backend-services",355"description": "Node.js API services including auth, payments, and core business logic",356"hints": ["API", "endpoint", "service", "backend", "database"]357},358{359"name": "mobile-app",360"description": "React Native mobile application for iOS and Android",361"hints": ["mobile", "app", "iOS", "Android", "native"]362}363]364365async def classify_repository(message: str, channel: str, thread: list[str]) -> str:366"""Use fast model to classify which repo the message refers to."""367prompt = f"""Classify which repository this message is about.368369Message: {message}370Channel: #{channel}371Thread context: {' | '.join(thread[-3:])}372373Repositories:374{json.dumps(REPO_DESCRIPTIONS, indent=2)}375376Return ONLY the repository name, or "unknown" if unclear."""377378response = await openai.chat.completions.create(379model="gpt-4o-mini",380messages=[{"role": "user", "content": prompt}],381max_tokens=50382)383384return response.choices[0].message.content.strip()385386@app.event("app_mention")387async def handle_mention(event, say, client):388"""Handle @mentions of the bot."""389channel = event["channel"]390message = event["text"]391thread_ts = event.get("thread_ts", event["ts"])392393# Get thread context if in a thread394thread_messages = []395if "thread_ts" in event:396result = await client.conversations_replies(397channel=channel,398ts=thread_ts399)400thread_messages = [m["text"] for m in result["messages"]]401402# Get channel info for context403channel_info = await client.conversations_info(channel=channel)404channel_name = channel_info["channel"]["name"]405406# Classify repository407repo = await classify_repository(message, channel_name, thread_messages)408409if repo == "unknown":410await say(411text="I'm not sure which repository you're referring to. Could you specify?",412thread_ts=thread_ts413)414return415416# Start session and process417session = await start_session(repo, event["user"])418419await say(420text=f":robot_face: Starting work in `{repo}`...",421thread_ts=thread_ts422)423424result = await session.process(message)425426# Post result with Block Kit formatting427await say(428blocks=format_result_blocks(result),429thread_ts=thread_ts430)431```432433### Chrome Extension DOM Extraction434435Extract DOM structure instead of sending screenshots:436437```typescript438// content-script.ts439interface ElementInfo {440tag: string;441classes: string[];442id?: string;443text?: string;444rect: DOMRect;445reactComponent?: string;446}447448function extractDOMInfo(element: Element): ElementInfo {449// Get React component name if available450let reactComponent: string | undefined;451const fiberKey = Object.keys(element).find((key) =>452key.startsWith("__reactFiber")453);454if (fiberKey) {455const fiber = (element as any)[fiberKey];456reactComponent = fiber?.type?.name || fiber?.type?.displayName;457}458459return {460tag: element.tagName.toLowerCase(),461classes: Array.from(element.classList),462id: element.id || undefined,463text: element.textContent?.slice(0, 100),464rect: element.getBoundingClientRect(),465reactComponent,466};467}468469function extractSelectedArea(selection: DOMRect): ElementInfo[] {470const elements: ElementInfo[] = [];471472// Find all elements within selection bounds473document.querySelectorAll("*").forEach((el) => {474const rect = el.getBoundingClientRect();475if (476rect.top >= selection.top &&477rect.left >= selection.left &&478rect.bottom <= selection.bottom &&479rect.right <= selection.right480) {481elements.push(extractDOMInfo(el));482}483});484485return elements;486}487488// Message handler for sidebar489chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {490if (request.type === "EXTRACT_SELECTION") {491const elements = extractSelectedArea(request.selection);492sendResponse({ elements });493}494});495```496497## Multiplayer Implementation498499### Authorship Tracking500501Track which user made each change:502503```python504@dataclass505class PromptContext:506content: str507author: Author508session_id: str509timestamp: datetime510511@dataclass512class Author:513id: str514name: str515email: str516github_token: str # For PR creation517518class MultiplayerSession:519def __init__(self, session_id: str):520self.session_id = session_id521self.participants: dict[str, Author] = {}522self.prompt_queue: list[PromptContext] = []523524def add_participant(self, author: Author):525"""Add a participant to the session."""526self.participants[author.id] = author527self.broadcast_event("participant_joined", author)528529async def process_prompt(self, prompt: PromptContext):530"""Process prompt with author attribution."""531# Update git config for this author532await self.sandbox.exec(533f'git config user.name "{prompt.author.name}"'534)535await self.sandbox.exec(536f'git config user.email "{prompt.author.email}"'537)538539# Run agent540result = await self.agent.run(prompt.content)541542# If changes were made, create PR with author's token543if result.has_changes:544await self.create_pr(545branch=result.branch,546author=prompt.author547)548549return result550551async def create_pr(self, branch: str, author: Author):552"""Create PR using the author's GitHub token."""553async with aiohttp.ClientSession() as session:554headers = {555"Authorization": f"Bearer {author.github_token}",556"Accept": "application/vnd.github.v3+json"557}558559await session.post(560f"https://api.github.com/repos/{self.repo}/pulls",561headers=headers,562json={563"title": self.generate_pr_title(),564"body": self.generate_pr_body(),565"head": branch,566"base": "main"567}568)569```570571## Metrics and Monitoring572573### Key Metrics to Track574575```python576from dataclasses import dataclass577from datetime import datetime, timedelta578579@dataclass580class SessionMetrics:581session_id: str582started_at: datetime583first_token_at: datetime | None584completed_at: datetime | None585pr_created: bool586pr_merged: bool587prompts_count: int588participants_count: int589590@property591def time_to_first_token(self) -> timedelta | None:592if self.first_token_at:593return self.first_token_at - self.started_at594return None595596class MetricsAggregator:597def get_adoption_metrics(self, period: timedelta) -> dict:598"""Get adoption metrics for a time period."""599sessions = self.get_sessions_in_period(period)600601total_prs = sum(1 for s in sessions if s.pr_created)602merged_prs = sum(1 for s in sessions if s.pr_merged)603604return {605"total_sessions": len(sessions),606"prs_created": total_prs,607"prs_merged": merged_prs,608"merge_rate": merged_prs / total_prs if total_prs > 0 else 0,609"avg_time_to_first_token": self._avg_ttft(sessions),610"unique_users": len(set(s.author_id for s in sessions)),611"multiplayer_sessions": sum(6121 for s in sessions if s.participants_count > 1613)614}615616def get_repository_metrics(self) -> dict[str, dict]:617"""Get metrics broken down by repository."""618metrics = {}619620for repo in self.repositories:621repo_sessions = self.get_sessions_for_repo(repo)622total_prs = self.get_total_prs(repo)623agent_prs = sum(1 for s in repo_sessions if s.pr_merged)624625metrics[repo] = {626"agent_pr_percentage": agent_prs / total_prs * 100,627"session_count": len(repo_sessions),628"avg_prompts_per_session": sum(629s.prompts_count for s in repo_sessions630) / len(repo_sessions)631}632633return metrics634```635636## Security Considerations637638### Sandbox Isolation639640```python641class SandboxSecurityConfig:642"""Security configuration for sandboxes."""643644# Network restrictions645allowed_hosts = [646"github.com",647"api.github.com",648"registry.npmjs.org",649"pypi.org",650]651652# Resource limits653max_memory_mb = 4096654max_cpu_cores = 2655max_disk_gb = 10656max_runtime_hours = 4657658# Secrets handling659secrets_to_inject = [660"GITHUB_APP_TOKEN",661"NPM_TOKEN",662]663664# Blocked operations665blocked_commands = [666"curl", # Use fetch tools instead667"wget",668"ssh",669]670```671672### Token Handling673674```python675class TokenManager:676"""Manage tokens for GitHub operations."""677678def get_app_installation_token(self, repo: str) -> str:679"""Get short-lived token for repo access."""680# Token expires in 1 hour681return github_app.create_installation_token(682installation_id=self.get_installation_id(repo),683permissions={"contents": "write", "pull_requests": "write"}684)685686def get_user_token(self, user_id: str) -> str:687"""Get user's OAuth token for PR creation."""688# Stored encrypted, decrypted at runtime689encrypted = self.storage.get(f"user_token:{user_id}")690return self.decrypt(encrypted)691```692693## References694695- [Modal Documentation](https://modal.com/docs)696- [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/)697- [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/)698- [GitHub Apps Authentication](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app)699- [Slack Bolt for Python](https://slack.dev/bolt-python/)700- [Chrome Extension APIs](https://developer.chrome.com/docs/extensions/)701