Skip to main content

Digital FTE बनाना: 4-hour crash course

15 concepts और एक worked build: Skills, system of record, और इनके बीच MCP wire.

यह Mode 2, Manufacturing track का दूसरा course है। यह सात में से दूसरी move है: आपने जो agent पहले बनाया था, उसे agent से AI Worker की तरफ़ पहला real step देते हैं। पिछला course, Build AI Agents, agent खुद बनाता था: sessions, guardrails, और tracing वाला streaming chat agent, जो compute के लिए sandbox पर run होता था। वह काम करता था। लेकिन terminal बंद करते ही वह सब भूल जाता था, और उसके सारे tools उसके Python में ही लिखे हुए थे।

पहले इसे काम करते देखना चाहते हैं? नीचे 15-minute Quick Win पर जाएँ। आप एक real database और छोटा Worker बनाएँगे जो उसमें write करता है और याद रखता है, फिर वापस आकर वे concepts पढ़ेंगे जो बताते हैं कि इसकी shape ऐसी क्यों है।

AI Worker वही chat agent है, बस बड़ा हो चुका। लोग इसे AI Employee या Digital FTE भी कहते हैं: एक ही चीज़, जिसे उसके build होने के तरीके, जिस team में वह जुड़ता है, और उसकी cost के आधार पर नाम दिया जाता है। यह course उसकी foundation बनाता है: ऐसा agent जिसे आप grow कर सकते हैं, जो याद रखता है, और जिसकी ownership आपके पास है। पूरा Worker round the clock भी run करता है, अपने आप act करता है, और किसी भी app पर आप तक पहुँचता है, लेकिन वह बाद में आएगा। पिछले course का SDK और SandboxAgent runtime वही रहता है; उसके चारों ओर की चीज़ें बदलती हैं।

यह बदलाव दो moves और उनके बीच एक wire से होता है:

  • इसकी abilities, Skills बन जाती हैं: छोटे folders जिन्हें agent खुद find और load करता है, बजाय इसके कि tools उसके Python में hard-wired हों।
  • जो चीज़ें restart पर भूल जाती थीं, वे Postgres, उसके system of record, में चली जाती हैं: एक authoritative store जिसके against Worker run करता है, business जिस source of truth पर चलता है, CRM या ledger की तरह। इसमें कुछ तरह का data रहता है:
    • Business records: operational truth. Customers, tickets, orders. इन्हें आप look up और update करते हैं।
    • Reference library: knowledge जिसे वह meaning से search करता है। Policy library, reference documents, past cases.
    • State: अभी काम कैसा दिख रहा है। कौन सी chats open हैं, approval के लिए क्या waiting है।
    • Trace: उसने क्या किया, इसका record, ताकि company उसके actions replay और trust कर सके।
  • MCP (the Model Context Protocol) agents को outside tools और data से connect करने का open standard है। यहाँ यह वही wire है जिससे agent उस store तक पहुँचता है।

Agent से AI Worker तक: agent का runtime वही रहता है; उसकी capabilities उन Skills में बाहर चली जाती हैं जिन्हें वह खुद load करता है, और वे चीज़ें जिन्हें उसे भूलना नहीं चाहिए Postgres में बाहर चली जाती हैं, जहाँ उसका system of record, state और reference library रहती है, जिन तक वह MCP से पहुँचता है.

Semantic recall वह एक चीज़ है जिसे लोग गलत label करते हैं। इसका मतलब exact words से नहीं, meaning से चीज़ें find करना है। यह search करने का एक तरीका है, अपना अलग store नहीं: आप इसे reference library, past conversations, या खुद business records पर run कर सकते हैं। यह pgvector से आता है, जो Postgres में search-by-meaning जोड़ता है।

Worker कैसे run करता है: harness vs. compute (यहाँ आप किसी को deploy नहीं करते)

Running Worker के दो parts होते हैं जिन्हें production अलग-अलग deploy करता है। Harness agent का runtime है: SDK loop खुद। Compute वह sandbox है जहाँ agent का code सच में run होता है; जब agent कोई tool call करता है, तो वह code उस sandbox को hand off करता है। इस course में दोनों local रहते हैं। UnixLocalSandboxClient आपकी machine पर sandbox run करता है (zero infrastructure, one API key), और आप एक-line change से इसे Docker, Cloudflare, E2B, या Modal की तरफ़ point कर सकते हैं (Part 5 का Swap guide)। Harness को खुद always-on cloud service की तरह deploy करना अपना अलग course है, Deploy Your Agent Harness to the Cloud.

यह course Agent Factory thesis में कहाँ बैठता है

Thesis Seven Invariants का नाम देता है जिन्हें हर production agent system को satisfy करना होता है। पिछले course ने engine (Invariant 4) बनाया था: sandbox पर OpenAI Agents SDK. यह course Invariant 5: every Worker runs against a system of record जोड़ता है। Engine वह है जिस पर Worker run करता है; system of record वह है जिसके against वह run करता है।

दो open standards इसे portable रखते हैं। Skills (शुरुआत में Anthropic से, अब agentskills.io पर ecosystem-wide) capabilities को tools के बीच travel करने देते हैं। MCP वह standard wire है जिससे agent record तक पहुँचता है; पिछले course में यह नहीं था, और यहाँ यही key new pattern है। Record खुद Neon Postgres + pgvector है, जिसे इसलिए चुना गया है कि यह शुरू करने के लिए free है, idle होने पर zero तक scale करता है, और official MCP server ship करता है। Product replaceable है; Swap guide alternatives list करता है।

ये 15 concepts तीन layers में split हैं: Skills, system of record, और MCP. नीचे की table पूरा map है।

15 concepts एक नज़र में (पूरा map देखने के लिए expand करें)
#ConceptLayerयह किस सवाल का जवाब देता है
1Agent Skill क्या हैSkillsReusable capability कहाँ रहती है? एक folder में, SKILL.md plus optional scripts/references.
2Progressive disclosureSkillsSkills को हाथ में रखना cheap क्यों है? Discovery → activation → execution सिर्फ़ वही load करता है जिसकी ज़रूरत हो, जब ज़रूरत हो।
3SKILL.md लिखनाSkillsSkill file में सच में क्या होता है? Metadata, trigger description, operational instructions.
4Skill packaging conventionsSkillsSkills tools के बीच travel कैसे करती हैं? वही folder Claude Code, OpenCode, और किसी भी compliant client में काम करता है।
5Skills compose करनाSkillsछोटे skills को filesystem handoff से chain कब करें और एक बड़ा skill कब लिखें।
6Managed Postgres क्योंSystem of recordकौन सा store "system of record" कहलाने लायक है? जिसमें persistence, branching, governance, और agent के लिए ज़रूरी vector primitives हों।
7Worker का schemaSystem of recordAgent को सच में कौन सी tables चाहिए? Conversations, documents, embeddings, audit log, capability invocations, plus turns के लिए SDK Session.
8pgvector basicsSystem of recordPostgres में semantic search कैसे काम करता है? Embedding column, distance operators, index types.
9Embedding pipelineSystem of recordText queryable vector कैसे बनता है? Chunking, embedding model, re-embed कब करना है।
10Audit trail as disciplineSystem of recordWorker के लिए "reads and writes" का मतलब क्या है? Worker की हर action ऐसी trace छोड़ती है जिसे company replay कर सके।
11MCP क्या है और क्या नहीं हैMCPTools, resources, और prompts के लिए protocol: framework नहीं, service नहीं।
12Neon MCP serverMCPAgent का database interface: यह क्या expose करता है, auth कैसे करता है।
13MCP को Agents SDK से connect करनाMCPSDK का MCP integration: server register कैसे करें, model क्या देखता है, trust boundary कहाँ रहती है।
14Custom MCP serversMCPअपना server कब लिखें बनाम सिर्फ़ @function_tool कब use करें। Decision tree.
15MCP under loadMCPTransport choices, connection pooling, queue कब करना है।

जब आपके पास यह mapping हो जाती है, बाकी mostly mechanics है। Production में failure आम तौर पर इनमें से किसी एक पर trace होता है: Skill discover नहीं हुआ (description बहुत vague), दो Workers system of record पर disagree करते हैं (schema race), या MCP wire events drop करता है (workload के लिए wrong transport). Diagnostic आपको बताता है कि कौन सा है।

यह course किसके लिए है

Intermediate. आपके पास यह होना चाहिए:

  • Ideally Build AI Agents किया हुआ हो, हालांकि अगर आपने उसे skip किया है तो आपका agent base पर उसका end state scaffold कर सकता है।
  • Agentic Coding Crash Course से Plan-mode और rules-file habits.
  • एक PRIMM-AI+ cycle का अनुभव।

यह Python-first sequel है: आप Python या SQL hand-type नहीं करेंगे, आपका agent code लिखेगा और आप steer करेंगे। Parts 2 और 3 dense हो जाते हैं (Pydantic models, asyncpg pools, छोटा custom MCP server), इसलिए वहाँ ज़्यादा back-and-forth expect करें।

Databases में नए हैं? 60-second version

Database information को tables में रखता है। Spreadsheet सोचें: हर row एक चीज़ है (customer, support ticket) और हर column उसके बारे में एक detail है (name, date, status). यहाँ आपको बस यही mental model चाहिए। आप database code खुद नहीं लिखते; आपका agent लिखता है, और ये दो शब्द आपको उसका build पढ़ने में मदद करते हैं।

Currency

May 2026 तक current, openai-agents 0.17.x, mcp SDK, Neon के MCP docs, और pgvector 0.8+ के against verified. Build करते समय versions pin करें; अगर docs और यह page कभी disagree करें, तो Cloudflare Sandbox tutorial और Neon docs authoritative हैं।

यह course आपके general agent का use कैसे करता है

आप direct करते हैं, agent build करता है, और क्योंकि base में AGENTS.md ship होता है जिसे वह open पर पढ़ता है, आपके prompts short रह सकते हैं: बस कहें कि आगे क्या build करना है।


Fifteen-minute quick win: एक बार succeed करें, फिर समझें कि यह क्यों काम किया

उन 15 concepts को पढ़ने से पहले जो बताते हैं कि यह architecture क्यों काम करता है, इसका सबसे छोटा actually-working version build करें। अंत तक आपके पास होगा:

  • fresh Neon project जिसमें दो tables, notes और audit_log, होंगी, जिन्हें आपने MCP के through create किया और console में देखा,
  • minimal AI Worker जिसने अपने save_note tool से एक transaction में दोनों में write किया,
  • और "system of record ने मेरे लिए सच में कुछ किया क्या?" का worked answer: आपकी note और उसकी audit row, एक ही id share करते हुए।

यह prompts की एक screen है: आपका coding agent Neon MCP पर store build करता है, फिर छोटा Worker scaffold करता है जो उसमें write करता है, और आप Worker को याद रखते हुए देखते हैं। Full Worker (आठ decisions, five-table schema) Part 4 में आता है। अगर आपके पास सिर्फ़ एक sitting है, तो यह करें, फिर concepts के लिए वापस आएँ।

इसमें दो planes चलते हैं, और उन्हें अलग रखना पूरा mental model है। आपका coding agent (Claude Code या OpenCode) database को build और inspect करने के लिए Neon MCP use करता है। आप जो Worker build करते हैं, वह runtime पर उसमें write करने के लिए अपना tool use करता है। Worker कभी Neon MCP को touch नहीं करता, और Neon के अपने docs साफ़ कहते हैं कि MCP server "development and testing only" के लिए है, running app में wire करने के लिए नहीं।

एक Neon database पर Quick Win flow, दो planes में. Build plane: आपका coding agent notes और audit_log tables create करने, connection string fetch करने, और Neon console में empty tables दिखाने के लिए Neon MCP use करता है. String .env में DATABASE_URL के रूप में लिखी जाती है. Runtime plane: आपका Worker, save_note function tool वाला SandboxAgent, DATABASE_URL पढ़ता है; "Remember this" कहने से model save_note pick करता है और एक transaction में note plus audit row लिखता है, जिसे आप फिर same id share करते हुए read back करते हैं. Worker कभी Neon MCP call नहीं करता.

Base लें और open करें

Base download करें और folder को अपने general agent में open करें। नीचे दिए prompts से agent setup खुद करता है। यह setup आप एक बार करते हैं: digital-fte/ पूरे course के लिए आपका folder है, Quick Win और Part 4 दोनों के लिए। हर build अपना fresh Neon project (database) provision करता है, लेकिन आप दोबारा download या unzip नहीं करते।

Download digital-fte-base.zip

cd digital-fte
claude

यह base एक capable general agent assume करता है (Claude Code, या Claude Sonnet/Opus, GPT-5, या similar पर चल रहा OpenCode). Smaller model build prompt पर drift करेगा; अगर उसकी पहली plan specific के बजाय vague लगे, तो आगे जाने से पहले stronger one पर switch करें।

Base prep करें (~3 min)

Base rules और wiring ship करता है; skills और आपकी key अगली हैं। अपने agent से setup करवाएँ। यह paste करें:

Read AGENTS.md, then get this base ready: install the skills it lists for whichever agent you are, copy .env.example to .env for me, and tell me exactly what you need from me to bring the Neon and Context7 MCP servers online.

ध्यान दें: agent skill-creator, mcp-builder, और neon-postgres install करता है (आप install run देखते हैं), .env create करता है, फिर आपसे दो चीज़ें माँगता है: .env में paste करने के लिए आपका OPENAI_API_KEY, और OAuth पर Neon authorize करने के लिए एक browser click. Neon free है; अगर account नहीं है, तो neon.com पर लगभग एक minute में sign up करें, या authorization screen पर ही create करें। Install और wiring complete होने पर agent आपसे restart करने को कहता है (exit और relaunch), ताकि new skills और MCP servers load हों; कोई भी mid-session load नहीं होता।

Done when: skills installed हैं, .env में आपकी key है, Neon authorized है, और आपने agent restart कर दिया है ताकि new skills और MCP servers live हों।

Gate: confirm करें कि agent database तक पहुँच सकता है (~1 min)

यह course जो genuinely new चीज़ जोड़ता है, वह है agent का MCP के over real system of record तक पहुँचना। इसलिए कुछ build करने से पहले confirm करें कि boundary live है। यह paste करें:

List the Neon tools you can see.

ध्यान दें: Neon tool names की real list (project create करना, SQL run करना, tables describe करना, वगैरह). यह list database पर agent का hand है, और नीचे की सारी चीज़ इसी पर ride करती है।

Gate open: reply real Neon tool names list करता है। अगर ऐसा नहीं होता: आपने लगभग निश्चित रूप से restart skip किया है, इसलिए tools अभी loaded नहीं हैं। Exit करें, relaunch करें, और फिर पूछें। फिर भी कुछ नहीं? Neon OAuth complete नहीं हुआ: उसे redo करें और retry करें।

Store build करें, और connection string लें (~3 min)

अपने coding agent से Neon MCP के through database create करवाएँ, फिर अपने Worker को वह एक चीज़ दें जिससे वह बाद में पहुँचेगा: connection string.

इसे अपने general agent में paste करें। पहले plan करें; approval पर execute करें।

On a fresh Neon project, create two tables: notes (the note text) and audit_log (a record of what happened). Then call get_connection_string and write that URL into my .env as DATABASE_URL. Use the Neon tools for all of it; don't write SQL for me to run.

ध्यान दें: agent project और दो tables create करने के लिए Neon MCP tools call करता है (आप वे tool calls देखते हैं, न कि वह SQL जो आपने type किया), फिर .env में DATABASE_URL लिखता है। यह string handoff है: Neon MCP ने store provision किया, और आपका Worker string use करेगा, MCP server नहीं।

Done when: fresh Neon project में notes table और audit_log table हैं, और .env में DATABASE_URL है।

अपनी आँखों से देखें (~1 min)

कोई code run होने से पहले Neon console में empty tables देखें। यह "यह सच में वहाँ है" वाला beat है, और इसकी cost एक browser tab है।

Neon console में: अपना project select करें, Tables view open करें, ज़रूरत हो तो databases switch करें, और tables को spreadsheet की तरह पढ़ें.

console.neon.tech open करें, agent ने जो project अभी बनाया उसे pick करें, और Tables open करें। वहाँ notes और audit_log बैठे हैं, अभी empty. Table बस spreadsheet है: हर row एक चीज़, हर column एक detail. अंत में आप यह view refresh करेंगे और row appear होते देखेंगे।

Worker scaffold करें और एक बार run करें (~2 min)

अब Worker खुद build करें: minimal SandboxAgent, वही runtime जो बाकी course use करता है, अभी कोई tools नहीं। इसे empty run करना साबित करता है कि runtime काम करता है और आपकी key good है, इससे पहले कि आप कोई और failing part add करें।

Using uv, scaffold a minimal OpenAI Agents SDK project in this folder: a SandboxAgent on a gpt-5-class model (e.g. gpt-5-mini) with no tools yet, run from the terminal on a local sandbox, reading OPENAI_API_KEY from .env. Run it once with "hello" so I can see it answer.

ध्यान दें: agent uv से project setup करता है, छोटा SandboxAgent plus Runner script लिखता है (UnixLocalSandboxClient पर, zero infrastructure), और उसे run करता है। एक reply वापस आता है।

यह पहली जगह है जहाँ आपकी key use होती है, इसलिए bad key पहली बार यहीं दिखती है। अगर run 401 देता है, तो key गलत है या आपका provider OpenAI नहीं है: paste करें "the run failed with a 401; read the error and propose one fix I can approve."

Done when: empty Worker run होकर answer देता है।

Worker को tool दें, और उसे याद रखते देखें (~3 min)

अब एक capability add करें: ऐसा tool जो note और उसकी audit row को एक transaction में उस database में लिखता है जिसे आपने build किया।

Add a save_note tool to the Worker, written as a @function_tool, that inserts a row into notes and a matching row into audit_log in a single transaction, using the DATABASE_URL in .env. Then run the Worker and send it: "Remember this: the production deploy needs a new env var before Friday." Show me what happened.

ध्यान दें: model आपकी sentence को अपने आप save_note से match करता है (tool की description ही उसका routing signal है), और tool DATABASE_URL से connection खोलकर एक transaction में दोनों rows लिखता है। Worker report करता है कि note saved है। ध्यान दें उसने क्या नहीं किया: वह कभी Neon MCP की तरफ़ नहीं गया। Admin wire ने store बनाया; Worker अपना narrow tool use करता है।

Done when: Worker confirm करता है कि note saved है और आपको वह save_note call दिखाता है जिसने यह किया। एक sentence in, एक tool call, दो rows written.

Win: उसे read back करें (~2 min)

एक moment पहले वाला Neon console Tables view refresh करें। आपकी note अब notes में row है, और matching row audit_log में note_saved record करती है, उसी id से tied. (Terminal में रहना पसंद है? अपने coding agent से पूछें: "using the Neon tools, show me the new notes row and its matching audit_log row side by side.")

यही पूरी architecture miniature में है: truth hold करता system of record, अपना tool use करके उसमें write करने वाला Worker, और replayable audit trail.

आपने क्या बनाया, और यह कहाँ grow करता है

आपने plain @function_tool use किया क्योंकि एक Worker एक store में write करता है, जो सही default है, shortcut नहीं। आप छोटा MCP server तब उठाते हैं जब तीन में से एक चीज़ सामने आए: second consumer जिसे वही save_note चाहिए (दूसरा Worker, आपका coding agent, Claude itself), tighter scope जिसे आप enforce करना चाहते हैं, या process isolation. Function tool बनाम अपना server वाला decision Concept 14 है, और Part 4 server build करता है।

Part 4 इसी shape को कई Skills, five-table schema, कुछ tools, और embedding pipeline तक scale करता है। Shape नहीं बदलती: system of record, same transaction में audit, और admin wire और Worker के अपने access के बीच clean line. अगर यह Quick Win काम कर गया, तो बाकी course बस यह समझाता है कि हर piece की shape ऐसी क्यों है।

अगर कुछ काम नहीं हुआ, तो एक recovery move paste करें जो सब cover करता है: "Something didn't work. Read the error, tell me in plain language what you see, and propose one fix I can approve." फिर यहाँ वापस आएँ।


Part 1: Skills, capability as portable folders

आपने Claude Code के अंदर Skills पहले ही use किए हैं। Part 1 वही on-demand, professional workflows उस agent को देता है जिसे आप build करते हैं। Skill reusable capability है जिसे आप agent को देते हैं: workflow package करने वाला folder (instructions, plus कोई scripts या references), जिसे agent सिर्फ़ task आने पर load करता है, और जो एक agent के code में baked होने के बजाय agents के बीच portable रहता है। ये पाँच concepts आपको ऐसी Skills लिखना सिखाते हैं जो सही समय पर fire हों, और Part 1 आपके Worker के अपने SDK में, उसी digital-fte folder में, एक Skill run करके ख़त्म होता है।

Concept 1: Agent Skill क्या है

Agent Skill ऐसा folder है जिसमें SKILL.md file होती है (plus optional scripts/, references/, assets/). SKILL.md entry point है। यह Anthropic का open standard है जिसे कोई भी agent read कर सकता है: आज Claude Code और OpenCode, और वह OpenAI Agents SDK Worker जिसे आप build कर रहे हैं। सबसे छोटा skill एक file है:

---
name: hello-skill
description: Greets the user by name and time of day. Use when the user says hello or asks to be greeted.
---

# Hello skill

1. Check the local time of day.
2. Greet the user warmly, by name if known, in under 25 words.

कोई code नहीं, कोई deploy नहीं, कोई SDK call नहीं। क्योंकि यह disk पर file है, skill version होता है, travel करता है, और किसी text की तरह review होता है, Python object या API endpoint की तरह नहीं।

PRIMM, Predict. किसी message के आने से पहले startup पर agent क्या load करता है? (a) पूरा SKILL.md; (b) सिर्फ़ name और description; (c) invoked होने तक कुछ नहीं। Confidence 1-5.

Answer (b) है: startup पर agent हर skill की सिर्फ़ metadata पढ़ता है; body on demand load होती है। यही progressive disclosure है, अगला concept.


Concept 2: Progressive disclosure, three-stage loading model

एक साथ 50 skills load करना model को उन instructions में दबा देगा जिनकी उसे ज़रूरत नहीं। इसलिए skill तीन stages में load होता है, और हर stage सिर्फ़ तब fire करता है जब पिछला stage कहता है कि यह relevant है।

Stage 1, Discovery. Startup पर agent हर skill का name और description load करता है, roughly 100 tokens each. 50 skills की cost करीब 5,000 tokens per turn है: library में क्या है जानने की price.

Stage 2, Activation. जब model task को description से match करता है, तो वह पूरा SKILL.md body load करता है (इसे ~5,000 tokens से कम रखें; ज़्यादातर 500-2,000 पर बैठते हैं)। Cost सिर्फ़ उन turns पर लगती है जो skill use करते हैं।

Stage 3, Execution. Body जिन files को reference करता है (कोई scripts/ script, कोई references/ doc), वे सिर्फ़ तब load होती हैं जब agent उन्हें उठाता है।

Progressive disclosure timeline: startup पर सिर्फ़ सभी skills के names और descriptions load होते हैं (cheap, हर turn paid). Activation पर पूरा SKILL.md body load होता है (medium, सिर्फ़ matching turns पर paid). Execution पर referenced files on demand load होती हैं (variable, सिर्फ़ जब reach किया जाए तब paid).

PRIMM, Predict. किसी Worker के पास 30 skills हैं: descriptions ~100 tokens each, bodies ~1,500 tokens, हर skill में दो reference files (~4,000 tokens total). ऐसे turn पर जो एक skill activate करता है और उसकी एक reference read करता है, rough context cost है: (a) ~3,000 tokens; (b) ~6,500 tokens; (c) ~135,000 tokens. Confidence 1-5.

Answer (b), ~6,500 tokens है: discovery के लिए 30 × 100 (3,000), plus एक 1,500-token body, plus एक ~2,000-token reference. Discovery library size के साथ scale करता है; activation और execution per turn constant रहते हैं। Progressive disclosure के बिना आप हर turn पर सभी 30 bodies और उनके references की cost देते, सिर्फ़ यह जानने के लिए कि agent क्या कर सकता है लगभग ~165,000 tokens. कोई इसे run नहीं करता।

दो बातें निकलती हैं, और वे अगले तीन concepts drive करती हैं: description Stage 1 में fire करता है, इसलिए वही सब decide करता है; और long bodies हर matching turn पर cost करते हैं, इसलिए SKILL.md tight रखें और depth को references/ में push करें।


Concept 3: description trigger है, और वही part आपका है

SKILL.md के दो parts होते हैं: YAML frontmatter (contract जिसे model पढ़ता है) और markdown body (instructions जिन्हें वह follow करता है)। सिर्फ़ दो frontmatter fields required हैं:

FieldRequiredयह क्या है
nameYesSkill का identifier (lowercase, hyphens, folder name से match).
descriptionYesTrigger surface: discovery में agent इसे पढ़कर decide करता है कि skill fire करनी है या नहीं।

(license, compatibility, metadata, allowed-tools optional हैं और rarely needed; skill-creator इन्हें fill करता है।)

Description पूरा game है, और scaffold अक्सर यही गलत करता है। वह circular description लिखता है: "Summarizes a ticket into five sections. Use when the user wants to summarize a ticket." यह "summarize this ticket" पर fire होता है, लेकिन support सच में जिस तरह बोलता है उसे miss करता है: "write a handoff note for #4471," "TL;DR this thread," "give my lead the rundown before I escalate." Generic version real phrasings में से लगभग 6 of 8 पकड़ता है; hand-written one सभी 8 पकड़ता है।

Reliably fire करने वाली description तीन चीज़ें करती है, plus एक guardrail:

  • What यह produce करता है (actual output का नाम: पाँच sections, एक ticket पर).
  • When इसे reach करना है (real situations: handoff, escalation, manager को brief करना, किसी और की thread pick करना).
  • Keywords जो users सच में type करते हैं, उनमें वे भी जो obvious word कभी नहीं कहते ("handoff note," "TL;DR this thread," "where does this stand").
  • Do-NOT line उन look-alikes के लिए जहाँ इसे quiet रहना चाहिए (customer reply draft करना, batch triage करना, ticket volume पर report करना).

Circular descriptions मारने वाला self-check: अपनी description से obvious keyword ("summarize") delete करें। क्या यह फिर भी बताती है कि कब fire होना है? अगर नहीं, तो यह बहुत narrow है।

Body, by convention. Required format नहीं है, लेकिन अच्छे skills imperative होते हैं ("Read the full thread. List what was tried."), एक-दो real examples रखते हैं (steering के लिए description से roughly 5x valuable), और दो-तीन edge cases name करते हैं जो सच में टूटे हैं।

PRIMM, Predict. दो skills का same name summarize-document है: एक ~/.claude/skills/ में (user-level), एक .claude/skills/ में (project-level). Task दोनों से match करता है। क्या होगा? (a) random pick; (b) project-level wins; (c) model chooses. Confidence 1-5.

(b), project-level wins Claude Code और OpenCode दोनों में, CLAUDE.md जैसी precedence: ज़्यादा specific context, ज़्यादा general को override करता है।


Concept 4: Packaging, skills कहाँ रहती हैं और travel कैसे करती हैं

Skill disk पर बस folder है, इसलिए आप उसे कहाँ रखते हैं यह decide करता है कि कौन से agents उसे find करेंगे। पूरे course के लिए एक rule काफी है: अपनी skills .claude/skills/ में रखें। Claude Code यह folder पढ़ता है, OpenCode इस पर fallback करता है, और आपके Worker का SDK सीधे इसी पर point करता है (LocalDir(src=".claude/skills"), ऊपर के hands-on से). Skill एक बार लिखें और तीनों वही folder byte-for-byte load करते हैं।

Full path map (per tool, project vs. user-level)
ToolProject-levelUser-level (global)
Claude Code.claude/skills/<name>/SKILL.md~/.claude/skills/<name>/SKILL.md
OpenCode.opencode/skills/<name>/SKILL.md~/.config/opencode/skills/<name>/SKILL.md
OpenCode (fallback).claude/skills/<name>/SKILL.md~/.claude/skills/<name>/SKILL.md

OpenCode पहले अपना folder check करता है, फिर .claude/skills/ पर fallback करता है; Claude Code सिर्फ़ .claude/ पढ़ता है। इसी कारण .claude/skills/ वह one location है जो हर जगह काम करती है।

Skill folder में एक required file और तीन optional folders होते हैं, हर एक का अपना job:

my-skill/
├── SKILL.md # required: frontmatter + body, the entry point
├── scripts/ # optional: code the agent runs (by relative path)
├── references/ # optional: deep docs, loaded on demand, one topic per file
└── assets/ # optional: templates, schemas, lookup tables

SKILL.md के अंदर उन files को relative path से point करें (references/policies/us.md, scripts/extract.py); वे skill के अपने folder से resolve होते हैं, न कि agent जहाँ run कर रहा हो वहाँ से। references/ shallow रखें, one topic per file.


Concept 5: Skills compose करना, एक बड़ा या कई छोटे

"Weekly customer-health report" एक skill हो सकता है जो research, draft, format, और review करता है, या चार skills जो filesystem के through hand off करते हैं। दोनों काम करते हैं, opposite trade-offs के साथ।

  • एक बड़ा skill: discover करना easy, एक activation. लेकिन हर step एक context में run होता है, कुछ भी अकेले reusable नहीं होता, और mid-way failure model को stale work के साथ recover करने पर मजबूर करता है।
  • कई छोटे skills: हर एक को अपने दम पर test, replace, और reuse किया जा सकता है; failure localized होता है; हर step fresh activate होता है, इसलिए leftover context pile up नहीं होता। Cost है ज़्यादा discovery entries और उन्हें chain करने की कोई चीज़।

Composing Skills: monolithic &#39;customer-health-report&#39; Skill एक activation के साथ एक context में चार steps run करता है, जबकि चार small Skills tmp/ files के through hand off करते हैं. Chained version चार activations pay करता है, लेकिन हर एक fresh start करता है, अकेले reuse हो सकता है, और debugging के लिए intermediate artifacts disk पर छोड़ता है.

एक skill लिखें जब steps tightly coupled हों और कभी अकेले reuse न हों। कई लिखें जब कोई step अपने आप call हो सकता हो, या हर step का context clean रखना wiring simple रखने से ज़्यादा important हो। दो या तीन steps के बाद separation आम तौर पर जीतती है।

Conversation से नहीं, filesystem से chain करें। Skill A tmp/research-{id}.md लिखता है, Skill B उसे read करके tmp/draft-{id}.md लिखता है, और ऐसे आगे। Conversation सिर्फ़ final result देखती है; बीच के steps disk पर agent, आप, और audit trail के लिए रहते हैं। वही isolation जो पिछले course ने subagents के लिए use किया था, अब skill size पर।

और यही Part 2 का bridge है: कुछ handoffs temp file में नहीं, system of record में belong करते हैं। tmp/ में write करने वाला skill draft है; system of record में write करने वाला skill action है। यही distinction Part 2 build करता है।

AI के साथ try करें

Compare two designs for a customer-refund workflow:
A: one "issue-refund" skill (eligibility, policy, amount, gateway, ticket, notify).
B: five small skills chained via tmp/ handoffs.

For each, name one situation where it's the right call and one failure mode
it's vulnerable to. Then say which you'd ship, and why.

दोनों runtimes में skill fire करें (~10 min, hands-on)

आपने enough पढ़ लिया; अब जिस agent को आप build करते हैं उसके अंदर skill fire होते देखें। Quick Win वाला वही digital-fte folder open करें, जहाँ आपका SandboxAgent already run करता है। Mechanics familiar करने के लिए throwaway skill पर यह एक बार run करें (real में Decision 4 यही move करता है), और देखें कि Claude Code में पहले से use होने वाली .claude/skills/ files आपके Worker के अपने SDK में भी वैसे ही काम करती हैं।

1. इसे scaffold करें। आपको general agent और Node installed चाहिए (npx के लिए)। यह paste करें:

Use skill-creator to scaffold a summarize-ticket skill. It turns one support ticket into a
short five-section handoff. Make it fire on how support actually asks (handoff note, TL;DR
this thread, "what's the status and next step"), including phrasings that never say
"summarize", and not on look-alikes (drafting a reply, triaging a batch). Then check it:
delete "summarize" from the description; if it no longer says when to fire, sharpen it.

Body अच्छा आएगा; description पढ़ें और sharpen करें जब तक वह delete-the-keyword check pass न कर ले। वही review skill है, और वह part जो कोई scaffold आपके लिए नहीं करता।

2. Client में fire करें (optional, zero wiring). अगर Claude Code या OpenCode installed और signed in है, तो folder वहाँ open करें और "summarize" कहे बिना किसी ticket को handle करने को कहें (जैसे "write a handoff note for case #4471 before I escalate"). Client .claude/skills/ discover करता है, आपकी description match करता है, और summarize-ticket activate करता है। एक caveat: अगर request इतनी simple है कि model skill के बिना ही directly answer कर दे, तो कोई skill fire नहीं होता, और यह model का call है, description bug नहीं; real handoff से test करें, one-line question से नहीं। SDK-only readers step 3 पर skip कर सकते हैं।

3. OpenAI Agents SDK में fire करें। अब skill को अपने Worker runtime में wire करें, और वही तरीका use करें जो Part 4 में हर जगह use होगा: आप prompt देते हैं, agent plan करता है, आप approve करते हैं, वह build और run करता है। आप अभी भी digital-fte folder में हैं, इसलिए uv project और OPENAI_API_KEY carry over करते हैं। यह paste करें:

Wire the summarize-ticket skill into a minimal SandboxAgent I can run from this folder: a Skills capability pointed at .claude/skills, the default capabilities kept, a gpt-5-class model, on a local sandbox. Make sure openai-agents is installed. Plan first.

यह Quick Win जैसा ही SandboxAgent shape है, बस save_note tool को Skills capability से swap किया गया है। gpt-5-class model matter करता है: default capabilities में filesystem tool होता है जिसे smaller models 400 के साथ reject करते हैं। Plan सही लगे तो approve करें और एक ही pass में live-test करें:

Implement it, then run it with "write a handoff note for case #4471: no refund, two weeks" and show me the trace so I can see the skill fire.

Trace में verify करें कि यह fire हुआ। SDK हर run को उसी OpenAI dashboard में trace करता है जिसे आपने पिछले course में use किया था: platform.openai.com/traces open करें और run में summarize-ticket का load_skill call दिखेगा, फिर five-section reply. (Dashboard नहीं है? print loop आपके terminal में वही load दिखाता है।) .claude/skills source है; .agents/ वह जगह है जहाँ loaded skill runtime पर staged होता है। Same file, two runtimes: यही portable capability है, और Decision 8 इसे full Worker में wire करता है।

Less-disciplined models के लिए skills लिखना

ये concepts strong instruction-follower assume करते हैं (Claude Sonnet/Opus, GPT-5-class). Smaller model (deepseek-chat, Haiku-class, ज़्यादातर local models) पर तीन चीज़ें drift करती हैं:

  1. Multi-skill sequencing. "ALWAYS run X before Y" strong models पर land करता है, weak ones पर slip करता है। Fix: order को system prompt के short GENERAL-FLOW preamble में रखें; SKILL bodies declarative रखें।
  2. Format drift. Weaker model emojis, tables, या आपके inputs paraphrase कर देता है। सिर्फ़ क्या करना है नहीं, क्या नहीं करना है भी explicit करें।
  3. Trigger blindness. जो description "summarize ticket TKT-1042" पर fire करती है, वह "what's the story on #1042" miss कर सकती है। Concept 3 की discipline weak model पर और ज़्यादा matter करती है।

Rule of thumb: strong model की effort SKILL.md में budget करें, weak model की effort system prompt में। Architecture hold करती है; आप उसके चारों ओर ज़्यादा scaffolding लिखते हैं।


Part 2: Neon Postgres + pgvector as system of record

Part 1 ने agent को capabilities दीं। अब उसे ऐसी durable जगह चाहिए जहाँ वह वह सब रख सके जिसे भूलना afford नहीं कर सकता: customer record, policy library, past resolved cases, और उसने क्या किया इसका trace.

वही store आपके Worker का system of record है: एक authoritative store जिसके against वह run करता है, business जिस source of truth पर चलता है, CRM या ledger की तरह। यह Postgres है, pgvector extension के साथ; Concept 6 समझाता है कि dedicated vector database के बजाय यह default क्यों है। हम Neon use करते हैं: start करना free, idle होने पर cost नहीं, और आपका coding agent इसे सीधे drive कर सकता है। लेकिन pgvector वाला कोई भी managed Postgres काम करता है।

System of record में कुछ तरह का data रहता है। Business records (customers, orders, tickets) आपके business-specific होते हैं, इसलिए वे Part 4 में बनते हैं। यह Part बाकी shared pieces बनाता है, यानी वे parts जिनकी हर Worker को ज़रूरत होती है:

  • Reference library: knowledge जिसे Worker meaning से search करता है: policy library, knowledge-base articles, past resolved cases की summaries. यह documents और embeddings में रहती है (Concepts 8 और 9).
  • State: live conversation. उसके turns agent SDK की Session में रहते हैं, जिसे SDK खुद create और write करता है, इसलिए आप वे tables design नहीं करते (Concept 7); उसके beside एक conversations row रहती है, session id से linked envelope की तरह: कौन, कब, closing summary.
  • Trace: Worker ने क्या किया, उसका record, यानी audit_log ledger (Concept 10). Optional companion table capability_invocations per-skill और per-tool metrics जोड़ती है।

Concept 6: Managed Postgres क्यों, और specifically Neon क्यों

Thesis systems of record पर product-agnostic रहती है: "AI-Native Company के existing databases, workflows, और operational platforms (CRMs, ERPs, ticketing systems, data warehouses, ledgers) system of record की तरह serve करते हैं।" लेकिन scratch से build किए agent के लिए आपको कुछ pick करना होता है। सवाल "Postgres vs. MongoDB vs. vector DB" नहीं है। सवाल है "कौन सा Postgres."

Postgres क्यों, dedicated vector database क्यों नहीं। तीन कारण 2026 में भी hold करते हैं।

  1. One database, one transaction, one auth boundary. Separate vector DB का मतलब sync में रखने के लिए दो stores, दो auth systems, दो backup pipelines. pgvector vectors को उन records के next to रखता है जिनसे वे relate करते हैं, इसलिए JOIN, JOIN ही रहता है, दो services के बीच network hop नहीं। हर major managed Postgres (AWS RDS, Cloud SQL, Azure, Supabase, Neon) इसे ship करता है, और यह सबसे ज़्यादा installed Postgres extensions में है। ज़्यादातर workloads के लिए यह enough है।

  2. Postgres hard parts पहले से करता है। Transactions, indexes, foreign keys, row-level security, point-in-time recovery, query planning. Dedicated vector DB को ये scratch से invent करने पड़ते हैं और आम तौर पर कुछ में worse होता है। Default boring choice के compounding advantages हैं।

  3. Postgres के लिए MCP servers हर layer पर exist करते हैं। Neon एक ship करता है (management के लिए)। General Postgres MCP servers exist करते हैं (SQL execution के लिए)। आप अपना लिख सकते हैं (scoped runtime access के लिए)। Postgres के around MCP ecosystem सबसे mature है।

Dedicated vector DB कब जीतता है। Pinecone, Weaviate, Qdrant, और Milvus जैसे tools तब worth हैं जब search-by-meaning ही product हो, business data के beside बैठी feature नहीं। Signs extreme होते हैं: इतने vectors कि वे एक Postgres server की memory में fit न हों, search traffic इतना heavy कि vectors-only engine चाहिए, या vectors अपने आप में कई अलग services द्वारा use हों। Pgvector कहाँ give out करता है इसका fixed number नहीं है, इसलिए किसी figure पर trust करने के बजाय अपने data पर test करें। tickets table और उसके beside embeddings वाला Worker उस point के पास भी नहीं है, इसलिए pgvector सही default है।

Specifically Neon क्यों: तीन differentiators.

  • यह scale to zero करता है। Database idle हो तो cost nothing. 50 conversations per day handle करने वाला Worker ज़्यादातर time idle रहता है, इसलिए always-on server के लिए monthly pay करने के बजाय near $0 रहता है। यह तब matter करता है जब आप कई Workers run करते हैं जो each only bursts में busy होते हैं।

  • यह branch करता है। Seconds में Neon आपके live database की full copy बना देता है, original को touch किए बिना। Agent-relevant use: agent को branch पर change try करने दें, और अगर गलत हो जाए तो branch delete कर दें। जिस database में branch नहीं बनती, वहाँ bad change undo करना backup restore है।

  • इसका official MCP server है। Neon एक MCP server ship करता है जिससे आपका coding agent बात कर सकता है, इसलिए वह plain language में projects create, branches manage, और migrations run कर सकता है। Build करते समय use करें; Concept 12 समझाता है कि running Worker के लिए यह क्यों नहीं है।

AI के साथ try करें

A teammate proposes splitting the stores: Postgres for the relational
data (customers, tickets, orders) AND a separate Pinecone index for the
embeddings, "because Pinecone is purpose-built for vectors."

Context for you, the assistant: keeping vectors in Postgres (via the
pgvector extension) next to the relational data means one query can
filter by business state, rank by similarity, and return the full
record in a single transaction. Splitting the stores forces the agent
to round-trip between two services, denormalize and sync metadata
across them, and give up cross-store transactional consistency.

1. Make the case against the split as concretely as you can on ONE
request: a support Worker gets a message and must answer "have we
seen this before, and what did we tell them?" Show exactly what that
request costs when the vectors live in Pinecone and the tickets live
in Postgres. Name the join, what happens to ranking at the LIMIT
boundary when you filter in application code, and how an embedding
goes stale after a resolution is updated.
2. Name the ONE condition under which the teammate is actually right and
a dedicated vector DB is the better call. Be specific about the scale
at which the crossover happens.
3. Neon adds two properties a plain Postgres box doesn't: scale-to-zero
(an idle Worker's database costs nothing) and branching (the agent
forks a production-fidelity copy of the data, experiments or migrates
on it in isolation, then verifies before merging). Which matters more
for an AI Worker specifically, and why? Defend your pick in two
sentences.

Concept 7: Worker का schema, agent को सच में कौन सी tables चाहिए

Database schema बस वे tables और हर table के columns हैं जिन्हें आप रखते हैं, यानी आपके data की shape. Worked example जो पाँच tables बनाता है वे system of record के shared parts हैं जिनकी हर Worker को ज़रूरत होती है; business records खुद Part 4 में आते हैं। वे दो groups में fall करते हैं, ताकि essential और optional साफ़ दिखे।

हर Worker की चार tables, shared spine. ये Part opener वाली state, reference library, और trace को अब tables के रूप में रखती हैं:

  • conversations (state): हर conversation के लिए एक row, कौन था, कब था, और अंत में short summary. Turn-by-turn messages अलग stored होते हैं, SDK द्वारा; नीचे देखें।
  • documents और embeddings (reference library): documents text रखता है (policies, past cases); embeddings उसे meaning से searchable बनाता है। Embedding text के piece को numbers की list में बदलती है जो उसका topic capture करती है, इसलिए related text पास-पास आता है, जैसे board पर similar notes cluster हों, और "find relevant" का मतलब "find nearest" बन जाता है। Concept 9 इसे build करता है; अभी बस जानें कि embeddings search-by-meaning layer है।
  • audit_log (trace): Worker ने क्या किया इसका running record, हर action order में, जिसमें refund issue होने जैसे business events भी शामिल हैं।

एक और table, जब आपको usage analytics चाहिए।

  • capability_invocations: हर बार Worker कोई skill run करता है या tool call करता है तो एक row. दोनों इसी table को share करते हैं; एक column mark करता है कि कौन सा था, ताकि per tool अलग table न बनानी पड़े। इसमें कितना time लगा, success/failure, और rough cost रहती है। इसे तब add करें जब आपको SQL में capability-usage analytics चाहिए: skill कितनी बार fire होती है, error rate क्या है, escalation से पहले क्या होता है।

इस set के बाहर दो और tables रहती हैं, दोनों Part 4 में: आपकी business-specific tables (customers, tickets, orders), और run_states, जो paused approval store करती है जब human तुरंत नहीं, बाद में या किसी दूसरे process में sign off करता है। दोनों shared spine का हिस्सा नहीं हैं।

Messages खुद कहाँ जाते हैं? Transcript और cover sheet imagine करें। Transcript हर message है: आपका question, model का reply, हर tool call, हर एक अपनी row में; SDK इसे आपके लिए write और keep करता है (Decision 3 में wired), इसलिए आप इसे build नहीं करते। Cover sheet single conversations row है जिसे आप write करते हैं: कौन, कब, summary, plus user_id जैसे business details जो SDK की अपनी tables carry नहीं करतीं। आप इसे इसलिए रखते हैं क्योंकि transcript "इस customer की last five conversations दिखाओ" answer नहीं कर सकता; यह conversations पर quick lookup है, उस session id से transcript में joined जिसे वे share करते हैं। यह optional है: अगर आपको per-user lists या summaries कभी नहीं चाहिए, transcript alone enough है।

सभी पाँच tables का full SQL नीचे box में है। आपका coding agent Decision 3 में plan से इसे लिखता है, इसलिए skim कर सकते हैं; important यह जानना है कि हर table किसके लिए है।

The schema, in full (four shared tables plus the optional capability_invocations)
-- 1. CONVERSATIONS: business metadata per conversation (your app writes this row)
CREATE TABLE conversations (
session_id TEXT PRIMARY KEY, -- the SAME id you pass to SQLAlchemySession
user_id TEXT NOT NULL,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ended_at TIMESTAMPTZ,
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
-- searchable summary; your app writes it at conversation end
summary TEXT
);
CREATE INDEX idx_conversations_user ON conversations(user_id, started_at DESC);
-- The turns themselves live in the SDK Session's tables (agent_sessions /
-- agent_messages, via SQLAlchemySession), created automatically on this same
-- database and keyed by this session_id; you do not hand-build them.

-- 2. DOCUMENTS: the agent's reference library
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source TEXT NOT NULL, -- 'policy_library', 'kb_article', 'past_case', etc.
title TEXT NOT NULL,
body TEXT NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_documents_source ON documents(source);

-- 3. EMBEDDINGS: vector representations of documents AND past conversations
CREATE TABLE embeddings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- one of these is populated; the other is NULL
document_id UUID REFERENCES documents(id) ON DELETE CASCADE,
conversation_id TEXT REFERENCES conversations(session_id) ON DELETE CASCADE,
chunk_text TEXT NOT NULL,
chunk_index INT NOT NULL,
embedding VECTOR(1536) NOT NULL,
model TEXT NOT NULL, -- 'text-embedding-3-small', etc.
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CHECK (
(document_id IS NOT NULL)::int + (conversation_id IS NOT NULL)::int = 1
)
);
-- the key index for semantic search; see Concept 8
CREATE INDEX idx_embeddings_hnsw
ON embeddings USING hnsw (embedding vector_cosine_ops);

-- 4. AUDIT_LOG: replayable trace of how the Worker changed or used the record
CREATE TABLE audit_log (
id BIGSERIAL PRIMARY KEY,
conversation_id TEXT REFERENCES conversations(session_id) ON DELETE SET NULL,
actor TEXT NOT NULL, -- 'worker:customer-support', 'system', etc.
action TEXT NOT NULL, -- a name from a small, agreed set (Concept 10)
target TEXT, -- table name, skill name, etc.
payload JSONB NOT NULL, -- the data of the action
result JSONB, -- what happened
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_audit_conv ON audit_log(conversation_id, created_at);
CREATE INDEX idx_audit_action ON audit_log(action, created_at);

-- 5. CAPABILITY_INVOCATIONS: every skill or tool call, for replay and metrics
CREATE TABLE capability_invocations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id TEXT NOT NULL REFERENCES conversations(session_id) ON DELETE CASCADE,
capability TEXT NOT NULL, -- 'skill:summarize-ticket', 'tool:search_docs', etc.
arguments JSONB NOT NULL,
result JSONB,
status TEXT NOT NULL CHECK (status IN ('ok', 'error', 'timeout')),
latency_ms INT,
cost_cents INT, -- approximate cost in 1/100 cents
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_cap_conv ON capability_invocations(conversation_id, created_at);

एक Neon database पर Worker schema: आप जो चार shared tables build करते हैं, plus SDK Session और optional metrics table. Conversations row और SDK Session का turn store dialogue और state hold करते हैं. Documents और embeddings reference library और उसके vectors hold करते हैं. Audit_log Worker ने क्या किया उसका trace रखता है; optional capability_invocations table per-skill और per-tool metrics उसके beside रखता है. Foreign keys इन्हें एक consistent operational database में link करती हैं.

कुछ design choices समझने लायक हैं:

  • Documents और conversations दोनों के लिए एक embeddings table. CHECK constraint हर row को exactly one चीज़ की तरफ़ point कराता है: document या conversation. इसलिए single search policies और past conversations दोनों cover कर सकती है, और "क्या हमने पहले इसका जवाब दिया है?" एक index use करता है, दो नहीं।

  • audit_log BIGSERIAL use करता है, UUID नहीं। Audit rows तेज़ी से pile up होती हैं, और plain integer key writes quick तथा order obvious रखती है। बाकी tables UUIDs use करती हैं क्योंकि उनकी rows API responses और URLs में दिखती हैं, जहाँ UUID आपके row counts hide करता है।

  • Skills और tools capability_invocations share करते हैं। Skill call और tool call similar हैं लेकिन identical नहीं: different code, different costs, different failure modes. दोनों को एक table में रखना, और column से बताना कि कौन सा है, आपको "agent ने क्या किया?" दोनों के across पूछने देता है, या split करके "कौन सी skills slow या failing हैं?" पूछने देता है।

  • metadata JSONB columns escape hatches हैं। Schema हर domain-specific field predict नहीं कर सकता जिसकी आपको ज़रूरत होगी; JSONB migrations के बिना fields add करने देता है। Sparingly use करें: जो fields कई queries में आते हैं उन्हें columns में promote करें।

आप अपने business के लिए और tables add करेंगे: customers table, tickets table, orders table, ordinary relational tables जिन्हें agent MCP के through read और write करता है।

PRIMM, Predict. Worker 200 conversations/day handle करता है, हर conversation average 10 turns, 30% एक skill invocation trigger करते हैं और 50% skill row के अलावा दो audit rows write करते हैं। एक month (30 days) के बाद कौन सा store सबसे तेज़ grow करता है? तीन options: (a) all of them at similar volume; (b) audit_log grows fastest by a wide margin; (c) embeddings table, क्योंकि हर turn embed होता है। Confidence 1-5.

Answer (b) है: आप जो tables build करते हैं, उनमें audit_log सबसे तेज़ grow करता है, क्योंकि एक interaction कई action rows write कर सकता है (skill या tool call, record पर write, कभी refund), जबकि सिर्फ़ एक conversations row और कोई new documents नहीं add होता। इसलिए grow करते समय retention और indexing सबसे पहले इसी table के लिए plan करते हैं। SDK का अपना turn store इससे भी तेज़ grow करता है, लेकिन आप उसे manage नहीं करते।

AI के साथ try करें

I'm building a customer-support Worker. Its database already
has the four shared tables from Concept 7: `conversations` (one row per
conversation, plus a summary), `documents` and `embeddings` (a
searchable reference library), and `audit_log` (the record of what it
did). The turn-by-turn messages are held by the agent SDK's Session,
not a table I built.

I want to extend this for a Worker that handles software bug reports
specifically. What three additional tables would you add, and what
columns would they have? For each, say what the agent will use it for
(read access? write access? both?) and what foreign keys connect it to
the tables above.

Concept 8: pgvector basics, types, distance operators, indexes

embeddings table Worker को सिर्फ़ words match करके नहीं, meaning से text find करने देती है। Board को याद करें: text का हर piece (policy, past case, record) एक pin पाता है, और related चीज़ें पास रहती हैं। Pin की position ही embedding है, numbers की list. pgvector (Postgres extension) Postgres को वे pins store करने और nearest pins find करने देता है, इसलिए आपको separate vector database नहीं चाहिए (Concept 6 ने why बताया)।

Vector type. VECTOR(n) ऐसा column है जो एक pin hold करता है: n numbers की fixed list. Embeddings बनाने वाला model n decide करता है: OpenAI के text-embedding-3-small के लिए 1536, text-embedding-3-large के लिए 3072, बाकी models अलग। लोगों को bite करने वाला rule: stored text और search query same model से आने चाहिए। दो models अलग scale पर बने maps जैसे हैं; एक map पर "downtown" वाली जगह दूसरे पर ocean में land कर सकती है। Documents एक model से embed करें और queries दूसरे से, तो "nearest" results nonsense आएँगे, भले query बिना error run हो। यही सबसे common pgvector mistake है।

बहुत बड़ी embeddings (2,000 से ज़्यादा numbers) के लिए halfvec column हर number को half precision पर store करता है: storage roughly half, index still possible (up to 4,000 numbers), small accuracy cost के साथ। हमारा 1536-number case इसे नहीं माँगता; plain vector(1536) fine है।

"कितना close" measure करने के तीन तरीके। Text pin हो जाने के बाद "similar" का मतलब बस "near" है। Pgvector दो pins के बीच distance measure करने के तीन तरीके देता है। एक pick करें और उसी पर stick करें; mid-project switch करने से results confuse होते हैं।

OperatorNameयह क्या measure करता हैकब use करें
<=>Cosineदो pins कितने aligned हैं, length ignoretext, हमारा default
<->Straight-lineदो points के बीच plain distanceimage search और other geometric data
<#>Dot productdirection और length साथ मेंrare: जब आपके vectors all one length नहीं हैं

Text के लिए cosine (<=>) use करें। यह vector कितने लंबे हैं इससे अलग meaning compare करता है, वही चाहिए, और यही standard choice है (इसका index vector_cosine_ops कहलाता है)।

Search करने के लिए, आप user's question को embedding में बदलते हैं और Postgres से वे rows माँगते हैं जिनकी <=> distance सबसे छोटी है, nearest first, top few. आपका agent वह SQL लिखता है; नीचे "Feel it work" में आप real query run होते देखेंगे।

Indexes: search को fast क्या बनाता है। हर pin को एक-एक करके check करना हजारों pins पर slow हो जाता है। Index इसे fix करता है, जैसे किताब के पीछे का index आपको हर page पढ़ने के बजाय topic पर jump कराता है। Pgvector यह index दो ways से बना सकता है: HNSW और IVFFlat. Letters का full form जानना ज़रूरी नहीं, सिर्फ़ behavior:

  • HNSW से start करें। यह हर pin को उसके neighbors से link करता है ताकि search closest ones की तरफ़ hop कर सके: fast searches, slower build, more memory. सही default.
  • IVFFlat सिर्फ़ तब use करें जब build speed search speed से ज़्यादा matter करे। यह pins को buckets में sort करता है और nearest buckets search करता है: build जल्दी, memory हल्की, लेकिन searches slower, और table में data होने के बाद ही build हो सकता है (buckets rows से सीखता है)। जब index अक्सर rebuild होता है, तब worth है।
  • DiskANN (separate add-on) उन indexes के लिए है जो memory में fit नहीं होते। आपको almost certainly इसकी ज़रूरत नहीं।

ऊपर schema वाला HNSW index:

CREATE INDEX idx_embeddings_hnsw
ON embeddings USING hnsw (embedding vector_cosine_ops);

HNSW में दो dials हैं, m और ef_construction. Defaults ज़्यादातर workloads के लिए fine हैं; उन्हें तब तक छोड़ें जब तक आपने change करने की वजह measure न की हो।

Quick check. True या false? (a) Same column पर multiple HNSW indexes हो सकते हैं, एक per distance operator. (b) HNSW index वाली table में row add करना no vector index वाली table से महँगा है। (c) Data load होने से पहले HNSW index create किया जा सकता है। तीनों true हैं: several operators के लिए index हो सकता है (rarely needed), rows आते ही index current रखना real cost रखता है (इसलिए कुछ teams पहले bulk-load, फिर index build करती हैं), और IVFFlat के उलट HNSW को training data नहीं चाहिए।

AI के साथ try करें

Two scenarios. For each, pick HNSW or IVFFlat and justify with one
specific property of the index:

Scenario A: A research index of 10M scientific papers. Built once,
queried millions of times. Build time is "whatever it takes,
overnight is fine." Query latency directly affects user experience.

Scenario B: A live index of customer support tickets that's
re-indexed every 4 hours because thousands of new tickets stream in.
Query patterns are simple (top-5 nearest neighbors). The current
HNSW build takes 20 minutes, a third of the re-index cycle.

After you answer: name ONE thing that would change your answer for
each scenario. Be specific about what you'd need to see in
production metrics before switching.

Concept 9: Embedding pipeline, text in, queryable vector out

Embedding text के piece को space में point में बदलती है। Refunds पर text, refunds पर दूसरे text के पास land करता है; login bugs वाला text कहीं और। इसलिए "similar tickets find करो" बन जाता है "nearest points find करो।" यही पूरा idea है। बाकी plumbing है।

Plumbing के चार steps हैं, और हर एक में एक decision matter करता है:

  1. Chunk document को ऐसे pieces में split करें जो हर एक एक idea carry करने जितने छोटे हों।
  2. Embed हर piece को model call करके करें; आपको उसका point वापस मिलता है।
  3. Text, उसका point, और थोड़ा metadata embeddings table में store करें।
  4. User's question को भी point में बदलकर query करें, फिर nearest stored points find करें।

Embedding pipeline: raw policy document (top-left) semantic boundaries पर ~400-token pieces with overlap में chunk होता है; हर chunk OpenAI के text-embedding-3-small के through 1536-dim vector में batch-embedded होता है; vectors embeddings table में VECTOR(1536) rows की तरह HNSW index के साथ store होते हैं. Query time पर (bottom), user&#39;s question same embed step से गुजरता है, फिर cosine-distance operator वाली single SQL query top-5 nearest chunks find करती है. Bottom पर avoid करने के लिए तीन traps call out हैं: model mismatch, wrong chunk size, filter के बिना sources mix करना.

Chunking: पहले long text split करें। Long document को one giant embedding नहीं बनाना चाहिए। आप उसे chunks में split करते हैं, और chunk size ही main decision है:

  • Natural breaks पर split करें (headings, paragraphs). Mid-sentence रुकने वाला chunk badly search करता है।
  • हर chunk में कुछ hundred words aim करें। बहुत बड़ा chunk "everything weakly" match करता है; बहुत छोटा chunk वह context खो देता है जिसने उसे meaningful बनाया।
  • Chunks को थोड़ा overlap करें, ताकि boundary पर बैठी idea फिर भी found हो।
  • जो already short है उसे chunk न करें। Single resolved ticket या short FAQ entry already one chunk है; उसे as-is embed करें।

आपका agent splitting code लिखता है; आपका decision chunk size और overlap है।

Embedding: हर chunk को point में बदलें। हर chunk embedding model को दें और जो point वापस मिले उसे store करें, batches में, जो one call per chunk से बहुत cheaper है। Concept 8 का rule enforce रखें: stored text और search queries को same model से embed करें, वरना matches noise बन जाते हैं। एक setup trap जानने लायक है (आपका agent handle करता है): database driver को vector type के बारे में बताना पड़ता है, वरना inserts silently fail हो सकते हैं।

अगर आप OpenAI पर नहीं हैं तो? OpenAI ही major provider है जो first-class embeddings API भी ship करता है, इसलिए अगर inference DeepSeek, Anthropic, Gemini, या local model से run कर रहे हैं, तो embedding model अलग pick करते हैं, और dimension वही चीज़ है जिसे match करना होता है। Usual escape hatch local sentence-transformers model है, जैसे all-MiniLM-L6-v2 (384 dims): कोई API call नहीं, और text आपकी machine से बाहर नहीं जाता। Either way embeddings bill की सबसे cheap line हैं, इसलिए यह choice budget नहीं, architecture move करती है।

Models switch करना dimensions switch करना है: column को new size पर rebuild करें और हर row re-embed करें। "Close enough" नहीं होता।

Re-embed कब करना है। तीन triggers:

  1. Source text changed, उन rows को re-embed करें।
  2. Embedding models switch किए, हर पुराना point अब अलग map पर है, इसलिए सब re-embed करें (या switchover के दौरान दोनों रखें)।
  3. Chunk size बदला, re-chunk और re-embed करें।

PRIMM, Predict. आपने text-embedding-3-small से 100,000 chunks embed किए हैं। फिर decide करते हैं कि agent past conversations भी embed करे (सिर्फ़ documents नहीं), ताकि "क्या हमने यह पहले discuss किया है?" lookups कर सके। आप conversation embeddings उसी embeddings table में same column से लिखते हैं। Semantic search query (user question के 5 nearest neighbors, no filter) mixed document और conversation results लौटाती है। क्या यही चाहिए था? सही query shape क्या है? Confidence 1-5.

Answer: almost certainly वह नहीं जो आप चाहते थे। Documents और past conversations results में mix हों तो agent old chat snippet को authoritative policy जैसा treat कर सकता है। Fix है search करते समय source filter करें: documents only माँगें, या दो searches run करके weigh करें, ताकि दोनों kinds blur न हों।

Results गलत लगें तो cause almost always तीन में से एक है: query और stored text different models से गुज़रे (matches noise हैं), आपने source type से filter करना भूल गए, या chunks meaning carry करने के लिए बहुत छोटे हैं। पहले इन्हें check करें।

Retrieval quality Worker accuracy का silent killer है। Final answer perfectly reasonable लग सकता है जबकि wrong evidence cite कर रहा हो। इसे catch करने का only way answer से पहले retrieval check करना है।

AI के साथ try करें

I'm chunking a corpus of legal contracts (each averaging 8,000 words)
for semantic search. The user will query things like "what's the
termination clause in this contract", phrases that map cleanly to
specific sections. Walk me through three chunking strategies:

A) Fixed 400-token chunks with 60-token overlap (the default)
B) Chunk at section headings only, with no overlap
C) A two-level approach: store both 400-token chunks AND
whole-section chunks, search both, combine results

For each, name (1) when it wins and (2) when it loses.

इसे काम करते महसूस करें: दस minutes में semantic search

आपने pgvector पर चार concepts पढ़ लिए, बिना एक भी result return होते देखे। Part 3 MCP layer ऊपर रखने से पहले, दस minutes निकालकर semantic search को meaning से rank करते देखें। यह throwaway है, Worker नहीं: scratch table, पाँच sentences, एक query. Part 4 real thing build करता है।

आपका Neon Quick Win से already wired है, इसलिए यह एक prompt है:

On a fresh scratch branch of my Neon project, create a tiny notes(id, text, embedding vector(1536)) table with an HNSW index. Embed these five sentences with text-embedding-3-small and insert them: "the refund hasn't arrived", "my package is late", "how do I reset my password", "the charge appears twice", "I was billed for something I didn't buy". Then embed the query "I never got my money back", run a cosine-distance search, and show me the rows ranked by distance.

ध्यान दें: billing और refund sentences "my package is late" से ऊपर rank करती हैं और "reset my password" से बहुत ऊपर, भले query किसी sentence के साथ almost no words share करती हो। Keyword overlap से नहीं, meaning से ranking होना ही embeddings table के exist करने का पूरा reason है।

Done when: आपने ranked list देख ली है जिसमें refund और billing sentences top पर हैं। अपने agent से scratch branch delete करने को कहें; real schema Part 4 है।

अगर refund sentences win नहीं करतीं, तो usual cause Concept 9 model mismatch है: insert और query अलग embedding models से गए। Same model both ends, वरना distances noise हैं।


Concept 10: Audit trail as discipline, Worker के लिए "reads and writes" का मतलब

Agent जो भी meaningful action लेता है, उसे database में एक row छोड़नी चाहिए। उस row के बिना आप बाद में यह answer नहीं कर सकते: "agent ने क्या किया, और कब?" यही trail real action को plausible-sounding reply से अलग करता है।

यहाँ दो चीज़ें पास-पास बैठती हैं और अक्सर confuse होती हैं, इसलिए इन्हें अलग रखें:

  • Truth itself: अभी क्या सच है: customer का tier, ticket का status, policy का text. यह business records और reference library में रहता है, और Worker इसे read और update करता है।
  • Audit trail: Worker ने उस truth के साथ क्या किया इसका replayable record: कौन सा tool call किया, क्या बदला, क्या return हुआ, किसने approve किया। यह उसी database में audit_log में रहता है और अलग सवाल का answer देता है: "क्या सच है?" नहीं, बल्कि "Worker ने क्या किया, और क्या आप उसे prove कर सकते हैं?" यह conversation की दूसरी copy नहीं है (Session पहले से हर message hold करता है); यह typed actions और उनके results record करता है, including वे actions जो message की तरह कभी appear नहीं होते: database write, refund, guardrail block. (Per-skill और per-tool metrics के लिए अलग optional capability_invocations table इसके साथ बैठती है; Concept 7 देखें।)

इसलिए हर meaningful action अपनी audit row लिखता है, भले जिस data को उसने touch किया वह कहीं और stored हो। Action हुआ यह fact audit_log में रहता है; दोनों foreign key से जुड़े होते हैं।

इसमें क्या जाता है। Meaningful actions, इतने detail के साथ कि replay हो सकें: हर tool या skill call (name, inputs, result, कितना time लगा, success हुआ या नहीं), record में हर change (कौन सी table, क्या बदला, किस conversation के under), हर guardrail decision, और हर model call with token cost.

क्या बाहर रहता है। Full conversation text, क्योंकि Session already hold करता है; उसे फिर store करना storage double करता है। Raw sensitive data जिसे humans row में पढ़ सकते हों; hash या summary रखें और full चीज़ locked away रखें। और model की private reasoning.

जो इसे audit trail बनाता है, सिर्फ logs नहीं: given a conversation and a time, आप model re-run किए बिना reconstruct कर सकते हैं कि Worker ने क्या किया और क्यों। अगर नहीं कर सकते, तो आपके पास logs हैं।

Action और उसका record साथ लिखें। जो code refund issue करता है, वही refund और उसकी audit row एक transaction में लिखता है: दोनों land करें या कोई नहीं। Half-written audit trail none से बदतर है, क्योंकि वह complete दिखता है और होता नहीं। (Part 4 में आपका agent यह लिखता है।)

हर action को small, agreed set से name दें (refund_issued, message_sent, और ऐसे ही) और उन names को drift न होने दें। Same event के तीन different names, छह महीने बाद, trail को query करना impossible बना देते हैं। refund_issued जैसे domain events अपना name पाते हैं ताकि row business event की receipt लगे, सिर्फ उस tool call की नहीं जिसने उसे trigger किया।

Audit trail क्या नहीं है। सिर्फ logs नहीं: यह आपके अपने database में queryable SQL है ("agent ने customer X को पिछले महीने क्या बताया, और कौन सी policy cite की?" one query है), text files पर grep नहीं, और यह आपके business data के साथ backup और access-control होता है। Event sourcing नहीं: यह आपके state के साथ append-only trace है, वह चीज़ नहीं जिससे आप state rebuild करते हैं (tickets, documents, और Session state हैं)। Traces नहीं: tracing (OpenTelemetry, OpenAI dashboard) debugging का flight recorder है, अलग system में रहता है, off किया जा सकता है, और Zero-Data-Retention में unavailable होता है; audit log receipt है, action के same transaction में committed और जितना needed हो उतना kept. दोनों चलाएँ: trace debug करने के लिए, ledger prove करने के लिए।

Thesis का मतलब यही है: "Workers only become governable as a workforce when a ledger makes them legible." आपका audit_log वही ledger है। और legible होना Worker को sellable बनाता है: जिस outcome को आप prove नहीं कर सकते, उसके लिए charge नहीं कर सकते। Per-seat pricing logins गिनती है; outcome pricing यह गिनती है कि Worker ने क्या किया: per resolved ticket, per processed invoice, per drafted reply. refund_issued और ticket_resolved rows वही outcomes हैं, low-level events के साथ same log में, ऐसी चीज़ जिसे आप customer को दिखाकर invoice कर सकते हैं। इसलिए Worker को system of record सिर्फ इसलिए नहीं चाहिए कि वह runs के बीच भूलना बंद करे, बल्कि इसलिए कि उसका work provable, billable artifact बने। यही database से wired agent और actually sellable Worker के बीच line है।

AI के साथ try करें

Here's a customer support scenario: a customer claims the Worker told
them they would receive a $50 refund, but the actual refund issued was
$30. The Worker handled the conversation 19 days ago.

Walk me through the audit-trail query path to resolve this:

1. Find the conversation. (Which columns of which tables?)
2. Find the message where the refund amount was promised. (How do you
distinguish "discussed" from "promised"?)
3. Find the capability invocation that issued the refund.
4. Find the database write that recorded the $30 amount.

For each step, name the table you'd query and the WHERE clauses.
Then say what's MISSING from the five-table schema that would make
this query easier.

Part 3: MCP, agent को system of record से wire करना

Part 1 ने agent को Skills की library दी। Part 2 ने उसे Postgres system of record दिया। Part 3 दोनों को Model Context Protocol से wire करता है: agents external state और external capability तक कैसे पहुँचते हैं, इसका open standard. Thesis MCP की जगह पर direct है: "MCP is how the workforce reaches [its systems of record]: every authoritative store becomes addressable to any Worker through an MCP server, under policy." यह Part उसे operational बनाता है।

Concept 11: MCP क्या है और क्या नहीं है

Model Context Protocol (modelcontextprotocol.io) एक open client/server protocol है (originally Anthropic से, अब open standard के रूप में governed) जिससे AI agent external tools, data, और prompts से connect करता है। Repeated framing है "AI tools के लिए USB-C": one protocol, many implementations, किसी भी side को swap करें बिना दूसरी side तोड़े। Framing accurate है; हर metaphor की तरह इसकी limits हैं जिन्हें name करना worth है।

MCP क्या है। Protocol. Specification. तीन primitives जिन्हें server client को expose कर सकता है।

  1. Tools: functions जिन्हें model invoke कर सकता है। Client उन्हें list करता है, model एक pick करता है, server उसे execute करता है। Conceptually पिछले course के @function_tool decorator जैसा, लेकिन implementation agent process में नहीं, MCP server process में रहती है। यह by far सबसे-used primitive है।
  2. Resources: read-only data जिसे agent fetch कर सकता है। Files, database query results, API responses. इन्हें MCP की GET-only side समझें। Practice में tools से कम common, लेकिन "agent को यह document on demand read करने दें" के लिए useful.
  3. Prompts: reusable prompt templates जो server provide करता है। Team standardised prompts publish कर सकती है ("summarize-incident-report") जिन्हें server से connected कोई भी agent invoke कर सके। Tools और resources की तुलना में rarely used.

तीन transports, 2026 तक current recommendations:

Transportकब use करेंStatus
stdioLocal subprocess; agent और server same machine परMature. Local tools का default.
streamable HTTPRemote server; production deploymentsNew remote work के लिए recommended. Plain HTTPS पर single endpoint.
SSERemote server; older deploymentsLegacy. कई servers अभी expose करते हैं; new ones increasingly streamable HTTP default.

Streamable HTTP दो flavors में आता है, और deploy करते समय difference matter करता है। Stateless default है: हर call independent request और response है, ordinary API call जैसा, इसलिए आप load balancer के पीछे server की कई copies चला सकते हैं और कोई भी copy answer कर सकती है। Stateful live session खुला रखता है ताकि server partial results stream कर सके या mid-task notifications push कर सके; long-running work के लिए इसकी ज़रूरत होती है, लेकिन यह हर client को one server instance से pin करता है और operate करना ज्यादा कठिन है। Open session की specific reason (live streaming, server-initiated messages) न हो तो stateless use करें।

MCP क्या नहीं है।

  • Framework नहीं। यह protocol है। आपका agent MCP को वैसे "use" नहीं करता जैसे Agents SDK को करता है; आपका agent का MCP client, MCP server से MCP बोलता है। Agents SDK में MCP client included है; वही integration point है।
  • Service नहीं। कोई "MCP cloud" नहीं है। MCP servers programs हैं जिन्हें आप run करते हैं (या vendors आपके लिए run करते हैं). Neon MCP server mcp.neon.tech पर hosted है; filesystem MCP server local subprocess की तरह run होता है; custom MCP server जो आप लिखते हैं, जहाँ deploy करें वहाँ run होता है।
  • Security boundary नहीं। MCP transport और protocol define करता है; MCP server कौन से tools expose करता है और वे क्या कर सकते हैं, यह server की responsibility है। Malicious MCP server वही सब कर सकता है जो उसका server-side code करता है। Trust boundary अब भी agent loop है जो decide करता है कौन से tools call हों, और sandbox है जहाँ tools execute होते हैं।
  • @function_tool का replacement नहीं। दोनों की जगह है। Decision tree Concept 14 है।

Quick check. True या false: (a) MCP client एक समय में exactly one MCP server से बात करता है। (b) वही @function_tool-style function, अगर आप चाहें, MCP tool के रूप में expose हो सकता है या function tool रह सकता है, और model को difference पता नहीं चलेगा। (c) MCP servers और OpenAI Agents SDK tightly coupled हैं, इसलिए MCP use करने के लिए SDK use करना ही होगा। Answers: (a) False: agent multiple MCP servers से connect हो सकता है और their tools का union देख सकता है। (b) True: model को दोनों callable tools with schemas दिखते हैं। Difference implementation कहाँ रहती है। (c) False: MCP model-agnostic है। Claude, Gemini, और others के अपने MCP clients हैं। OpenAI Agents SDK उनमें से एक client है।

AI के साथ try करें

For each item, say which MCP primitive fits best (tool, resource, or
prompt), and why in one line:

A) The agent reads the current text of a policy document on demand,
but never writes it.
B) The agent issues a refund through the payment gateway.
C) Every Worker on the team should summarize incidents the same way,
from one shared, versioned template.

Then a judgment question. A teammate says: "We put the refund logic
behind an MCP server, so the agent can't do anything dangerous." Using
this concept's "what MCP is NOT," explain why that sentence is false,
and name where the real trust boundary actually lives.

Concept 12: Neon MCP server, development plane, runtime नहीं

इस concept की specifics age होंगी। Pattern नहीं होगा। Neon के MCP server tooling, auth flow, और exact tool surface हर कुछ months में बदलते हैं। जो true रहता है: managed-database vendor अपनी management API को natural-language operations के लिए MCP के through expose करता है, जबकि runtime production traffic direct connections या scoped custom servers use करता है। Specifics pin करने से पहले Neon docs verify करें।

आपने setup के दौरान Neon MCP server को अपने coding agent से connect कर लिया था, और तब से आप उस पर lean कर रहे हैं: plain English में schema पूछना, tables में क्या है check करना, connection string लेना। उस fifteen-minute connection पर रुकना worth है, क्योंकि यह पूरे Part की सबसे important line सिखाता है: Neon MCP server किसके लिए है, और उसे किससे कभी wire नहीं करना चाहिए।

यह Neon की management API (projects, branches, schema, migrations, ad-hoc SQL) को tools की तरह expose करता है जिन्हें आपका agent plain language में call कर सकता है। इससे यह development tool बनता है, production tool नहीं। Neon के अपने docs blunt हैं: "Never connect MCP agents to production databases."

यह line इतनी hard क्यों है। Server का run_sql tool model द्वारा लिखा गया any SQL चलाता है। Build करते समय यही point है: आप कहते हैं "show me users who signed up last week and never logged in," model query लिखता है, server उसे run करता है, और आपको answer मिलता है। उसी tool को live database पर point कर दें और यह एक door बन जाता है। जो कोई आपके Worker में instructions slip कर सकता है (customer का cleverly worded message), वह उससे आपका पूरा database पढ़वा सकता है, क्योंकि tool का काम है handed SQL चलाना।

इसलिए उसे वहीं use करें जहाँ वह shine करता है, और वह सब development में है:

  • Schema और migrations. "Tickets table में priority column add करें।" Server पहले throwaway branch पर change test करता है, फिर merge करता है। Branch-first habit schema evolve करने का safe way है।
  • अपने data को explore करना। "कितनी embeddings हैं, source के हिसाब से grouped?" One-off question के लिए hand-written SQL से faster.
  • चीज़ें look up करना। Connection strings, project settings, table shapes, Neon console खोले बिना।

Setup में आपने यही देखा: आपने agent से project create करने, pgvector on करने, schema run करने, और connection string report करने को कहा, और उसने सब Neon MCP tools से किया, main touch करने से पहले branch पर migration test करते हुए। हाथ से कोई SQL type नहीं हुआ।

PRIMM, Predict. आपका finished customer-support Worker चाहता है: (a) customer के orders look up करना; (b) उनके tier के लिए refund policy check करना; (c) refund issue करना; (d) उसने क्या किया और क्यों, इसकी audit row लिखना। क्या उसे Neon तक इसी MCP server से पहुँचना चाहिए, या किसी और way से? Confidence 1-5.

Answer: चारों के लिए some other way। Live Worker के पास कभी run_sql-style tool नहीं होना चाहिए, यह ऐसा door है जिसे आप पूरी तरह lock नहीं कर सकते। उसे कुछ narrow abilities चाहिए, arbitrary SQL चलाने की power नहीं। Production patterns दो हैं: custom MCP server जो सिर्फ़ needed specific operations expose करे (Concept 14), या direct Postgres connection जो उन्हें wrap करे। Part 4 दोनों use करता है: business operations के लिए custom customer-data server, और audit subsystem के लिए direct connection only (Decision 7 बताता है कि audit उस MCP boundary से बाहर क्यों रहता है जिसे वह audit कर रहा है)।

यही Invariant 5 है: workforce governed stores से read और write करती है। Broad run_sql tool governance नहीं है; वह no governance पर friendly face है। Neon MCP server वह है जिससे आप store build करते हैं। यह वह नहीं है जिससे आपका Worker उसे touch करता है।

AI के साथ try करें

Read Neon's MCP server documentation page and answer three questions:

1. List THREE management operations the Neon MCP server exposes that
would be useful while you're building a customer-support Worker.
2. List THREE things a running Worker NEEDS to do that you should NOT
use the Neon MCP server for, and why.
3. For each of the three in (2), say what the Worker should use instead
(direct Postgres connection? custom MCP server? function_tool?).

Concept 13: MCP को OpenAI Agents SDK से connect करना

आप coding agent से Neon MCP server drive कर रहे थे। आपका Worker, जिसे आप Part 4 में build करते हैं, अलग program है: OpenAI Agents SDK agent. तो यह concept बस यह answer करता है: वह agent MCP server से बात कैसे करता है? आप connection plumbing हाथ से नहीं लिखेंगे, SDK उसे ship करता है। समझने लायक चीज़ shape है, ताकि आप build steer कर सकें और misbehave होने पर debug कर सकें।

Whole picture यह है। SDK में built-in MCP client है, transport के हिसाब से one connector: stdio के लिए local, remote streamable HTTP के लिए modern, और SSE के लिए legacy (new work में SSE avoid करें)। आप server से connection open करते हैं, उसे agent को hand करते हैं, और उसके बाद SDK सब करता है: server से पूछता है कौन से tools हैं, उन tools को आपके खुद लिखे @function_tools के next to model के सामने रखता है, और जब model कोई tool pick करता है, call सही server तक route करके answer वापस लाता है। Model MCP tool और local function tool में difference नहीं बता सकता, और बताने की जरूरत भी नहीं। यही sameness point है: MCP model को capability देने का एक और way है।

MCP architecture: model decide करता है कौन सा tool call करना है; MCP client trust boundary के across streamable HTTP (या stdio, या legacy SSE) से call route करता है; MCP server narrow, scoped tools expose करता है और वही Postgres touch करता है. Boundary आपको तीन properties देती है: scope, isolation, reusability.

चार बातें याद रखें, और आप ask करेंगे तो आपका agent इन्हें handle करता है:

  • Connection साफ open करें, और साफ close करें। MCP connection कुछ open रखता है: stdio के लिए subprocess, remote के लिए HTTPS session. Proper close न हो तो connection leak होता है। SDK की connection objects managed block में open/close होने के लिए built हैं, इसलिए जब तक आप उससे लड़ते नहीं, यह handled है।
  • Production में tool list cache करें। Default में agent हर single run पर server से फिर पूछता है "what tools do you have?", यानी wasted network round-trip. Caching उसे once बना देती है। Catch बस इतना है: server tools बदलें तो agent से cache refresh (या restart) करवाएँ। Build करते समय caching off रखें ताकि changes तुरंत दिखें।
  • Servers stack होते हैं। आप agent को एक साथ कई MCP servers दे सकते हैं, और model simply combined set of tools देखता है। Part 4 का Worker अपने custom customer-data server से इसी तरह connect करता है।
  • Dangerous tools को approval के पीछे gate करें। Default में tool calls बिना confirmation run होते हैं। Sensitive ones के लिए आप हर call पर human approval require कर सकते हैं। Concept 12 के development-vs-runtime gap के लिए यह practical knob है: Neon MCP server को hand-driven work में use करते हुए भी destructive tools (जो drop या rewrite करें) को approval prompt के पीछे रखना real safety win है।

एक gotcha याद रखें: अगर MCP server startup पर कुछ heavy load करता है (machine-learning model, for instance), तो agent का default "server ने time पर answer दिया?" window बहुत छोटा हो सकता है और आपको confusing connection-failure error दिखेगी। Fix एक setting है जो window lengthen करती है। आप इससे तभी मिलेंगे जब कोई server boot होते ही real work करे।

Hands-on, understanding के लिए ही। Shape concrete करने का fastest तरीका। नीचे वाला prompt अपने coding agent में paste करें। यह एक tiny throwaway script build करता है जो OpenAI Agents SDK agent को आपके already-connected Neon MCP server पर point करता है, और agent को plain language में आपके projects list करते देखने देता है। यह learning exercise है, production path नहीं: real Worker कभी Neon MCP server से connect नहीं करता (Concept 12). आप इसे एक बार यहाँ इसलिए कर रहे हैं ताकि Agents SDK agent को MCP server drive करते end to end देख सकें।

Write me a small throwaway Python script (call it scratch_neon_agent.py)
that uses the OpenAI Agents SDK to connect to the Neon MCP server over
its remote streamable-HTTP transport, then runs one agent turn asking it
to "list my Neon projects and show the schema of the largest one."

Use the current OpenAI Agents SDK MCP classes (check the docs for the
exact import and class name). Open the connection as a managed block so
it closes cleanly, turn on tool-list caching, and print the final output.

Then run it and show me what the agent did, step by step. Remind me in a
comment that this is for understanding only and a real Worker should
never connect to the Neon MCP server.

देखें क्या होता है: agent connect करता है, SDK Neon के tools pull करता है, model अपने आप list_projects pick करता है, और आपको English में answer मिलता है। आपने अभी वही wiring देखी जो आपका Part 4 Worker use करेगा, बस एक ऐसे server पर point करके जिसे production में use नहीं करना चाहिए, इसलिए script throw away है।

AI के साथ try करें

Explain, in plain language and without writing code, how you would
connect one OpenAI Agents SDK agent to TWO MCP servers at once: the
Neon MCP server (remote) and a local filesystem MCP server for reading
project files. Cover:

1. Which transport each server would use, and why.
2. How the model decides which server's tool to call.
3. Which tools you'd put behind human approval, and why.
4. One thing that could go wrong with two servers connected, and how
you'd notice it.

Concept 14: Custom MCP servers, अपना कब लिखें और कब नहीं

Neon MCP server generic है: वह Neon की API जो भी कर सकती है, कर सकता है। Development के लिए यही इसकी strength है और runtime के लिए weakness. Custom MCP server trade-off को invert करता है: narrow surface, no general-purpose run_sql, सिर्फ़ वे specific operations जिनकी आपके Worker को सच में जरूरत है।

Decision tree, priority order में।

Capability placement के लिए decision tree: root question से शुरू करके पाँच filters order में answer करें (single-use? vendor has one? multi-agent reuse? sensitive scope? process-isolation?). तीन leaves green हैं (जो है वही use करें: @function_tool या vendor MCP server); तीन amber हैं (कुछ नया build करें: custom MCP server). First YES पर stop करें.

Same logic quick-scan table में:

आप expose करना चाहते हैं...Use thisक्यों
One function with one input, used by one agent@function_toolProtocol overhead की जरूरत नहीं। Local function call ठीक है।
कई functions tightly coupled to your agent's code@function_toolअगर वे agent के साथ state share करते हैं और same repo में हैं, तो वे agent का part हैं।
Capability जिसे multiple agents (या deployments) use करेंगेCustom MCP serverProtocol ही उसे reusable बनाता है।
Capability जिसे agent process से longer live करना हैCustom MCP serverLong-running connections, background jobs, queue consumers.
Vendor-provided functionality (Neon, GitHub, Linear)Vendor's MCP serverजो वे ship करते हैं उसे rebuild न करें।
Sensitive operations जिन्हें narrow scope चाहिएCustom MCP serverExactly वे tools define करें जिनकी जरूरत है; कुछ और नहीं।

Custom MCP server की shape जितनी लगती है उससे simpler है। यह एक छोटा program है जो handful named tools declare करता है। हर tool का plain-English description होता है (वही trigger text जैसा SKILL.md carry करता है) जो model को बताता है कब उसे reach करना है, और typed inputs की short list होती है ताकि model जान सके क्या pass करना है। बस इतना: कुछ well-described, narrow tools और कुछ नहीं। No general run_sql, no escape hatch.

और आप वह program hand-write नहीं करते। जैसे आपने skills install किए और agent से काम करवाया, वैसे ही mcp-builder skill scope description को working, tested server में बदलता है। आपका judgment scope में जाता है: कौन से tools exist करें, हर tool क्या कर सकता है, और कौन से tools deliberately नहीं हैं, plumbing में नहीं। Prompt flow ऐसा दिखता है:

/mcp-builder Let's design a custom MCP server called "customer-data"
on the streamable-HTTP transport, stateless flavor (each call an
independent request, no open session, so it scales). Plan the
implementation first, then build it.

Scope: exactly three tools, nothing else.
- lookup_customer(customer_id): return id, email, tier, open-ticket count
- find_similar_resolved_tickets(description, limit): semantic search over
past resolved tickets
- issue_refund(order_id, amount, reason): issue a refund AND write an
audit row in the same transaction

No general SQL tool. Each tool gets a clear description so the model
knows when to call it. Start a fresh project with uv, walk me through
the plan before writing code, then build and verify it.

Agent नया uv project scaffold करता है, tools plan करता है, server build करता है, और verify करता है कि वह run होता है। Once it exists, आप उसे MCP servers connect करने के same दो ways से connect करते हैं जिन्हें आप देख चुके हैं: अपने general coding agent से (Claude Code या OpenCode, ताकि hand-test कर सकें) और अपने OpenAI Agents SDK Worker से (ताकि Worker सच में use कर सके)। Part 4 का Decision 6 यह build end to end चलता है।

तीन चीज़ें जो यह server देता है और @function_tool नहीं देता।

  1. Process isolation. MCP server अपने process में run करता है (stdio के लिए subprocess, streamable HTTP के लिए separate service). Server crash agent को crash नहीं करता; server memory leak agent में leak नहीं होता।

  2. Scope. Server सिर्फ़ वे handful tools expose करता है जिन्हें आप define करते हैं (worked example के customer-data server में तीन). No run_sql. No "execute arbitrary code." Model इस scope से escape नहीं कर सकता क्योंकि protocol कुछ और expose नहीं करता। यह real defense in depth है: model कुछ stupid करने का decide करे भी, तो उसे करने की surface area वही few functions हैं।

  3. Agents के across reusability. दूसरा agent (Sales Worker, Reporting Worker) same customer-data MCP server से बात कर सकता है। Same scope, same protocol, same trust boundary. Capability copy-paste between agents के बजाय shared infrastructure बन जाती है।

Trade-off real है। Custom MCP servers operational complexity add करते हैं: deploy करने के लिए another process, logs का another set, another network hop (अगर remote), manage करने के लिए another version. Single agent द्वारा use होने वाली single function के लिए server न लिखें। Server तब लिखें जब capability reuse होगी, scope matter करता है, या isolation safety देती है।

PRIMM, Predict. आप customer-support Worker design कर रहे हैं। आपको चाहिए: (1) past resolved tickets पर semantic search; (2) refund audit row write करना; (3) current weather read करना (एक greeting skill में use जो कहता है "good morning from sunny Karachi"); (4) payment gateway call करके refund issue करना। हर एक के लिए predict करें: @function_tool, custom MCP server, या vendor MCP server (e.g., Stripe's, अगर exist करता हो)?

Answers framework को tease out करते हैं:

  1. Custom MCP server (customer-data). Agents के across reused; sensitive data; scoped tools broad run_sql से बेहतर।
  2. Custom MCP server (customer-data) या @function_tool. दोनों work करते हैं; अगर Worker only writer है, function tool ठीक है। अगर multiple Workers audit rows write करेंगे, MCP server.
  3. @function_tool. One agent, one tiny function, defend करने के लिए कोई security surface नहीं। इसके लिए server न build करें।
  4. Vendor MCP server (Stripe MCP) अगर exist करे, वरना Stripe API call करता @function_tool. Third-party APIs को अपने MCP server में wrap न करें जब तक ऊपर policy add करने की जरूरत न हो।

Framework clear है जब आप trace करते हैं: MCP की value उस boundary की value के साथ बढ़ती है जो वह create करता है। Boundary जिसकी जरूरत नहीं, overhead है।

AI के साथ try करें

Here are five capabilities I'm thinking of adding to my customer-support
Worker. For each, walk the Concept 14 decision tree with me and recommend
one: a @function_tool, my custom customer-data MCP server, or a vendor
MCP server (if a credible one exists). Justify each choice with ONE of
the three properties (isolation, scope, reusability), or say plainly why
no boundary is worth building.

1. Look up a customer by email (the gap Decision 8 leaves open).
2. Issue the real refund through Stripe (actual money, third-party API).
3. Send the drafted reply as an email through our mail provider.
4. Convert a UTC timestamp to the customer's local time for a greeting.
5. Let a second Worker (a sales assistant) reuse the customer lookups.

Then push back on me: which TWO of these would you deliberately NOT put
behind a custom MCP server, and what does that say about when the
boundary earns its cost?

Concept 15: MCP under load: transports, pooling, और scale पर क्या होता है

One agent और one server वाला demo बस काम करता है। Real traffic, many conversations a minute, तीन pressures add करता है। First Worker के लिए आपको इन पर अभी act नहीं करना, लेकिन इनके exist करने का पता होना बाद में confused afternoon बचाता है। हर एक का plain fix है।

  1. Agent और server के बीच wire. Local subprocess (stdio) तब ठीक है जब सब one machine पर run हो। जैसे ही more than one agent server share करे, या server अपनी hardware पर move हो, remote transport (streamable HTTP) पर switch करें। यह deployment change है, rewrite नहीं।
  2. Same setup cost बार-बार न दें। तीन छोटी habits repeated costs को one-time बना देती हैं: Worker boot होते समय हर server से एक बार connect करें और connection open रखें, हर request पर reconnect न करें; agent को server की tool list remember करने दें, हर run पर "what can you do?" फिर न पूछें (tools बदलें तो refresh करें); और server के अंदर database connections का ready pool रखें, ताकि query हर बार fresh connection open करने का wait न करे।
  3. हर चीज़ पर ceiling रखें, और trace whole रखें। One request कितने steps ले सकता है cap करें, failed tool call को हार मानने से पहले दो बार retry करें, और server को rate-limit करें ताकि one burst उसे swamp न करे। और ensure करें कि आपका trace MCP boundary के across call follow करे: जब Worker tool call करता है, तो server का own database work same picture में दिखना चाहिए। वरना server के अंदर slow query outside से invisible है, और आप latency गलत जगह chase करेंगे।

Deeper knobs (per-tenant concurrency caps, fine transport tuning) first Worker से आगे हैं। ये तीन पहले bite करते हैं।

Quick check. True या false: (a) Legacy SSE transport से streamable HTTP पर server move करने के लिए आपको server के tools rewrite करने पड़ते हैं। (b) Agent को server की tool list cache करने देना production में safe है, अगर tools बदलने के बाद cache refresh करें। (c) पाँच abilities को MCP tools की तरह expose करना हमेशा model को same पाँच local function tools से ज्यादा context budget cost करता है। Answers: (a) Mostly false: tools unchanged रहते हैं; server को सिर्फ newer transport बोलना होता है, जो most modern ones already करते हैं। (b) True: यही intended pattern है। (c) False: model के लिए tool, tool है। पाँच tool descriptions लगभग same cost करती हैं चाहे वे जिस side रहें।

AI के साथ try करें

My customer-support Worker is in production. It runs 80 conversations/minute
at peak. Each conversation makes 2-4 MCP tool calls on average. I'm seeing
intermittent latency spikes: most calls return in 200ms, but a small
percentage take 5-15 seconds.

Walk me through five places I'd investigate, in order of priority:

1. The agent-side MCP client connection management.
2. The transport choice between agent and MCP server.
3. The MCP server's internal connection pool to Postgres.
4. Postgres-side query performance (slow queries blocking the pool).
5. Network or DNS issues between agent and MCP server.

For each, name the specific signal I'd look for and the rough fix.

Part 4: Worked example, customer-support Worker

एक realistic evolution, ऊपर के हर concept के साथ, दोनों tools. हम Build AI Agents वाले chat-agent project को लेते हैं और तीन Skills, Neon system of record, और MCP wiring layer जोड़कर customer-support Worker बनाते हैं। Eight build decisions, उस course के Part 5 जैसी same shape.

Part 4 एक picture में: पिछले course के chat agent (left) से शुरू करके, आठ Decisions तीन phases में grouped. Phase 1 (blue) Foundation है: D1 CLAUDE.md update करता है, D2 Plan Mode में plan करता है, D3 Neon provision करता है. Phase 2 (amber) Capability है: D4 पहला Skill लिखता है (एक deliberate hand-write), D5 embedding pipeline build करता है. Phase 3 (green) Runtime + Verify है: D6 custom MCP server build करता है, D7 audit logging wire करता है, D8 end-to-end verify करता है. जब भी कोई Decision arc में कहाँ fit होता है, यह समझना हो, यहाँ लौटें.

शुरू करने से पहले: setup जो prereqs में नहीं है। यह Part तीन चीज़ें assume करता है जो already done हैं। (1) Evolve करने के लिए chat-agent. अगर आपने Build AI Agents complete किया है, तो वही project open करें। अगर आपने skip किया है, तो नीचे वाले prompt से उसका end state अपने digital-fte folder में scaffold करवाएँ; दोनों cases में आठ Decisions उन्हीं files को in place evolve करते हैं। (2) आपके पास free Neon account है और आपने Neon MCP server authorize कर लिया है (Quick Win के Prep वाला one-click OAuth step; अगर आपने Quick Win skip किया है, तो आपका agent आपको उससे walk through करवाएगा)। (3) आपके पास Claude Code या OpenCode installed और authenticated है। इनमें से कुछ भी missing है, तो Decision 1 से पहले fix करें।

Chat-agent नहीं है? पहले scaffold करें (अगर Build AI Agents से लाए हैं तो skip करें)। One prompt उस course का end state आपके digital-fte folder में reproduce करता है, ताकि हर कोई Decision 1 same जगह से शुरू करे:

Starting in this digital-fte folder, scaffold the end state of the
Build AI Agents course so I have a chat agent to evolve: a sandboxed
OpenAI Agents SDK chat agent that runs from the terminal. If the Quick
Win's SandboxAgent is already here, build on it rather than duplicating.
Using uv and the current OpenAI Agents SDK (check the docs for the exact
APIs), create:

- cli.py: a streaming terminal chat loop (read input, stream the reply)
- agents.py: a SandboxAgent on a gpt-5-class model with a short
customer-support system prompt, running on a local sandbox
- tools.py: one or two @function_tool stubs (e.g. a search_docs that
returns a placeholder) wired into the agent
- a conversational Session so turns persist within a run
- one input guardrail and one output guardrail, kept simple

Plan it first and show me the plan, then build it, then run it once with
"hi" so I can see it answer. The eight Decisions below evolve these files
in place; don't add Skills, Postgres, or MCP yet.

इसे एक बार "hi" के साथ run करें और confirm करें कि यह reply करता है। वह clean, runnable chat agent starting line है; Decision 1 उसे CLAUDE.md के through new architecture सिखाने से शुरू होता है।

Brief

पिछले course के chat-agent को ऐसे customer-support Worker में evolve करें जो:

  • तीन Skills on demand load करता है: summarize-ticket, find-similar-cases, और escalate-with-context.
  • Concept 7 की five tables वाले Neon Postgres system of record से read और write करता है (conversation turns same database पर SDK Session में रहते हैं).
  • Past resolved cases की small library पर semantic search के लिए pgvector use करता है।
  • Runtime पर business data के लिए Postgres से scoped, custom MCP server (customer-data) के through बात करता है, कभी Neon MCP server से नहीं और agent code में direct asyncpg से नहीं।
  • हर meaningful action के लिए audit row लिखता है (हर skill invoked, हर database write, हर refund considered) अपने own direct connection से, वह one path जो deliberately MCP boundary bypass करता है, ताकि audit trail उस system से starve न हो जिसे वह audit करता है।

End में "verification" test: customer message करता है "I haven't received my refund from order #4429, it's been two weeks." Worker फिर actions की chain run करता है। वह vector search से तीन similar past cases find करता है, सबसे similar case की resolution cite करते हुए response draft करता है, और जो किया उसे record करते हुए audit row लिखता है (और real deploy में, अगर customer Pro-tier user है तो escalate करता है)। Message itself से customer या order record resolve करने के लिए lookup tool चाहिए जिसे आप बाद में add करेंगे; Decision 8 exactly दिखाता है कि gap कहाँ है।

नीचे आने वाले prompts कैसे पढ़ें। आप इस Worker को अपने coding agent को एक small task at a time prompt करके build करते हैं। आप SQL, Python, या config type नहीं करेंगे: agent लिखता है, आप steer और check करते हैं। हर Decision numbered steps की short sequence है, और हर step same tiny loop run करता है:

  • हर Decision के top पर once orient करें: "Read CLAUDE.md and the files this touches, tell me what you see, and ask me 1-2 questions before we start." फिर steps order में करें।
  • One step does one thing. उस step का prompt paste करें और कुछ नहीं। जिस step में real code लिखा जाता है, prompt कहता है "plan first": plan पढ़ें, push back करें, approve करें, फिर build होने दें।
  • Next step से पहले check करें। हर step एक Check पर खत्म होता है, usually one plain-English question जो आप agent से पूछते हैं ("show me X"). Check pass होने तक next step पर न जाएँ।

यही पूरी discipline है: small task, prove it worked, next task. Checks skip करेंगे तो आप चार steps deep होंगे और तब पता चलेगा step one wrong था; database-backed agents ऐसे ही afternoon waste करते हैं।


Decision 1: Rules file को new architecture से update करें

इस Decision के end में आपका CLAUDE.md new architecture के guardrails encode करता है, ताकि हर बाद वाला prompt उन पर lean कर सके। One task. अपने agent को chat-agent project में open करें (जो आप लाए या scaffold किया).

Step 1: Rules file update करें।

Update CLAUDE.md so a fresh session understands this project's new
architecture and the rules that keep it intact. We've added three things on
top of the Build-AI-Agents stack: Skills in .claude/skills/, a Neon Postgres
system of record (five-table schema), and MCP wiring (Neon MCP for dev only; a
scoped customer-data MCP server for runtime). The rules it must encode,
because the model will otherwise break them: business reads and writes only
through the customer-data MCP server; audit on its own asyncpg pool, in the
same transaction as each action; never Neon run_sql in a shipped path;
pgvector registered on any connection touching embeddings, same embedding
model both ends; schema changes on a branch before main. Show me the diff
before writing.

Check. Diff accept करने से पहले पढ़ें, और "Critical rules" section सबसे hard पढ़ें। तीन rules plain, unambiguous form में survive होने चाहिए: business reads और writes सिर्फ customer-data MCP server से जाएँ; audit subsystem अपना direct connection use करे (कभी उस MCP boundary को नहीं जिसे वह audit करता है) और action के same transaction में row commit करे; और कोई general run_sql shipped path तक न पहुँचे। अगर diff इनमें से किसी को soften करे, drop करे, या ऐसी constraint invent करे जो आपने नहीं मांगी, accept करने से पहले re-prompt करें।

यह सबका step zero क्यों है। Weak rules file silently fail करती है, weeks later, जब model वही shortcut लेता है जिसे rule रोकने वाला था। यही file हर later step के prompt को short रहने देती है: disciplines यहाँ रहती हैं, इसलिए आप उन्हें हर बार repeat नहीं करते। "Business data through MCP, audit through its own direct connection" load-bearing rule है; Decision 7 बताता है कि यह independence क्यों matter करती है।


Decision 2: Schema और Skill set plan करें

इस Decision के end में आपके पास written plan होगा जिसे आपने review किया है, code की एक line से पहले। One task. Plan Mode में जाने के लिए Shift+Tab दो बार press करें (OpenCode में Plan agent पर switch करने के लिए Tab press करें): model project read कर सकता है लेकिन edit नहीं कर सकता।

Step 1: Plan लें।

Plan the customer-support Worker evolution of this project. The
foundation (OpenAI Agents SDK, your sandbox runtime, sessions, streaming,
guardrails) stays. We're adding:

1. Three Skills: summarize-ticket, find-similar-cases, escalate-with-context.
For each, propose: the description, the operational shape (script-driven
or instruction-driven), and what reference files it needs.

2. The five-table schema from Part 2 Concept 7, plus any tables specific
to a customer-support domain (probably: customers, orders, tickets, refunds).

3. The custom MCP server (customer-data), with exactly the runtime tools
our agent will need. Propose the tool list and signatures. No run_sql.

4. The audit-logging plan: what writes an audit row, what doesn't.

Output the plan as a markdown file at plans/customer-support-worker-plan.md.
Do not write code yet.

Check. Plan पढ़ें और उन दो चीज़ों पर push back करें जो first draft usually गलत करता है: vague Skill descriptions ("Summarizes tickets", ऐसी description जो correctly fire नहीं करती, Concept 3) और over-broad MCP tool inputs ("query: string", जो disguise में बस run_sql है; lookup_customer को customer_id लेना चाहिए, free text नहीं जिससे SQL build हो)। दोनों tight होने तक plan approve न करें।

Plan first क्यों। दोनों failure modes build होने के बाद hours cost करते हैं और markdown plan में minutes में fix होते हैं। पूरे Part में wrong होने की सबसे cheap जगह यही है।


SQL कौन run करता है, और कौन सा MCP server

आप पहली बार database touch करने वाले हैं, और Decisions 3 से 8 तक बहुत SQL दिखेगा। आप इसे हाथ से type या run नहीं करते। तीन components इसे own करते हैं, और दो different MCP servers दो different jobs करते हैं।

SQL / data pathकौन लिखता हैकौन run करता हैकब
Schema + migrations (यह Decision)आप describe करते हैं; agent draft करता हैNeon MCP server (dev tool जिसे आप agent से connect करते हैं)Setup में एक बार
Verification queries ("Done when" checks)Lesson में shownNeon MCP server run_sql, plain English में आपके द्वारा drivenStep worked confirm करने को
Runtime business SQL: lookups, vector search, refunds (D6)mcp-builder generate करता हैआप जो customer-data MCP server build करते हैंहर customer interaction
Audit writes (D7)Audit subsystem codeSeparate asyncpg pool (no MCP)हर action

दो MCP servers, never confused. Neon MCP server (जिसे आपने ऊपर setup step में authenticate किया) development tool है: आप उसे plain English में database provision और verify करने के लिए use करते हैं, और runtime पर कभी use नहीं करते। customer-data MCP server वह scoped server है जिसे आप Decision 6 में build करते हैं; running Worker business data के लिए उसी से, और केवल उसी से, बात करता है। Concept 12 बताता है कि production में general-purpose run_sql prompt-injection hole क्यों है।

Read, write, और drop equal authority नहीं हैं। Running Worker's tools risk के हिसाब से split होते हैं:

  • Read (lookup_customer, find_similar_resolved_tickets, D6 में built): freely run, no gate. Reads allow करना cheap है।
  • Write (issue_refund, D6 में built): customer-data server को require_approval={"always": {"tool_names": ["issue_refund"]}} से register करके approval-gated (Concept 13), ताकि money move होने से पहले human sign off करे। Audit writes append-only हैं: inserted, never updated or deleted.
  • Drop / schema change (CREATE/DROP TABLE, DDL): runtime पर callable ही नहीं। Custom server DDL tool expose नहीं करता, इसलिए approve करने को कुछ नहीं। Schema changes dev time पर ही होते हैं (यह Decision), Neon MCP server के through, temporary branch पर main को touch करने से पहले।

Rule of thumb: reads free run करते हैं, writes gated हैं, और structural changes production agent तक कभी नहीं पहुँचते।

Decision 3: Neon provision करें और schema migration run करें

Cost impact (Decision 3)

Neon का free tier Part 5 के assumed volume (~200 conversations/day) पर single Worker cover करता है। यहाँ $0/month plan करें। Free plan limits 0.5 GB storage और 100 compute-hours per project हैं (Neon pricing); उसके ऊपर Launch tier pay-as-you-go है (roughly $0.11/CU-hour + $0.35/GB-month), और worked-example Worker typically $25/month से कम रहता है। Full breakdown के लिए Part 5 की cost shape table देखें।

इस Decision के end में आपके पास live Neon database होगा जिसमें schema है, plus Session जो conversation turns उसमें persist करता है। Four small steps, और हर next से पहले check, क्योंकि broken database step तब तक invisible रहता है जब तक downstream कुछ पढ़ता नहीं। Plan Mode से exit करने के लिए Shift+Tab press करें और ensure करें कि Neon MCP server connected है (Concept 12). Agent यह सब Neon MCP tools से run करता है; आप database console नहीं खोलते।

Step 1: Project create करें।

Create a fresh Neon project called "chat-agent" and give me the
connection string for its main branch.

Check. Agent से confirm करवाएँ कि project exists है और main connection string paste करवाएँ। (आप Neon console में भी देख सकते हैं।) Connection string हाथ में आए बिना continue न करें।

Step 2: pgvector on करें।

Enable the pgvector extension on the chat-agent database.

Check. "Confirm the vector extension is now listed on the database." अगर नहीं है, तो downstream embeddings store करने वाली कोई चीज़ काम नहीं करेगी, इसलिए यही रुकें।

Step 3: Schema branch-first apply करें।

Apply our schema to chat-agent: the five-table core from Concept 7
(conversations, documents, embeddings, audit_log, capability_invocations)
plus four domain tables, customers, orders, tickets, refunds. Test it on
a temporary branch first, then merge to main. Plan the DDL first; I'll
approve before you merge.

Check. "Count the tables in the public schema, I expect nine, and confirm the embeddings index exists." Nine tables मतलब migration land हुई। कम हो तो merge cleanly apply नहीं हुआ: agent से fresh branch पर re-run करवाएँ। (यही Concept 12 का development use case है: plain English में schema work, branch पर tested, main में merge सिर्फ आपके "go ahead" के बाद।)

Step 4: .env और Session wire करें।

Write the main connection string to .env as NEON_DATABASE_URL. Then
install openai-agents[sqlalchemy] (plus asyncpg and pgvector) and back
the conversational Session with SQLAlchemySession on this same database.

Check. One short conversation run करें, फिर पूछें: "show me that the turn persisted in the Session's tables." Turn को Postgres में देखना prove करता है कि state now system of record में रहती है, सिर्फ memory में नहीं। (Agent को heads-up: SQLAlchemySession [sqlalchemy] extra के पीछे रहता है; bare openai-agents package import पर ImportError raise करता है।)


Decision 4: पहला Skill, summarize-ticket, लिखें

इस Decision के end में पहला Skill, summarize-ticket, .claude/skills/ में live होगा, और उसकी description आपकी होगी। Agent folder scaffold करता है; आप वह one field own करते हैं जिसे वह judge नहीं कर सकता।

Step 1: skill-creator install करें।

npx skills add https://github.com/anthropics/skills --skill skill-creator --agent claude-code -y

Check. Skill .claude/skills/ में land करता है। OpenCode उस folder को fallback की तरह read करता है (Concept 4), इसलिए यह one command दोनों tools serve करता है; separate --agent opencode install न चलाएँ, वह skill को .opencode/skills/ में duplicate करता है, exactly वही चीज़ जिसे rules file forbid करती है।

Step 2: Skill folder scaffold करें।

Use skill-creator to scaffold a skill named summarize-ticket in
.claude/skills/. It summarizes a customer support ticket into five
sections: Customer Context, Issue Description, Resolution Steps Taken,
Current Status, Recommended Next Action. The body should be imperative
step-by-step instructions, two examples (one short ticket, one
complex), and three edge cases (escalated ticket, ticket with no
resolution yet, irate customer). Keep the body under 200 lines.

Check. Folder, SKILL.md, body, और examples सब .claude/skills/summarize-ticket/ के under exist करते हैं। Body, examples, और edge cases skill-generated हैं और आपके review के under रहते हैं, लेकिन next step वह one piece है जिसे आप खुद लिखते हैं।

Step 3: Description own करें। description field हाथ से rewrite करें। यही Concept 3 का point concrete है: description routing surface है जो decide करती है skill कभी fire करेगा या नहीं, और scaffolded one generic होती है जहाँ hand-owned one वह triggers capture करती है जिनकी आपको सच में care है। कुछ drafts के बाद आप कुछ ऐसा settle करते हैं:

---
name: summarize-ticket
description: Summarizes a customer support ticket into a structured format with sections for Customer Context, Issue Description, Resolution Steps Taken, Current Status, and Recommended Next Action. Use when the user provides a ticket ID, asks for a ticket summary, asks "what's the status of ticket X", or asks to be brought up to speed on a ticket. Produces a concise summary suitable for handoff to another agent.
---

यह real skill पर Concept 3 की what/when/keywords discipline apply करता है: यह what name करता है (structured format में summarize), when name करता है (ticket ID, summary या status request, "bring me up to speed"), और वे keywords जिन्हें model match करता है।

Check. दो चीज़ें। Description what/when/keywords test pass करती है: पाँच ways invent करें जिनसे real user request phrase कर सकता है ("TL;DR this thread," "rundown before I escalate," "what's the status of #4471") और confirm करें कि यह उन पर fire करेगी। और body imperative, not narrative read करती है: "Look up the ticket. Extract the customer. Format as five sections," न कि "This skill is designed to help with ticket summaries." Body drift करे तो steer करें।

यह field hand-write क्यों है। यह agent को मिली पहली capability है जो tools.py में नहीं थी। Ticket mention करने वाला next message search_docs stub पर नहीं जाएगा; यह skill fire करेगा, और model यह description से ही decide करता है। Description पूरा game है; body downstream है।

Step 4: बाकी दो descriptions author करें। Same loop (scaffold, फिर description own करें) दो remaining Skills के लिए। Worker को तीनों चाहिए।

# .claude/skills/find-similar-cases/SKILL.md (frontmatter only)
---
name: find-similar-cases
description: Searches the resolved-tickets library for tickets semantically similar to a customer's described issue, returning the top 3-5 with their resolutions, ranked by how closely each matches. Use when the user describes a problem, complaint, or symptom and you need to check whether the team has handled something similar before. Calls the find_similar_resolved_tickets MCP tool. Always run this BEFORE drafting a response, so the response can reference proven prior resolutions rather than inventing a new approach.
---

Body इन steps से चलता है:

  • Context से issue description extract करें।
  • find_similar_resolved_tickets को limit=5 के साथ call करें।
  • Top three को distance values के साथ markdown table में present करें।
  • Low-confidence matches (distance above ~0.3, जहाँ lower more similar है) को explicitly "no strong prior precedent found" flag करें।

Instruction "always run this BEFORE drafting" real work कर रही है; इसके बिना model sometimes priors से reply draft करता है और library देखता ही नहीं।

# .claude/skills/escalate-with-context/SKILL.md (frontmatter only)
---
name: escalate-with-context
description: Packages a customer conversation for handoff to a tier-2 support agent. Produces a structured escalation note with customer profile, issue summary, what was already tried, why escalation is recommended, and the suggested specialist team. Use when (a) the customer is on the Pro or Enterprise tier AND the issue is unresolved after one round of investigation, (b) the customer's sentiment is clearly negative, (c) the issue involves billing >$500 or a refund decision, or (d) the user explicitly asks for a human.
---

Body पहले summarize-ticket invoke करता है ताकि structured context मिले, फिर six-section escalation note लिखता है (customer context, issue, attempted resolutions, sentiment signals, recommended team, suggested SLA). Description की चार explicit trigger conditions ही इस skill को over-fire करने से रोकती हैं; vague escalation logic वाला Worker हर चीज़ escalate करता है, जिससे purpose defeat होता है।

Check. दोनों descriptions explicit, specific triggers name करती हैं, "use when relevant" नहीं। escalate-with-context especially: उसकी चार conditions ही उसे हर message पर fire करने से रोकती हैं। अब तीनों Skills .claude/skills/ में हैं।


Decision 5: Embedding pipeline build करें और document library seed करें

Cost impact (Decision 5)

कुछ dozen resolved tickets का seed corpus, हर ticket ~300 tokens, text-embedding-3-small के $0.02 per 1M input tokens पर fraction of a cent में embed होता है। Worked-example volume पर new tickets और conversations की ongoing embedding typically $3/month से कम रहती है। Cost lever embedding budget नहीं, inference budget है।

इस Decision के end में आपके पास past resolved tickets की small library होगी, embedded और searchable. Two steps.

Step 1: Seed corpus build करें। Worker की "library" curated past resolved tickets का set है: इतना छोटा कि fast run हो, इतना varied कि search के पास distinguish करने को कुछ हो। Course इसे ship नहीं करता क्योंकि इसे लिखना exercise का part है। Agent को column shape और कुछ rows दें:

mkdir -p data/seed
# data/seed/resolved-tickets.csv (columns: id, customer_email, summary, resolution)
id,customer_email,summary,resolution
1,sara@example.com,Refund not showing up two weeks after return approved,Refund was stuck in pending due to a payment-gateway batch delay; manually re-triggered and funds posted within 24h.
2,raj@example.com,Cannot log in after email change,Account email was updated but the session cache held the old address; cleared the session and the customer logged in normally.
3,mei@example.com,Duplicate charge on a single order,Gateway retry created a second authorization; voided the duplicate and confirmed only one capture settled.

फिर: "Expand this CSV to a dozen or more varied resolved tickets, different enough that semantic search has something to tell apart."

Check. CSV में dozen-plus rows हों, genuinely different issues (refunds, logins, charges, shipping) के across spread, same three की rewordings नहीं।

Step 2: Seed और embed करें। customer_email column seeder को हर ticket insert करने से पहले customers row find-or-create करने देता है (tickets.customer_id foreign key NOT NULL है)। फिर:

Seed the sample resolved tickets so the Worker can search them later.
For each CSV row: find-or-create the customer by email, insert a
resolved ticket, store the case text as a documents row tagged
source='past_case' with the ticket id in its metadata, then embed that
text with text-embedding-3-small and link the embedding to the document.
Write one audit_log row for the whole seed run. Plan first.

यह shape arbitrary नहीं है, और यही part agent guess नहीं कर सकता: Decision 6 का find_similar_resolved_tickets embeddings को documents (source='past_case') से tickets तक join करके search करता है। Seed ने rows उस shape में lay down नहीं कीं, तो Decision 8 की search silently nothing return करेगी और आपको reason समझ नहीं आएगा। Actual seeder agent लिखता है; आप वह shape specify कर रहे हैं जिसे उसे produce करना है। Result में दो rules confirm करें, दोनों Concept 9 से और already आपके CLAUDE.md में: बाद में query करने वाले same model से embed करें, और connection पर pgvector register करें (वरना vectors garbage की तरह write back होते हैं)।

Check. Agent से result read back करवाएँ: "Count the documents tagged as past cases (should match my CSV row count), count the embeddings (should match too), confirm only one embedding model is present, and run one similarity search to show the closest match to 'refund delayed two weeks' comes back ranked." दो failure shapes: अगर वह two embedding models report करे, seed ने बीच में models mix किए, reset और re-run करें; अगर counts zero आएँ, seeder ने error swallow किया, उससे seed run वाली audit_log row read back करवाएँ (इसीलिए seeder one row लिखता है)। Decision 6 पर तब तक न जाएँ जब तक similarity search ranked results return न करे।

यह direct connection क्यों है, MCP नहीं। Seed script infrastructure है: one time, by hand, आपके द्वारा run होती है, Worker अपने आप नहीं करता। MCP boundary उसके लिए है जो agent autonomously करता है; seed script वह चीज़ है जो आप करते हैं। जब keyboard पर आप हैं, अपनी database और अपने बीच boundary मत डालें।


Decision 6: Runtime access के लिए custom MCP server लिखें

Cost impact (Decision 6)

Custom MCP server आपके Worker के साथ small service की तरह run करता है; same host पर colocated हो तो meaningful hosting cost नहीं जोड़ता (compute line तभी आएगी जब उसे separate hardware पर push करें)। Bill असल में inference में दिखता है: हर lookup_customer या find_similar_resolved_tickets call next model turn में round-trip के tokens add करता है। MCP-under-load की latency और pool-size side Concept 15 cover करता है।

इस Decision के end में scoped customer-data server running और Worker से wired होगा। Agent इसे लिखता है; आप scope steer करते हैं और one dangerous tool gate करते हैं। Four steps, और आप कोई FastMCP boilerplate hand-write नहीं करते।

Step 1: mcp-builder install करें।

npx skills add https://github.com/anthropics/skills --skill mcp-builder --agent claude-code -y

Check. mcp-builder available है (Decision 4 के skill-creator जैसा same install pattern).

Step 2: Server plan करें। Disciplines explicit steering की तरह carry करें। इसे streamable HTTP, stateless flavor पर build करें (Concept 11 का default): हर call independent request है, इसलिए server real addressable service है जिसे Worker URL से reach करता है, और traffic grow होने पर आप more than one copy चला सकते हैं। (Purely local single-Worker build stdio use कर सकता था; stateless service वह shape है जिसे आप actually ship करेंगे।)

/mcp-builder Plan a custom MCP server called "customer-data" on the
streamable-HTTP transport, stateless flavor, with exactly three scoped
tools and no general SQL tool:

- lookup_customer(customer_id): return id, email, tier, open-ticket count
- find_similar_resolved_tickets(description, limit): semantic search over
past resolved cases. Embed the description with text-embedding-3-small
(the SAME model the seed used) and register pgvector on the connection.
The search joins embeddings -> documents -> tickets.
- issue_refund(order_id, amount, reason): insert the refund, set the order
to refunded, AND write the audit_log row, all in ONE transaction.

Give each tool a clear description so the model knows when to call it.
Show me the plan before any code.

Check. Code से पहले plan पढ़ें: exactly three tools, no general SQL tool, और issue_refund refund, order-status change, और audit row को one transaction में लिखता है। कुछ missing हो तो push back करें। (एक Neon gotcha agent को तभी दें अगर आपने schema default public से हटाया है: table names schema-qualify करें, क्योंकि Neon का pooled endpoint connection release पर search_path reset करता है, इसलिए SET search_path survive नहीं करेगा। Course की default migration पर यह बस काम करता है।)

Step 3: Server build और verify करें। Plan right हो जाए तो: "Build the server exactly as we planned, three tools and no more, then start it and confirm it boots cleanly. Don't add tools I didn't ask for."

Check. Built server में हर tool की description पढ़ें: यही model पढ़ता है decide करने के लिए कि tool कब call करना है (same role जो SKILL.md description निभाती है), और vague one wrong time पर fire करती है। फिर confirm करें कि agent सबसे subtle गलती नहीं कर रहा: issue_refund body तीनों writes एक single transaction में करती है। इनमें से most disciplines आपके CLAUDE.md में भी रहती हैं, इसलिए careful agent apply करता है; आप confirm कर रहे हैं कि वे survive हुईं।

Step 4: Worker से connect करें और refund gate करें। Server को Worker में wire करें और money move करने वाले one tool के सामने human रखें:

Register the customer-data server with the Worker as a remote
streamable-HTTP server at its URL, and require human approval for
issue_refund. Leave lookup_customer and find_similar_resolved_tickets
un-gated. Check the current SDK docs for the exact registration and
approval API before wiring it.

Sign-off server register करने के तरीके पर रहता है (Concept 13 वाला require_approval switch), tool के अंदर नहीं; Claude Code या OpenCode के अंदर client की own permission prompt वही gate है।

Check. क्योंकि यह streamable-HTTP service है, server start करें, फिर Worker run करें: "Start the customer-data server, then run the Worker and ask it to list the tools it can see." उसे exactly आपके तीन tools name करने चाहिए (plus, कुछ models पर, उनके own internal helpers, जो normal है)। दो red flags: general run_sql-style tool मतलब Worker runtime पर अभी भी Neon MCP server से wired है, उसे runtime list से निकालें (Concept 12); connection error या no customer-data tools मतलब server reachable नहीं है, confirm करें कि वह running है और Worker's URL match करता है। Server itself start न हो तो agent से logs पढ़वाएँ (Concept 13 startup-import note usual cause है)।

Custom server क्यों, सिर्फ agent code में asyncpg क्यों नहीं। Concept 14 के तीन reasons, यहाँ importance order में: scope (agent database से exactly तीन चीज़ें कर सकता है, SQL की anything-allowed power नहीं), isolation (server अपने process और अपने pool में run करता है जिसे agent exhaust नहीं कर सकता), और reusability (दूसरा Worker जिसे lookup_customer चाहिए वही server से बात करता है)। Narrow surface ही पूरा security argument है, इसलिए Step 3 का check plumbing नहीं, boundary पर है।

Synchronous vs. asynchronous approval. अगर human वहीं है (live run या client का permission prompt), paused run memory में रहता है और answer मिलते ही resume करता है। Approval asynchronous हो तो, manager एक hour बाद sign off करता है, आप pause serialize करते हैं (SDK का RunState) और उसे session_id keyed खुद store करते हैं, फिर decision आने पर rehydrate और resume करते हैं। Durable home छोटा run_states table है (one row per pause: serialized state plus awaiting/approved/rejected), audit_log नहीं (append-only) और conversations पर column नहीं (conversation एक से ज्यादा बार pause हो सकती है)। Serialize/resume calls SDK की moving surface का part हैं, इसलिए Context7 से confirm करें।


Decision 7: Audit logging हर जगह wire करें

इस Decision के end में agent के own actions audit_log में recorded होंगे। MCP server already एक चीज़ log करता है, issue_refund refund transaction के अंदर अपनी audit row लिखता है (Decision 6); बाकी agent-side writes हैं: skill invocations, model calls, tool calls, guardrail trips. One task, Concept 10 वाले log_capability helper से।

Step 1: Audit helper हर boundary पर wire करें।

Wire the audit helper around the agent's own actions, at three points:
the start and end of each skill invocation, after each MCP tool call,
and around any guardrail trip. Use the separate audit connection (its
own pool), not the customer-data MCP boundary. Plan first.

Check. One throwaway conversation run करें, फिर: "Using the Neon tools, find the most recent conversation and show me every audit_log row for it, in order." Standalone Python path से आपको कम से कम message_received, one capability_invoked, और message_sent दिखना चाहिए (अभी कोई skill_activated नहीं, Decision 8 बताता है क्यों)। दो failure shapes: अगर सिर्फ MCP server की own rows (capability_invoked, refund_issued) दिखें और agent-side rows नहीं, helper wired है लेकिन fire नहीं हो रहा, agent से confirm करवाएँ कि यह streaming loop के अंदर run करता है, सिर्फ startup पर नहीं; zero rows दिखें तो audit connection database तक नहीं पहुँच रहा, audit pool को database URL के against check करवाएँ।

Audit pool separate क्यों है। यह customer-data MCP pool नहीं, अपना connection use करता है, दो reasons से: audit को data pool saturated होने पर भी succeed करना चाहिए, और audit writes को business writes के साथ connections के लिए compete नहीं करना चाहिए। ऐसा audit subsystem जो audited system से starve हो सके, audit subsystem नहीं है। Mechanics small हैं (Concept 7 tables ship करता है, Concept 10 helper ship करता है); discipline है हर boundary पर consistently call करना। (OpenCode में identical: plain Python है।)


Decision 8: Test scenario से end-to-end verify करें

यह पूरा Decision verification है: आप one real scenario पर prove करते हैं कि stack works, three steps में।

Step 1: Scenario run करें और trace पढ़ें। Agent से Worker को उस one message के against run करवाएँ जो whole stack exercise करता है:

Run the Worker and send it this customer message, then show me the
audit_log rows that conversation produced, in order:

"I haven't received my refund from order #4429, it's been two weeks."

Standalone Python cli.py से आपको कुछ seconds में तीन core rows दिखनी चाहिए, plus conditional fourth:

  1. action=message_received: user's message आता है, conversation row created.
  2. action=capability_invoked, target=mcp:find_similar_resolved_tickets: vector search similar past cases find करता है। यही key call है; agent closest past resolution पढ़ता है और draft में use करता है।
  3. action=message_sent: agent का draft reply, recorded.

Conditional fourth, action=capability_invoked, target=mcp:lookup_customer, तभी आता है जब agent के पास already customer UUID हो। First turn में usually नहीं होता (user ने order number और email दिया, UUID नहीं), इसलिए upstream layer (auth, orchestrator, या lookup_customer_by_email tool जिसे आप later add करेंगे) customer resolve करे तब तक यह skipped है। यह fine है; response फिर भी past case cite कर सकता है।

अगर refund authorized हो: action=capability_invoked, target=mcp:issue_refund row, plus MCP tool itself (Decision 6) द्वारा लिखी action=refund_issued row जो amount और reason को payload में carry करती है। अगर refund authorized नहीं है (policy check fails), reason के साथ action=refund_blocked row: no-action case replay के लिए action case जितना important है। ये सभी Concept 10 के small, agreed set of action names से आते हैं।

Check. तीन core rows (message_received, find_similar_resolved_tickets call, message_sent) present और in order हैं। अगर सिर्फ MCP server की own rows appear हों, नीचे note देखें; अगर none appear हों, Decision 7 की wiring fire नहीं हुई।

अगर आपको सिर्फ़ MCP-side rows दिखें

message_received और message_sent Decision 7 की agent-side audit wiring से आते हैं। capability_invoked और refund rows MCP server itself से आते हैं (Decision 6). अगर आपने Decision 7 skip किया है (fair learning slice), तो आपको सिर्फ़ MCP-side rows दिखेंगे। वह भी success state है: business writes के पास receipt है। Agent-side wiring तब add करें जब आपको सिर्फ outcomes नहीं, reasoning replay करनी हो।

Step 2: Skills layer fire करवाएँ। Step 1 trace में कोई skill_activated row नहीं थी: bare Agent(...) सीधे MCP tools तक पहुँचता है, summarize-ticket skill के through नहीं। Decision 4 की तीन Skills disk पर ready हैं; इन्हें light up करने के दो ways हैं।

The two paths, and the check

नीचे दोनों paths Decision 4 की same .claude/skills/ files पढ़ते हैं। इनमें से किसी के बाद, आपकी log_capability wiring capability_invoked rows के next to skill_activated row record करती है; वही new row इस step का check है।

Dev-time, zero wiring. इस project को Claude Code (या OpenCode) में open करें और scenario prompt दें। Client .claude/skills/ scan करता है, model summarize-ticket description match करता है, और आपकी log_capability wiring capability_invoked rows के next to skill_activated row record करती है। एक trace में सभी तीन layers, Skills + system of record + MCP, देखने का fastest तरीका।

Production, SDK runtime में। अपने deployed Worker को SDK की Skills capability दें, same .claude/skills/ folder पर pointed, और वह coding-agent client के बिना उन्हें खुद discover करता है। Runtime हर skill का name और description index करता है और load_skill tool add करता है, वही discovery model जो Claude Code use करता है, इसलिए Worker summarize-ticket खुद activate करता है। यह वही exact capability pattern है जिसे आपने Part 1 में throwaway skill पर run किया था, अब Worker's real skill folder पर pointed. एक gotcha carry करें: आप Skills को runtime की default capabilities (filesystem, shell, और compaction जिन पर agent already rely करता है) के ऊपर add करते हैं, replace नहीं; defaults गलती से drop करें तो agent वह abilities खो देता है जिनकी उसे जरूरत है। Part 1 का fire-a-skill section verified snippet और version-pin caveat रखता है; यहाँ minimal Worker neither wire करता है, purposefully, ताकि focus MCP boundary पर रहे।

दोनों promotion moves production तक पहुँचते हैं: system of record और MCP running Worker की चीज़ें हैं, और Skills उसके अंदर Skills capability से run करती हैं। वे different layers पर बैठते हैं; कोई भी build-time-only नहीं। अब जब Skills Worker के अंदर run करती हैं, एक safety note: skill का scripts/ उस sandbox में executable code है, इसलिए skill folder trust boundary है। UnixLocalSandboxClient कोई isolation नहीं देता; Docker, E2B, Cloudflare, या Modal contain करते हैं। अपनी skill library की write access को deploy access की तरह treat करें, और वे skills load करने से पहले sandbox isolate करें जिन्हें आपने खुद नहीं लिखा।

Know the Memory capability, and what it isn't

Same capabilities list Skills() के साथ Memory() भी लेती है (दोनों agents.sandbox.capabilities से). इसे precisely जानना worth है, क्योंकि यह वही चीज़ लगती है जो आपने अभी build की, लेकिन है नहीं। Memory() Worker को अपने past runs से learn करने देता है: sandbox session close होने पर यह हर run की conversation को workspace files (MEMORY.md और summary) में distill करता है, और later runs उन्हें read back करते हैं, ताकि agent कम explore करे और कम corrections repeat करे। यह Concept 3 वाली "have we seen a question like this before?" recall है, runtime द्वारा handled, इसलिए आप इसे hand-build नहीं करते।

यह durable business record नहीं है। Sandbox memory file-based है, recency से oldest entries prune करती है, और beta में है; fresh sandbox empty start करता है, और agent को इसे guidance की तरह treat करने को कहा जाता है, authoritative storage की तरह नहीं। आपकी Neon tables हर count पर opposite हैं: durable, complete, stable, SQL में queryable. इसलिए आपको दोनों चाहिए, अलग jobs के लिए। Memory() agent को runs के across smarter बनाता है; system of record उसके work को durable, provable, and sellable बनाता है: वह asset जिसकी ownership आपके पास है। SDK docs में Sandbox agents के under चार pages इस whole layer का source हैं; companion AGENTS.md चारों link करता है।

Step 3: Replay query run करें। यह वही proof है जिसके लिए पूरा audit layer था। Agent से अभी run की गई conversation का trace pull करवाएँ:

Using the Neon tools, take the most recent conversation and show me its full audit_log trace, in order: created_at, action, target, payload, result.

Check. उस output को पढ़ते हुए, आप line by line reconstruct कर सकें कि agent ने क्या किया और क्यों, बिना model re-run किए। अगर नहीं कर सकते, अगर कोई step हुआ जो log में नहीं है, या row ऐसा action claim करती है जो business tables में reflect नहीं होता, तो wiring bug है। Worker done कहने से पहले उसे fix करें।

यह scenario क्यों। यह course जो architectural pieces add करता है, यह उन्हें exercise करता है: MCP-backed tools (lookup_customer, find_similar_resolved_tickets) system of record के against run करते हैं, और audit trail path record करता है, सब SQL में replayable. पिछले course के chat agent में यह कुछ नहीं था। Skills layer third piece है, और ऊपर callout दिखाता है कि वह trace से कहाँ जुड़ती है। Verification client-agnostic है: Claude Code और OpenCode same trace produce करते हैं (standalone Python cli.py ऊपर वाले reason से skill_activated row के बिना produce करता है).


अभी क्या हुआ

Eight Decisions, और पिछले course का chat agent अब Worker की foundation रखता है। देखें क्या बदला:

  • Capability code से बाहर move हुई। तीन Skills .claude/skills/ में बैठती हैं, version-controlled, agents के across sharable.
  • Durable stores process से बाहर move हुए। Real Postgres schema (five-table core plus customers, orders, tickets, और refunds के लिए domain layer) अब Worker's system of record और वह reference library hold करता है जिसे वह pgvector से search करता है, जबकि SDK Session same database पर Worker's conversation state रखता है।
  • Runtime business access mediated है। Agent Postgres में business data तक सिर्फ scoped MCP server से पहुँचता है जो exactly तीन tools expose करता है; हर business read और write उस one boundary से cross करता है। Audit subsystem one deliberate exception है, अपने direct connection पर, ताकि वह उस boundary से starve न हो जिसे वह audit करता है।
  • हर action trace छोड़ती है। Audit log किसी भी conversation की full reasoning trace weeks या months बाद SQL में replay कर सकता है।

OpenAI Agents SDK अब भी है। Sandbox अब भी आपका compute है, और previous course की streaming, guardrails, और tracing सब अब भी हैं। बदली है ऊपर की architecture: Skills capabilities hold करती हैं, system of record truth hold करता है, MCP उन्हें wire करता है।

यही Worker की foundation है। जो यह अभी नहीं है: always-on, proactive, या managed workforce का part. वे moves अगले courses add करते हैं।


Part 5: यह course कहाँ छोड़ता है

Worker की cost shape: operate करने की actual cost क्या है?

Previous course में "हर turn दुनिया को फिर से bill करता है" thread था; इस course ने अभी तक dollars पर quiet रखा। Gap close करते हुए, specifically Part 4 worked example के लिए: customer-support Worker जो 200 conversations per day करता है, ~10 turns per conversation, average context 8K tokens per turn, तीन Skills, तीन MCP tools. नीचे हर dollar figure May 2026 estimate है: per-token prices और tier limits बदलते हैं, इसलिए ranges को orders of magnitude समझें और budget बनाने से पहले vendor pages check करें।

Four cost lines, size के order में।

LineDriverRough monthly costकब bite करता है
Model inferenceinput tokens × turns × $/M$60-$200Volume × prompt size. Stable prefixes (CLAUDE.md, Skills metadata, system prompt) पर cache hits typically 60-80% input cost recover करते हैं।
Neon Postgresstorage + active compute$0-$25Free tier इस volume वाला single Worker cover करता है। Scale-to-zero का मतलब idle hours कुछ cost नहीं करते। Paid tier तब kick in करता है जब project 0.5 GB / 100 CU-hours free-plan limits cross करे (current numbers के लिए Neon pricing देखें).
Embeddingschunks × $0.02/M tokens$0.30-$3Seed data के लिए one-time cost plus new tickets/messages की incremental embedding. Negligible जब तक आप entire conversation histories continuously embed नहीं कर रहे।
Sandbox computecontainer minutes$0-$15Worked example UnixLocalSandboxClient पर $0 में run करता है। यह line production compute (Docker, Cloudflare, E2B, Modal) के लिए है और session length तथा concurrency पर depend करती है। Idle reaping मदद करती है; long-running sessions नहीं।

Part 4 Worker के लिए total monthly: roughly $60-$240. Model सबसे बड़ी line है, बाकी सब से order of magnitude ऊपर। System of record इस volume पर essentially free है। Skills discipline (progressive disclosure, Concept 2) cost discipline भी है: bloated SKILL.md bodies वाला Worker हर turn pay करता है जो उन्हें activate करता है; descriptions-only-at-discovery और tight bodies-on-activation वाला Worker सिर्फ़ जो use करता है उसका pay करता है।

तीन knobs जो dial सबसे ज़्यादा move करते हैं। (1) Cache hit rate: अपने CLAUDE.md, system prompt, और Skills metadata stable रखें; cache misses hits से 5-10x ज़्यादा cost करते हैं। (2) Model tier: वही Worker cheaper model (DeepSeek V4 Flash, Claude Haiku) पर अक्सर cost के 10% में job का 80% कर देता है; hard decisions को frontier model पर route करें only when needed. (3) Audit table growth: audit_log row count से largest table है (Concept 7 का PRIMM Predict); अगर आप historical audit data actually query नहीं करते तो 90 days के बाद partition या archive करें।

Honest scaling number. इस shape पर 50 Workers की workforce (जो आपका next course cover करता है) inference के लिए roughly $3,000-$12,000/month, Neon के लिए $50-$200, embeddings के लिए single-digit dollars, sandbox compute के लिए $100-$500 है। Infrastructure layer cheap रहती है; model bill scale करता है। इसी वजह से previous course की हर cost-discipline habit (cache hits, model tiering, context hygiene) एक Worker से many Workers पर जाते समय compound होती है।


Swap guide: architecture invariant है, products नहीं

यह course हर layer पर specific vendors name करता है (OpenAI Agents SDK, SDK का local sandbox, Neon, OpenAI embeddings, MCP Python SDK). इसलिए कि teaching example को concrete answers चाहिए, "अपना मनपसंद LLM runtime use करें" नहीं। लेकिन architecture किसी भी compliant alternative के साथ काम करती है। Course की design explicitly पाँच swaps anticipate करती है:

  • Postgres host: Neon → Supabase, AWS RDS, self-hosted. pgvector वाली कोई भी चीज़ काम करती है। आप branching और scale-to-zero खोते हैं (वे Neon-specific हैं), लेकिन five-table schema, embedding pipeline, audit-trail discipline, और custom MCP server pattern byte-for-byte transferable हैं। Only change connection string और शायद SSL config है।
  • Vector storage: pgvector → Pinecone, Weaviate, Qdrant. अगर आप Concept 6 की "relational और vector data दोनों के लिए one database" argument reject करते हैं, तो embeddings table को vector-DB client से swap करें। Cost: consistent रखने के लिए two stores (Concept 6 कहता है rarely worth it). Benefit: very large scales (10M+ vectors) पर better recall, और managed-service operational simplicity.
  • Embedding model: OpenAI → Cohere, Voyage, BGE-small (local). एक constant (EMBEDDING_MODEL) और एक column dimension (VECTOR(n)) change करें। Existing data का one-shot re-embed run करें। Concept 9 की pipeline नहीं बदलती।
  • Sandbox: local sandbox → Cloudflare, E2B, Modal, Daytona, अपना Docker. Isolated process boundaries और clean restart वाली कोई भी चीज़ काम करती है। SandboxAgent runtime backend-agnostic है; worked example UnixLocalSandboxClient पर run करता है, और production इन में से किसी पर swap करता है। Skills के scripts/ same way execute करते हैं। Previous course का trust-boundary diagram अब भी apply करता है।
  • Agent runtime: OpenAI Agents SDK → LangGraph, CrewAI, Pydantic AI, अपना loop. MCP boundary survive करती है; हर modern agent framework के पास MCP client है। Skills किसी भी agent में काम करती हैं जो SKILL.md files load कर सकता है (Claude Code, OpenCode, Goose, और increasingly Cursor/Windsurf). Audit-trail discipline framework-agnostic Python है।

जो easily swap नहीं होता। MCP protocol itself, Skills format spec, और audit-trail habit. ये वे parts हैं जिन्हें आप products के across carry करते हैं; products वे parts हैं जिन्हें आप swap करते हैं। नीचे same architectural shape, ऊपर replaceable implementations.

"Invariant" और "owned" पर एक word. दोनों heuristics हैं जिन पर bet लगाना worth है, settled facts नहीं। "Invariant" 2026 के best-available open standards को name करता है: MCP लगभग 18 months old है और Skills spec उससे younger है, और एक दिन wire या capability format itself replace हो सकता है, सिर्फ़ उसमें plugged products नहीं। Proprietary ones के बजाय open protocols पर bet करना अच्छी aging strategy है, लेकिन architecture को durable-by-design समझें, eternal नहीं। और "owned" सच में owned-by-composition है: यह Worker Neon cloud, vendor models, coding-agent client, और third-party repos से pulled skills पर run करता है। आपकी ownership freedom है कि किसी भी एक को बाकी rewrite किए बिना swap कर सकें। यह real है और बहुत valuable है, लेकिन word के full sense से less है। Interfaces own करें, substrate नहीं।


यह course क्या cover नहीं करता (yet)

अब आपके पास ऐसा Worker है जो thesis के Seven Invariants में से दो satisfy करता है। Specifically: यह engine पर run करता है (Invariant 4, previous course से), और system of record के against run करता है (Invariant 5, इस course से)। बाकी पाँच Invariants production AI-Native Companies require करती हैं, और subsequent courses cover करते हैं। यहाँ हर एक bullet है, section नहीं।

  • Invariant 1: The human is the principal. Authored specs, approval gates, budget declarations. Intent set करने और outcomes own करने की architecture, book के Part 6 में covered.
  • Invariant 2: Every human needs a delegate. Edge पर personal agent जो आपका context hold करता है, आपके judgment को represent करता है, और workforce को work broker करता है। Thesis OpenClaw को current realization name करता है।
  • Invariant 3: The workforce needs a manager. Orchestrator जो work assign करता है, budgets enforce करता है, execution audit करता है, hiring को callable capability की तरह expose करता है। Thesis Paperclip को name करता है।
  • Invariant 6: The workforce is expandable under policy. Meta-layer जहाँ authorized agent prompt generate करता है, runtime provision करता है, और new Worker register करता है, human को जगाए बिना। Claude Managed Agents एक realization है।
  • Invariant 7: The workforce runs on a nervous system. Triggers (schedules, webhooks, inbound API calls) authority envelope के under agent को wake करते हैं। Inngest (durable functions और background jobs) general workforce events के लिए एक realization है; Claude Code Routines coding-agent-specific path है।

System of record से read करता single Worker वह smallest unit है जिसकी architecture यह course सिखाता है। Next course उस Worker को workforce में extend करता है: manager द्वारा coordinated multiple Workers, on demand expandable, triggers से woken. Same SDK, same Skills format, underneath same Postgres system of record.


इसमें सच में अच्छा कैसे बनें

यह crash course पढ़ना आपको Workers build करने में अच्छा नहीं बनाता। इसे use करना बनाता है। Path previous course जैसा है: आप manual शुरू करते हैं, friction महसूस करते हैं, और friction का हर piece आपको सिखाता है कि वह कौन से Concept से belong करता है।

इस course की mapping:

  • "मेरा skill तब fire क्यों नहीं हो रहा जब होना चाहिए?" → description quality (Concept 3). Rewrite करें। पाँच different ways invent करके test करें जिनसे user trigger phrase कर सकता है।
  • "Agent ऐसा data invent क्यों कर रहा है जो database में नहीं है?" → agent सच में MCP server call नहीं कर रहा। Trace check करें; mcp_servers=[...] registration check करें।
  • "मेरा audit log incomplete क्यों है?" → audit write action के same code path में नहीं है (Concept 10). उसे action के next to move करें, same transaction में।
  • "मेरे pgvector results irrelevant क्यों हैं?" → या chunking wrong है (Concept 9), या insert-time embedding model query-time embedding model से match नहीं करता। Re-embed.
  • "मेरा MCP server load में slow क्यों है?" → server के अंदर connection pool बहुत small है, या client पर tools list cached नहीं है। Concept 15.
  • "Neon MCP server production में scary क्यों लगता है?" → क्योंकि Neon के अपने docs कहते हैं कि यह production के लिए नहीं है। Custom MCP server लिखें (Concept 14). पहला 30 minutes लेता है; दूसरा 10.

Architecture को एक piece at a time build करें। एक weekend में Skills, system of record, और MCP all at once add करने की कोशिश न करें। Previous course का chat agent लें। पहले system of record add करें (Decisions 3-5) और देखें आपका debugging experience कैसे बदलता है। Skill add करें (Decision 4) और देखें model उसे use करने का decision कैसे लेता है। MCP boundary last add करें (Decision 6). हर step अपनी learning है; तीनों एक साथ करना wall है।

Portability dividend real है: Skills, schemas, और MCP servers जो आप यहाँ लिखते हैं, सब other products में move होते हैं। Swap guide per-layer alternatives list करता है।

आप किस चीज़ पर time spend करते हैं, उसमें shift

Decision 4 के बाद आपके work की shape बदलती है। Code लिखना agent को brief करना बनता है; description review करना (config-file field जिसे normally skim करते) key craft बनता है। आपने description draft और refine करने में जो 30 minutes spend किए, वह agent द्वारा generated 200 lines MCP server code से ज़्यादा architectural work करता है, क्योंकि description वह routing surface है जिसे model हर turn पढ़ता है।

दो practical shifts. First, आप पूछना बंद करते हैं "मैं इसे implement कैसे करूँ?" और पूछना शुरू करते हैं "real user trigger phrase करने के पाँच different ways क्या हैं?" Code downstream है; अगर description wrong है, agent code तक पहुँचता ही नहीं और code की quality irrelevant है। Second, review authorship को key skill की तरह replace करता है। Agent draft करता है; आप decide करते हैं कि draft उन trigger cases में work करता है या नहीं जिनके लिए आपने description लिखा था। Hardest part है rewrite करने की urge resist करना जब आप खुद तीन minutes में solve कर सकते हैं: वही discipline जो आपको MCP boundary bypass करने से रोकती है।


Quick reference

15 concepts, हर एक one line में

  1. Agent Skill एक folder है। SKILL.md plus optional scripts/references/assets.
  2. Progressive disclosure. Startup पर metadata → activation पर full body → demand पर references.
  3. SKILL.md frontmatter + body है। Name, description, optional metadata, फिर operational instructions.
  4. Skills files की तरह travel करती हैं। Same SKILL.md Claude Code और OpenCode में बिना modification काम करता है।
  5. Small skills को filesystem handoff से compose करें जब isolation orchestration simplicity से ज़्यादा matter करे।
  6. Postgres + pgvector almost all agent workloads के लिए separate vector DB से बेहतर है। Neon branching, scale-to-zero, और MCP server add करता है।
  7. Five tables minimum operational schema हैं: conversations, documents, embeddings, audit_log, capability_invocations; conversation turns same database पर SDK Session (SQLAlchemySession) में रहते हैं।
  8. pgvector basics: VECTOR(1536) + <=> cosine distance + HNSW index. दोनों ends पर same embedding model use करें।
  9. Embedding pipeline: semantic boundaries पर chunk करें (~400 tokens with overlap), batch-embed करें, model metadata के साथ store करें।
  10. Audit सिर्फ logging नहीं है। हर meaningful action उसी transaction में row write करती है जिस action को वह record करती है।
  11. MCP protocol है, service नहीं। Three primitives (tools, resources, prompts), three transports (stdio, streamable HTTP, legacy SSE).
  12. Neon MCP server development के लिए है। Schema design, branch-based migrations. Production runtime के लिए नहीं।
  13. OpenAI Agents SDK में built-in MCP client है। from agents.mcp import MCPServerStdio, MCPServerStreamableHttp. async with use करें। Production में list_tools cache करें।
  14. Custom MCP servers scope, isolation, और reusability से अपनी जगह earn करते हैं। Single agent द्वारा use होने वाली single function के लिए server न लिखें।
  15. MCP under load: remote के लिए streamable HTTP, tools cache करें, connections reuse करें, server के अंदर pool करें, _meta से trace context propagate करें।

जब कुछ गलत लगे

Skill not firing when it should
→ Description too vague. Rewrite with "Use when..." and specific keywords (Concept 3).

Skill firing when it shouldn't
→ Description too broad. Add explicit constraints in the description.

pgvector returning irrelevant results
→ Embedding model mismatch (insert vs. query). Verify the model column in
the embeddings table. Re-embed if needed.

MCP tool not appearing in agent
→ Server not registered, or list_tools cache stale. Check mcp_servers=[...]
and try cache_tools_list=False temporarily.

Audit log has gaps
→ Action and audit write are in different code paths. Move them next to
each other, ideally same transaction.

Agent timing out on Postgres operations under load
→ MCP server's connection pool too small. Check asyncpg.create_pool(max_size=...).

MCP server hangs on startup with torch / sentence-transformers / large imports
→ Default client_session_timeout_seconds=5 is too short for servers that
load ML models at import. Bump to 60. See Concept 13's callout.

CREATE TABLE fails: relation "notes" already exists
→ You're pointing at a database that already has tables. Use a fresh
database or Neon project; the Quick Win's build prompt makes a fresh one.

Non-OpenAI key getting 401 against api.openai.com
→ Set OPENAI_BASE_URL to your provider's OpenAI-compatible endpoint
(e.g., https://api.deepseek.com/v1) before running the agent.

Agent fails partway with a 401 / auth / BadRequestError
→ Wrong key, wrong provider, or expired key. Have your agent confirm
OPENAI_API_KEY is set and test a model call before the full run; it
fails in one second instead of four files deep.

Neon MCP server returning errors in production agent code
→ You're using it wrong. Neon's docs are explicit: development only.
Write a custom MCP server instead (Concept 14, ~30 minutes).