SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-28

SandBase agent runtime को self-host कैसे करें

SandBase Harness v0.3.2 को अपने VPS पर सेटअप करने की पूरी प्रक्रिया जानें। इसमें tagged install, agent YAML कॉन्फ़िगरेशन, MCP सर्वर और Anthropic SDK को कनेक्ट करने के स्टेप्स शामिल हैं।

SandBase agent runtime को self-host करने पर आपको क्या मिलता है

SandBase agent runtime को self-host करने का अर्थ है SandBase Harness को अपने स्वयं के सर्वर पर चलाना। इससे sessions, credentials, memory और audit trails किसी और के सर्वर के बजाय आपकी अपनी डिस्क पर सुरक्षित रहते हैं। यह एक Node service है। यह 127.0.0.1:3000 पर listen करती है, एक /v1 HTTP API और web console प्रदान करती है, और अपनी state को आपके agent files के साथ SQLite में रखती है।

/v1 API को Claude Managed Agents (CMA), जो कि एक hosted managed-agent API है, के आधार पर तैयार किया गया है। यही कारण है कि यह runtime दोनों दिशाओं में उपयोगी है: आप Anthropic SDK का उपयोग करके कोड लिख सकते हैं और इसके baseURL को अपने सर्वर की ओर point कर सकते हैं, और बाद में उसी कोड को किसी hosted deployment पर ले जा सकते हैं।

SandBase Harness कोई model प्रदान नहीं करता है। यह एक model को call करता है। अगस्त 2026 तक, यह OpenAI, Anthropic और OpenAI-compatible endpoints को support करता है, जिसमें self-hosted gateways और DeepSeek V4 जैसे providers शामिल हैं। आपको अपना API key स्वयं प्रदान करना होगा, या एक ऐसा local सर्वर उपयोग करना होगा जो OpenAI API के अनुरूप हो।

शुरू करने से पहले आपकी आवश्यकताएं

  • कम से कम 2 GB RAM वाला Ubuntu 24.04 पर चलने वाला एक VPS। TypeScript build इस इंस्टॉलेशन का सबसे भारी चरण है।
  • Node.js 22 या उससे नया, और npm 10 या उससे नया। ये दोनों प्रोजेक्ट द्वारा निर्धारित अनिवार्य न्यूनतम आवश्यकताएं हैं।
  • git, साथ ही उस मॉडल प्रदाता के लिए एक API key जिसका आप उपयोग करने की योजना बना रहे हैं।
  • Docker, लेकिन केवल तभी यदि आप प्रति-सत्र (per-session) कंटेनर सैंडबॉक्स चाहते हैं।

Ubuntu 24.04 अपने रिपॉजिटरी में Node 18.19 प्रदान करता है, जो न्यूनतम आवश्यकता से कम है, इसलिए Node को NodeSource से प्राप्त करें।

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs git
node -v
npm -v

node -v को v22 या उससे अधिक प्रिंट करना चाहिए और npm -v को 10 या उससे अधिक प्रिंट करना चाहिए। यदि node -v अभी भी v18.19.1 प्रिंट करता है, तो इसका मतलब है कि डिस्ट्रीब्यूशन पैकेज अभी भी इंस्टॉल है और PATH पर प्राथमिकता ले रहा है। आगे बढ़ने से पहले इसे हटा दें, क्योंकि बिल्ड उसी node के साथ चलता है जिसे शेल सबसे पहले ढूंढता है।

v0.3.2 tag से SandBase इंस्टॉल करें

हमेशा एक tag से इंस्टॉल करें, कभी भी moving branch से नहीं। main का एक bare clone आपको वह सब देता है जो एक घंटे पहले ही merge हुआ है, और नीचे दिए गए config keys शायद उससे मेल न खाएं। 16 August 2026 तक v0.3.2 वर्तमान tag है।

sudo install -d -o "$USER" -g "$USER" /opt/sandbase
cd /opt/sandbase
git clone --branch v0.3.2 --depth 1 https://github.com/sandbaseai/sandbase-harness.git
cd sandbase-harness
npm ci
npm run build

npm install का नहीं, npm ci का उपयोग करें। ci कमिट किए गए lockfile में दर्ज सटीक versions को इंस्टॉल करता है, इसलिए आपका tree उस tree से मेल खाता है जिसे maintainers ने टेस्ट किया है। npm install को नए versions resolve करने की अनुमति होती है, और इसी तरह एक pinned tag चुपचाप unpinned हो जाता है।

अब एक workspace बनाएं। workspace एक अलग directory है जो आपकी agent files और सभी runtime state को रखती है, और इसे source checkout के बाहर रखने का मतलब है कि आप अपने डेटा को छुए बिना एक नया tag pull कर सकते हैं।

mkdir -p /opt/sandbase/workspace
cd /opt/sandbase/workspace
node /opt/sandbase/sandbase-harness/dist/index.js init
node /opt/sandbase/sandbase-harness/dist/index.js start

init workspace में एक .managed-agents/ directory लिखता है। start console को http://127.0.0.1:3000/dashboard पर और API को http://127.0.0.1:3000/v1 पर लाता है। अभी इनमें से कोई भी आपके laptop से reachable नहीं है, जो कि सही है और आगे इस पर विस्तार से चर्चा की गई है। अभी के लिए SSH के माध्यम से console तक पहुँचें:

ssh -N -L 3000:127.0.0.1:3000 you@your-server

वह लंबा node .../dist/index.js path थकाऊ हो जाता है, इसलिए इसे एक नाम दें।

alias sandbase='node /opt/sandbase/sandbase-harness/dist/index.js'

नीचे दिए गए commands को इसी आधार पर sandbase <command> के रूप में लिखा गया है।

इसे npm से install न करें

Project के अपने installation documentation में यह स्पष्ट लिखा है: npm पर दिखने वाला unscoped managed-agents package इस project का नहीं है। इसलिए npx managed-agents और npm install -g managed-agents चलाने पर आपको वह runtime नहीं मिलेगा जिसकी आपको आवश्यकता है। जब तक maintainers किसी आधिकारिक scoped package की घोषणा न कर दें, तब तक इसे tagged GitHub source से ही install करें। यह project के इतिहास में कोई छोटी-मोटी बात नहीं है: v0.3.1 का मुख्य उद्देश्य पुराने npm quick start को हटाकर उसे pinned tagged-source path से बदलना है।

Workspace को एक model provider पर point करें

init, .managed-agents/config.yaml लिखता है। पूरे workspace के लिए एक provider configure किया जाता है, और फिर अलग-अलग agents concrete model IDs चुनते हैं।

model:
  provider: openai
  api_key: ${OPENAI_API_KEY}
storage:
  metadata:
    provider: sqlite
    options: {}
  artifacts:
    provider: local
    options:
      base_path: files

${OPENAI_API_KEY} form process environment से value लेता है, इसलिए key config file से बाहर रहती है और उस file के हर backup से भी दूर रहती है। इसे एक ऐसी environment file में रखें जिसे केवल root ही पढ़ सके, क्योंकि systemd privileges drop करने से पहले EnvironmentFile= को root के रूप में पढ़ता है।

sudo install -d -m 750 /etc/sandbase
sudo touch /etc/sandbase/runtime.env
sudo chmod 600 /etc/sandbase/runtime.env

उस file को एक editor में खोलें और एक line जोड़ें, OPENAI_API_KEY=sk-...। Provider keys यहीं होनी चाहिए। वे secrets जिनका उपयोग एक agent session के दौरान करता है, उन्हें runtime के credential vaults में रखा जाना चाहिए। यह एक अलग समस्या है जिसका blast radius भी अलग है, और AI agents से secrets को दूर रखना पढ़ना उपयोगी होगा, इससे पहले कि आप किसी production token को कहीं भी paste करें।

Agent YAML: mcp_servers, tools और permission policies

Agents को workspace के agents/ directory में YAML files के रूप में define किया जाता है। runtime का यही वह हिस्सा है जहाँ आप वास्तव में समय बिताएंगे। जब आप हाथ से एक छोटा agent loop लिख लेंगे, तो ये keys अधिक स्पष्ट हो जाएंगी, क्योंकि इनमें से प्रत्येक उस चीज़ का एक नियंत्रण (knob) है जिसे आप अन्यथा खुद code कर रहे होते: system prompt, tool list, और tool चलने से पहले होने वाली जाँच।

name: Incident commander
description: Triages alerts and coordinates response.
model: gpt-4o
system: |-
  You are an on-call incident commander.
mcp_servers:
  - name: sentry
    type: url
    url: https://mcp.sentry.dev/mcp
tools:
  - type: agent_toolset_20260401
    default_config:
      permission_policy: { type: always_ask }
    configs:
      - name: bash
        permission_policy: { type: always_ask }
  - type: mcp_toolset
    mcp_server_name: sentry
metadata:
  template: incident-commander

इसे load करें और जाँचें कि यह सही जगह पहुँच गया है:

sandbase reload
sandbase list
sandbase chat agent_assistant --message "hello"

reload seed YAML को SQLite में import करता है। list को अब agent को उसके ID के साथ print करना चाहिए। यदि list में यह नहीं दिखता है, तो file parse नहीं हुई है, और .managed-agents/logs/runtime.log वह स्थान है जहाँ इसका कारण लिखा होता है।

mcp_servers MCP (model context protocol) endpoints घोषित करता है। type: url का अर्थ है कि runtime ऐसे server से HTTP के माध्यम से बात करता है जो कहीं और चलता है। इसलिए आपके द्वारा पहले से संचालित कोई भी चीज़ यहाँ काम कर सकती है, जिसमें runtime के समान VPS पर hosted MCP servers भी शामिल हैं। Web search आम तौर पर लोगों द्वारा इस्तेमाल किया जाने वाला पहला tool होता है। लेकिन इसे configure करने से पहले अपने agent को अपना SearXNG instance देना पढ़ना उपयोगी है, क्योंकि अजनबियों द्वारा लिखे गए pages लौटाने वाला tool untrusted text को सीधे model के context में डाल देता है। शुरुआती wiring के लिए अधिक सुरक्षित तरीका इसका उलटा है: आपके स्वामित्व वाले data पर read-only endpoint। यही सुविधा openGym workout tracker के साथ उपलब्ध कराता है। इससे agent आपकी training history के बारे में questions का answer दे सकता है, लेकिन उसमें कोई बदलाव नहीं कर सकता।

Server declare करने से उसके tools agent को नहीं मिलते। tools list ऐसा करती है, एक mcp_toolset entry के माध्यम से जिसका mcp_server_name ऊपर दिए गए name से मेल खाता है। यदि agent ऐसा व्यवहार करता है जैसे MCP tools मौजूद ही नहीं हैं, तो कहीं और देखने से पहले उन दोनों strings की अक्षर-दर-अक्षर तुलना करें।

agent_toolset_20260401 built-in tool set है। दिनांकित suffix एक schema version है, इसलिए इससे जुड़ा agent उन tool definitions को बनाए रखता है जिनके आधार पर इसे लिखा गया था। default_config set के प्रत्येक tool के लिए policy निर्धारित करता है, और configs के अंतर्गत प्रत्येक entry नाम के आधार पर एक tool को override करती है, जैसे उदाहरण में bash

permission_policy वह जगह है जहाँ एक runtime, bare model call की तुलना में अपनी उपयोगिता साबित करता है। always_ask session को रोक देता है और call चलने से पहले human approval का इंतज़ार करता है। always_allow इसे अनुमति देता है। bash को always_ask पर set करने का अर्थ है कि agent आपके द्वारा सटीक command देखे बिना shell command नहीं चला सकता, जो कि वही नियंत्रण है जिसे आप Claude Code को सुरक्षित रूप से VPS पर चलाने के समय अपनाते हैं। यदि आप DeepSeek Harness भी चलाते हैं, तो वही नियंत्रण वहाँ YAML keys के बजाय add-ons के रूप में आते हैं, और budget को सीमित करने और tool calls को नियंत्रित करने वाले plugins इस block के सबसे करीबी विकल्प हैं।

तीन सैंडबॉक्स मोड, और प्रत्येक कब उपयुक्त है

कोड निष्पादित करने वाले टूल कॉल एक सैंडबॉक्स के भीतर चलते हैं। बैकएंड का चयन प्रति एनवायरनमेंट किया जाता है, जो एनवायरनमेंट के config ऑब्जेक्ट में sandbox_provider के माध्यम से, या कंसोल में Settings के अंतर्गत Sandbox में होता है। एनवायरनमेंट POST /v1/environments पर API के माध्यम से बनाए जाते हैं।

local कोड को रनटाइम की चाइल्ड प्रोसेस के रूप में, होस्ट पर, रनटाइम के स्वयं के यूजर के रूप में चलाता है। यह डिफ़ॉल्ट है, और जब आप एकमात्र यूजर होते हैं और एजेंट केवल आपकी स्वामित्व वाली फाइलें पढ़ता है, तब यह उचित है। यह आइसोलेशन नहीं है। एक टूल कॉल जो फाइलें डिलीट करता है, वह आपकी फाइलें डिलीट कर देता है, और एक टूल कॉल जो /etc/sandbase/runtime.env पढ़ता है, वह आपकी प्रोवाइडर की (provider key) पढ़ लेता है।

docker प्रति सेशन एक कंटेनर शुरू करता है।

{
  "sandbox_provider": "docker",
  "image": "node:22-slim",
  "resources": { "memory": "1g", "cpu": 1 }
}

सेशन को अपना फाइलसिस्टम, अपनी मेमोरी सीलिंग और अपना CPU शेयर मिलता है, और सेशन के साथ कंटेनर को हटा दिया जाता है। जिस क्षण कोई एजेंट ऐसा कोड चलाए जिसे आपने नहीं लिखा है, उस क्षण इस पर स्विच करें। इसकी लागत यह है कि रनटाइम के यूजर को Docker सॉकेट तक पहुंच की आवश्यकता होती है, और docker ग्रुप की सदस्यता होस्ट पर root के बराबर है। प्रति-सेशन कंटेनर प्रति रन एक कंटेनर वाले सेल्फ-होस्टेड एजेंट सैंडबॉक्स के समान ही होते हैं, इसलिए एक एस्केप्ड प्रोसेस क्या एक्सेस कर सकती है, इस बारे में तर्क यहाँ अपरिवर्तित रूप से लागू होता है।

kubernetes सेशन वर्कलोड को एक पॉड के रूप में चलाता है और इसे kubectl exec और kubectl cp के साथ संचालित करता है। रनटाइम इमेज में kubectl का होना आवश्यक है, और इसके ServiceAccount को टारगेट नेमस्पेस में पॉड्स को बनाने, डिलीट करने, प्राप्त करने, लिस्ट करने और वॉच करने के लिए RBAC (रोल-आधारित एक्सेस कंट्रोल) अनुमति की आवश्यकता होती है, साथ ही exec सब-रिसोर्स की भी। यह मोड सेटअप करने योग्य तभी है यदि आप पहले से ही एक क्लस्टर चला रहे हैं।

Runtime को 127.0.0.1 पर क्यों bind किया गया है?

ऐसा इसलिए है क्योंकि यह authentication बंद होने के साथ शुरू होता है। जब कम से कम एक API key मौजूद होती है, तो runtime bearer-token authentication को सक्षम कर देता है, लेकिन एक नया init कोई key नहीं बनाता है। यदि इसे उस default पर 0.0.0.0 पर bind कर दिया जाए, तो एक unauthenticated agent runtime, जिसमें shell tools और आपका provider key मौजूद है, public internet पर expose हो जाएगा।

इसलिए जब आप इसे reachable बनाना चाहते हैं, तो bind address को न बदलें और दो अन्य काम करें।

सबसे पहले, authentication को चालू करें। service environment file में MANAGED_AGENTS_API_KEY सेट करें, या POST /v1/api-keys के साथ एक key बनाएँ, जो एक बार secret_key field लौटाती है और उसे दोबारा कभी नहीं दिखाती है। इसके बाद clients हर request पर Authorization: Bearer <key> भेजते हैं। एक key एक shared identity होती है, इसलिए यदि आप वास्तव में हर teammate के लिए अलग sandboxed agent चाहते हैं जहाँ provider keys एक ही gateway में हों, तो OneCLI इसी तरह के सेटअप के लिए बनाया गया है

दूसरा, सामने एक reverse proxy लगाएँ और वहाँ TLS (transport layer security) termination करें। runtime को design के अनुसार plain HTTP serve करने के लिए बनाया गया है और यह उम्मीद करता है कि certificates को संभालने का काम कोई और करेगा।

server {
    listen 443 ssl;
    server_name agents.example.com;

    ssl_certificate     /etc/letsencrypt/live/agents.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/agents.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_read_timeout 3600s;
    }
}

उनमें से दो lines केवल सजावट नहीं हैं। proxy_buffering off महत्वपूर्ण है क्योंकि sessions server-sent events (SSE) के माध्यम से stream होते हैं, और buffering चालू होने पर, nginx response को तब तक रोक कर रखता है जब तक उसका buffer भर न जाए। इस कारण console पर कुछ भी दिखाई नहीं देता जबकि agent काम कर रहा होता है, और अंत में सारा output एक साथ dump हो जाता है। proxy_read_timeout 3600s महत्वपूर्ण है क्योंकि default समय 60 seconds है, इसलिए यदि कोई stream एक मिनट से अधिक समय तक शांत रहती है, तो proxy उसे बीच में ही बंद कर देता है, और यह विफलता runtime के crash होने जैसी लगती है।

Firewall पर, 22 और 443 ports खोलें। 3000 को बंद रहने दें, क्योंकि proxy उस तक loopback के माध्यम से पहुँचता है और box के बाहर की किसी भी चीज़ को वहाँ पहुँचने की आवश्यकता नहीं है।

Anthropic SDK को अपने सर्वर की ओर निर्देशित करें

Runtime एक CMA-आकार की /v1 सतह लागू करता है, इसलिए एक Anthropic SDK क्लाइंट एक फ़ील्ड बदलकर इससे संवाद करता है।

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.MANAGED_AGENTS_API_KEY ?? 'local-dev-key',
  baseURL: 'http://127.0.0.1:3000'
});

यह उन बीटा हेडर को भी स्वीकार करता है जिन्हें Claude Managed Agents क्लाइंट भेजते हैं, जैसे anthropic-beta: managed-agents-2026-04-01 और anthropic-beta: agent-memory-2026-07-22। एक स्थानीय runtime के विरुद्ध ये वैकल्पिक हैं। इनका अस्तित्व इसलिए है ताकि hosted deployment के लिए लिखा गया कोड यहाँ बिना किसी बदलाव के चल सके।

संगतता (compatibility) काफी हद तक है, लेकिन पूर्ण नहीं है। किसी सतह के अस्तित्व को मानने से पहले चेकआउट में docs/api-matrix.md पढ़ें, क्योंकि प्रोजेक्ट वहाँ अपनी कमियों का दस्तावेजीकरण करता है, जिसमें क्लाइंट-साइड कस्टम टूल्स भी शामिल हैं, जिन्हें अभी भी वर्तमान event-result प्रोटोकॉल के ऊपर नामित पंजीकरण (named registration) की आवश्यकता है।

Plain HTTP भी उतना ही अच्छा काम करता है, और यह साबित करने का सबसे तेज़ तरीका है कि runtime सक्रिय है:

curl -N -X POST http://127.0.0.1:3000/v1/sessions/SESSION_ID/messages \
  -H "Content-Type: application/json" \
  -d '{"content": "Hello", "stream": true}'

एक स्वस्थ प्रतिक्रिया घटनाओं (events) का एक ऐसा प्रवाह है जो लगातार आता रहता है। यदि कनेक्शन टूट जाता है, तो पूरी टर्न को फिर से चलाने के बजाय उस अंतिम घटना से फिर से शुरू करें जिसे आपने देखा था:

curl -N http://127.0.0.1:3000/v1/sessions/SESSION_ID/events/stream \
  -H "Last-Event-ID: EVENT_ID"

वह फिर से शुरू होने योग्य (resumable) स्ट्रीम ही कारण है कि लैपटॉप बंद होने पर भी सत्र (session) बना रहता है। घटनाएं सर्वर पर सुरक्षित रहती हैं, इसलिए क्लाइंट केवल एकमात्र प्रतिलिपि रखने के बजाय एक लॉग को फिर से चला रहा होता है।

क्रेडेंशियल्स, मेमोरी और ऑडिट ट्रेल्स डिस्क पर कहाँ रहते हैं

रनटाइम के स्वामित्व वाली हर चीज़ वर्कस्पेस में .managed-agents/ के अंतर्गत होती है।

.managed-agents/
├── config.yaml
├── data.db
├── logs/runtime.log
├── files/
├── skills/
├── snapshots/
└── sandbox/
  • data.db SQLite मेटाडेटा है: एजेंट्स, सेशंस, क्रेडेंशियल वॉल्ट एंट्रीज, मेमोरी स्टोर एंट्रीज और API कीज़।
  • files/ में अपलोड की गई फाइल बाइट्स होती हैं और skills/ में अपलोड किए गए स्किल पैकेज होते हैं।
  • snapshots/ में सेशन वर्कस्पेस स्नैपशॉट्स होते हैं, और sandbox/ में लोकल-मोड सेशंस की वर्किंग डायरेक्टरीज होती हैं।
  • logs/runtime.log वह पहली जगह है जहाँ तब देखना चाहिए जब कुछ भी बिना किसी संकेत के काम न कर रहा हो।

क्रेडेंशियल वॉल्ट्स सीक्रेट्स के समूह हैं, जिन्हें प्रत्येक को auth_type जैसे कि environment_variable के साथ जोड़ा जाता है, और सेशन बनाते समय vault_ids के माध्यम से सेशन से अटैच किया जाता है। मेमोरी स्टोर्स में नामित एंट्रीज होती हैं जिन्हें आप memory_store के रूप में एक सेशन में माउंट करते हैं, जिसकी अपनी एक्सेस सेटिंग और निर्देश होते हैं। दोनों data.db में रहते हैं, जो कि एक रॉ मॉडल कॉल और इसके बीच का वास्तविक अंतर है: रनटाइम सेशंस के बीच याद रखता है, और यह लिखता है कि क्या हुआ था।

चूंकि यह एक ही डायरेक्टरी है, इसलिए इसका बैकअप एक साथ लें।

sudo systemctl stop sandbase
sudo tar czf /root/sandbase-$(date +%F).tgz -C /opt/sandbase/workspace .managed-agents
sudo systemctl start sandbase

सबसे पहले सर्विस को रोकें। रनटाइम के लिखते समय SQLite डेटाबेस को कॉपी करने से ऐसी फाइल कैप्चर हो सकती है जो रिस्टोर करने पर नहीं खुलेगी, और आपको इसका पता उसी दिन चलेगा जिस दिन आपको इसकी आवश्यकता होगी। यदि आप एजेंट YAML को git में और स्टेट को कहीं और रखना चाहते हैं, तो डिप्लॉयमेंट डॉक start पर --data-dir के साथ स्टेट लोकेशन को पिन करने का समर्थन करता है।

रिस्टोर करना इसका उल्टा है: एक नए बॉक्स पर उसी टैग को चेक आउट करें, आर्काइव को वर्कस्पेस में अनपैक करें, और सर्विस शुरू करें। यदि आपने ${OPENAI_API_KEY} फॉर्म का उपयोग किया है तो आपका प्रोवाइडर की आर्काइव में नहीं होगा, इसलिए उसे कहीं सुरक्षित रखें जहाँ वह आपके पास उपलब्ध रहे।

इसे systemd के अंतर्गत चलाएं

Runtime के लिए अपना एक अलग user बनाएं ताकि local sandbox mode में कोई tool call आपके user के रूप में कार्य न कर सके।

sudo adduser --system --group --no-create-home --home /opt/sandbase sandbase
sudo chown -R sandbase:sandbase /opt/sandbase

इसे /etc/systemd/system/sandbase.service के रूप में save करें।

[Unit]
Description=SandBase Harness runtime
After=network-online.target

[Service]
User=sandbase
Group=sandbase
WorkingDirectory=/opt/sandbase/workspace
EnvironmentFile=/etc/sandbase/runtime.env
ExecStart=/usr/bin/node /opt/sandbase/sandbase-harness/dist/index.js start --host 127.0.0.1 --port 3000
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Project का अपना deployment उदाहरण PATH पर एक managed-agents binary को call करता है। Tagged-source install इसे create नहीं करता है, इसलिए ExecStart इसके बजाय built entry point के विरुद्ध node चलाता है।

sudo systemctl daemon-reload
sudo systemctl enable --now sandbase
sudo systemctl status sandbase
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/dashboard

एक सही परिणाम status से active (running) और curl से 200 है। यदि कुछ और परिणाम मिले, तो पहले journalctl -u sandbase -n 50 पढ़ें और फिर .managed-agents/logs/runtime.log देखें। enable --now वह महत्वपूर्ण हिस्सा है, क्योंकि हाथ से शुरू की गई process अगले reboot के बाद समाप्त हो जाती है।

What breaks, and the message you will see

npm run build is killed with no error from npm. On a 1 GB VPS the TypeScript compile is stopped by the kernel out-of-memory killer, which reports it to the kernel log rather than to npm. Confirm with journalctl -k | grep -i "out of memory", which prints a line naming the killed node process. Add swap, or build on a larger instance and copy dist/ across.

Error: listen EADDRINUSE: address already in use 127.0.0.1:3000. Another process already holds the port. sudo ss -lntp | grep 3000 names it. Either stop that process or start the runtime with --port 3001 and update the proxy.

The dashboard will not load from your laptop. That is the intended behaviour, because the runtime binds to loopback. Use the SSH tunnel above, or finish the reverse proxy. Do not repair it with --host 0.0.0.0, because authentication is off until a key exists.

Docker sandboxes fail with permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock. The sandbase user is not in the docker group. Fix it with sudo usermod -aG docker sandbase and restart the service, and understand what you granted: that group is root on the host, so it undoes part of the reason you gave the runtime its own user.

Kubernetes sandboxes fail with Error from server (Forbidden). The ServiceAccount is missing pod permissions or the exec subresource. Check it directly with kubectl auth can-i create pods/exec -n <namespace>, which answers yes or no.

Every request returns 401 after you add an API key. Authentication switches on when the first key exists, and it applies to the console as well as the API. Send Authorization: Bearer <key>, and if you lost the key, create another one, because secret_key is returned once and is not stored in a readable form.

An MCP server's tools never appear in a session. Check the mcp_server_name in the tools block against the name in mcp_servers, then check the runtime can reach the URL from the server itself with curl -i <url>. A URL-type MCP server is a network dependency, and a VPS resolves names and routes traffic differently from your laptop.

FAQ

क्या मैं OpenAI या Anthropic key के बिना SandBase Harness चला सकता हूँ?

हाँ, यदि आपके पास OpenAI-compatible endpoint है। Runtime, OpenAI, Anthropic और OpenAI-compatible providers को सपोर्ट करता है, इसलिए OpenAI API पर काम करने वाला कोई भी local server इसके साथ चल सकता है। .managed-agents/config.yaml में workspace provider सेट करें और api_key तथा endpoint को उस पर पॉइंट करें। Runtime में अपना कोई model शामिल नहीं है, इसलिए calls का उत्तर देने के लिए किसी न किसी सेवा की आवश्यकता होती है।

क्या runtime को public port पर expose करना सुरक्षित है?

डिफ़ॉल्ट इंस्टॉलेशन के साथ ऐसा नहीं है। यह 127.0.0.1:3000 पर bind होता है और बिना authentication के शुरू होता है, और इसका समाधान केवल bind address बदलना नहीं है। एक API key बनाएँ, या MANAGED_AGENTS_API_KEY सेट करें, ताकि bearer-token authentication चालू हो सके। इसके बाद TLS के लिए nginx या Caddy को सामने रखें, और firewall पर port 3000 को बंद रखें ताकि अंदर आने का एकमात्र रास्ता proxy के माध्यम से ही हो।

local, Docker और Kubernetes sandboxes में क्या अंतर है?

local टूल कोड को host पर runtime के child process के रूप में चलाता है, जिसमें runtime user की अनुमतियाँ होती हैं और कोई isolation नहीं होता। docker प्रत्येक session को उसका अपना container देता है, जिसका अपना filesystem, memory limit और CPU share होता है, और session समाप्त होने पर यह उसे हटा देता है। kubernetes session को pod के रूप में चलाता है और इसे kubectl exec के साथ संचालित करता है, जिसके लिए runtime image के अंदर kubectl और pods पर RBAC के साथ-साथ target namespace में exec subresource की आवश्यकता होती है।

मुझे वास्तव में किसका बैकअप लेने की आवश्यकता है?

workspace में स्थित .managed-agents/ directory का। इसमें config.yaml, agents, sessions, credential vault entries और memory entries के साथ data.db SQLite database, और साथ ही uploaded files, skill packages और session snapshots होते हैं। इसे कॉपी करने से पहले service को रोक दें ताकि archive बनते समय SQLite में कोई डेटा न लिखा जा रहा हो। ${OPENAI_API_KEY} के रूप में संदर्भित Provider API keys बैकअप के अंदर नहीं होती हैं, इसलिए उन्हें अलग से सुरक्षित रखें।

main के बजाय v0.3.2 tag को clone क्यों करें?

एक tag एक fixed tree होता है, इसलिए जिन config keys और CLI commands के बारे में आप पढ़ते हैं, वे वही होती हैं जो आपको वास्तव में मिलती हैं। main बदलता रहता है, और गाइड लिखे जाने तथा आपके उसे चलाने के बीच के समय में कोई config key rename हो सकती है। प्रोजेक्ट यह भी चेतावनी देता है कि npm पर unscoped managed-agents पैकेज यह प्रोजेक्ट नहीं है, इसलिए npx managed-agents कुछ और ही इंस्टॉल कर देगा। Release v0.3.1 मुख्य रूप से उस npm quick start को pinned tagged-source path से बदलने के लिए मौजूद है।