VPS starter contract (Python / Node.js / Go)

HUB documentation · docs/VPS_TEMPLATE_CONTRACT.md

← Documentation library · Download Markdown

Production dashboard / HUB API: https://bamboubot.duckdns.org
Set HUB_URL=https://bamboubot.duckdns.org. Local-development commands and loopback bind addresses below are development/operator reference, not the production API origin. Use the existing hosted HUB; you do not need to deploy a new one.

Introduction

All templates implement the same API contract, Linux deployment, no captcha integration. Existing hub endpoint details: CONTRACT.md, docs/BACKUP_CONTRACT.md.

Local files / safe first enrollment

Each agent has a locally chosen runtime directory, default ./runtime (owner-only directory). It writes: - config.json: {ai_api_key,number_of_workers,ai_preset_id,revision} (NO captcha key and no hub token). - proxies.txt: canonical URL lines; credentials use percent-encoded scheme://username:password@host:port; no credentials in API proxy URL field. Blank/comment lines ignored on import. - .sync.json: {initialized:true,revision:N} indicates first enrollment complete, private mode0600. - backup-config.json: latest safe agent backup configuration (enabled,interval_minutes,destination_ids,agent_configured,agent_last_seen,next_backup_at), atomically refreshed whenever backup config is polled; cloud credentials never written on VPS. This is a hub-authored runtime snapshot, not a source for importing schedules.

First startup MUST call GET /api/agent/config (now adds revision:integer,local_sync_initialized:boolean) then, if not locally initialized, POST /api/agent/local-sync with {expected_revision:integer,config?:{ai_api_key?:string,number_of_workers?:integer,ai_preset_id?:string},proxies_content?:string}. Optional config loaded from localconfig.json (same fields, ignore revision) and optional localproxies.txt; send even emptybodyfields with expectedrevision to finalize enrollment. Server atomically imports local data ONLY when hub configuration is still pristine: no administrator config write and no proxy create/import/delete since sitecreation AND local_sync_initializedfalse. Otherwise it returns current authoritative hub values untouched. Result is full agent config with revision and local_sync_initializedtrue. Once initialized, never reimport localfiles automatically (even on lost local checkpoint, backend guard prevents resurrecting deleted proxies). After first enrollment hub is authoritative; local manual edits are overwritten on next poll. Explicit admin proxy import is available for intentional changes. Race: stale expected_revision returns409; fetch latest then retry once WITHOUT local data, to finalize enrollment without overriding newer admin edits. Reject invalid localfilecontent atomically; log sanitized failure and do not overwrite local files on invalid import.

After successful sync, write config.json and proxies.txt atomically via private temp+fsync+rename, then .sync.json LAST. Readers should read config revision after reload; per-file atomic publication, not a cross-file filesystem transaction. Poll30s; immediately reload on start/restart. Clearing dashboard AI key writes emptystring; deleting proxy writes reduced/emptyfile. Dashboard site deletion revokes token, does NOT delete the codebase or private runtimefiles on VPS (requires explicitlocaloperatoraction). Auth tokens stay environment-only. Files contain secrets: mode0600, directory0700; .gitignore local runtime and cloudconfigs. No file paths or executablecommands accepted from hub.

Local synchronization API: - POST /api/agent/local-sync site token only => full agentconfig {number_of_workers,ai_preset_id,ai_api_key,captcha_api_key,proxies:[{id,url,username,password}],revision,local_sync_initialized}. Response NO extra imported field required. - Existing GET /api/agent/config adds revision+local_sync_initialized (nonbreaking). - Existing GET/PUT admin /sites/{id}/config adds revision; every administrator PUT config, proxy POST, DELETE, successful non-dryrun proxy import (if inserted>0) marks site admin_modifiedtrue and increments revision. DELETEproxy always revision++, repeated invaliddelete no mutation. First local enrollment sets local_sync_initializedtrue and revision++; next local-sync is idempotent read, not reimport. expected_revision requirednonnegativeinteger. Admin touchedsites ignore local input (but validate schema) and finalize latest hubconfig. Local AIkeyencrypted, proxy passwords encrypted via existingmechanism. Cap1000proxies and100workers. No outbound fetch during localimport.

Template capabilities

Environment HUB_URL verified HTTPS origin (localhostHTTP devallowed), HUB_AGENT_TOKEN mandatory. Paths chosen locally via env/CLI. Separate heartbeat15s, lifecyclepoll5s, configpoll30s; no blocking backups on lifecycle thread. Worker slots UUID IDs (persistent/random UUID or UUIDv5 supported) with actual CPU/memory if practical; tasks_completed realhookcounter, never fabricated. Harmless placeholder worker loop with TODO businesslogic hook, not an automated target-site interaction. WorkerCount config reconciles runningpool; desired_state recovery onlyinitial, explicit commands start/stop/restart whitelist; persistent completedcommanddedupfile before ack, retryackwithoutrepeating. Explain crashwindownotexactlyonce. Mark commandcompleted onlyafterlocalaction; no remote shell. Report sanitized workererrors POST/errors.

Backup config/status/requestpoll follows backendcontract. Localsource directory configured on VPS only. Periodic off default, interval>=15min, requeston-demand works withperiodicoff; arbitraryfileuploadhelper streams octetstream with filename/source/request_id, no extensionfilter; pack whole codebase tar.gz using localtar command or libraries, no symlinkdereference, temp outsidecodebase and private, exclude own runtime/state/temp if nested. Do not bufferarchiveRAM. Explain stabletree/snapshots and codebaseincludes.env. persistlastuploadtimestamp, boundedsize, cancellationcleanup. Backupthread/task independent, no arbitrarycommandfromdashboard. Failureackonly if not accepted; ambiguouslostresponse reconcile requestqueue, don't falsely claimfailed after hubaccepted. No cloudcredentials required onVPS.

Language ownership: - Python template under templates/python can reuse agent/ robust supervisor, backup and new localfilemodule; bootstrap adds repositoryroot tosys.path and instantiates hooks/exampleworker. Must be runnable python main.py, requirements included, usefulautomationextensionpoints. No duplicating robustarchivecode needlessly. - Node template templates/node runnable node main.mjs, Node22+, minimal/no deps. Real modules inclworker_threadsorchildprocess supervisor, filesystem/proxyformat helper, backuphelper, tests node --test. Localtar argvfixed withoutshell. Streamingfetch needs duplexhalf. HTTPtimeoutandredacterrors. - Go template templates/go runnable go run . or go build; stdlib preferred, go.mod, real workerpool loopscontext, configfiles/proxyparse, backupgoroutine streamingviafile/tar.gz orlocaltar, httptimeoutsTLS and redirectsdisabled, tests go test ./... . No arbitraryshellstrings.

Documentation must clearly mark integrationhooks vs businesslogic and limitations. Languageparity tests can use a temporary livehub with rclonelocalalias. Root agent must also sync files by default with --runtime-dir (default./runtime), preserving localfiles on firstenroll as above.