This guide is for the people who deploy, operate, secure, and extend AutoGPT: administrators, platform engineers, architects, and block developers. It covers the AutoGPT Platform (autogpt_platform/) in depth and the legacy classic/ tree briefly. End-user tasks (building agents, AutoPilot, the Marketplace, scheduling) are in the companion User Guide.
1. Executive Summary
| Aspect | Summary |
|---|---|
| What it is | A platform for building and running AI agents as visual graphs of blocks, plus a conversational builder (AutoPilot), a Marketplace, schedules, webhook triggers, credits/billing, and chat-bot bridges |
| Two products, one repo | autogpt_platform/ (current, Polyform Shield license) and classic/ (original 2023 autonomous agent + forge + benchmark, MIT, unsupported) |
| Backend | Python (>=3.10,<3.14), FastAPI, Prisma ORM on PostgreSQL + pgvector, RabbitMQ, a 3-node Redis cluster, FalkorDB (Graphiti memory), ClamAV, APScheduler-backed scheduler, Pyro-style internal RPC between services |
| Frontend | Next.js (React, TypeScript) with an embedded Better Auth service issuing ES256 JWTs verified by the backend via JWKS |
| Deployment shapes | (1) Multi-container Docker Compose from source; (2) experimental single-container appliance significantgravitas/autogpt; (3) the hosted cloud (BEHAVE_AS=cloud) |
| Scale of code | ~7,000 files; 90 Prisma models; 219 migrations; 115 entries under backend/blocks/ |
| State | PostgreSQL (everything durable), RabbitMQ (execution queues), Redis (event bus, locks, caches), FalkorDB (memory graph), workspace/media storage (local or GCS) |
| Operational burden | Moderate-to-high: ~10 backend service roles, 6 infrastructure services, secret management (Fernet ENCRYPTION_KEY), Prisma migrations on every upgrade, OAuth apps per integration |
Important
The three most consequential operator facts: (1) the backend refuses to start without
ENCRYPTION_KEY, and losing it makes every stored integration credential unreadable; (2) the appliance persists every generated secret in/data/config/runtime.envand has no in-place rotation; (3)BEHAVE_AS=local(the self-host default) bypasses subscription entitlement gating and is only appropriate for single-tenant installs.
2. Architecture
2.1 Component diagram (Compose deployment)
Browser
│ :3000
┌───────────▼────────────┐
│ frontend (Next.js) │ Better Auth (sessions, ES256 JWT,
│ /api/auth/jwks │ JWKS in platform."UserAuthJwks")
└──────┬───────────┬─────┘
REST :8006 │ │ WS :8001
┌──────────────▼──┐ ┌────▼─────────────┐
│ rest_server │ │ websocket_server │◄── Redis event bus
│ FastAPI (/api, │ │ (execution │ (execution_event,
│ /external-api, │ │ updates) │ notification_event)
│ /health) │ └──────────────────┘
└──┬───────┬──────┘
│ RPC │ publish
│ ▼
│ ┌─────────┐ consume ┌──────────────┐ ┌──────────────────┐
│ │RabbitMQ │──────────► │ executor │ │ copilot_executor │
│ │ :5672 │──────────► │ :8002 │ │ :8008 (AutoPilot)│
│ └─────────┘ └──────┬───────┘ └────────┬─────────┘
│ │ RPC │
┌─────▼──────────────┐ ┌──────────▼─────────┐ ┌───────▼───────┐
│ database_manager │◄──────┤ scheduler :8003 │ │ FalkorDB │
│ :8005 (DB RPC) │ │ notification :8007 │ │ :6380 Graphiti│
└─────┬──────────────┘ │ linking mgr :8009 │ └───────────────┘
│ └────────────────────┘
┌───────▼───────────┐ ┌──────────────────┐ ┌──────────────┐
│ PostgreSQL :5432 │ │ Redis cluster │ │ ClamAV :3310 │
│ pgvector pg15 │ │ :17000-17002 │ │ (uploads) │
│ schema "platform" │ └──────────────────┘ └──────────────┘
└───────────────────┘
2.2 Service inventory
All backend roles are the same image started with a different Poetry script.
| Compose service | Command | Port | Responsibility |
|---|---|---|---|
migrate |
Prisma migrate | — | Applies migrations; other services wait for service_completed_successfully |
rest_server |
rest |
8006 |
FastAPI REST (/api/*), External API (/external-api), /health, webhook ingress, chat-bot webhook adapters |
websocket_server |
ws |
8001 |
Pushes execution events to browsers (/, /health) |
executor |
executor |
8002 |
Graph execution manager: consumes RabbitMQ, runs nodes, charges credits, resolves credentials |
copilot_executor |
python -m backend.copilot.executor |
8008 |
AutoPilot turn execution |
database_manager |
db |
8005 |
DB access service reached over internal RPC |
scheduler_server |
scheduler |
8003 |
Cron schedules (SQLAlchemy job store, pool of 3), periodic cleanup jobs |
notification_server |
notification |
8007 |
Email (Postmark) and push (VAPID) notifications |
platform_linking_manager |
platform-linking-manager |
8009 |
Links chat-platform users to accounts; bot profile only |
frontend |
Next.js | 3000 |
UI and Better Auth |
db |
pgvector/pgvector:pg15 |
5432 |
PostgreSQL |
redis-0/1/2 + redis-init |
redis:7 cluster |
17000–17002 |
Event bus, locks, caches |
rabbitmq |
rabbitmq:4.1.4 |
5672 |
Execution queues |
falkordb |
falkordb/falkordb:latest |
6380 (protocol), 3001 (UI) |
Graphiti temporal knowledge graph |
clamav |
clamav/clamav-debian:latest |
3310 |
Virus scanning for uploads |
Additional roles defined in code (not separate Compose services by default): batch-executor (batch_executor_port 8011, polls LLM batch APIs), and the chat bridge (copilot_chat_bridge_port 8010).
poetry run app starts all roles in one process tree, in this order: DatabaseManager, Scheduler, BatchExecutor, NotificationManager, PlatformLinkingManager, WebsocketServer, AgentServer (REST), ExecutionManager, CoPilotChatBridge, CoPilotExecutor (the last runs in the foreground).
2.3 Repository layout
| Path | Contents |
|---|---|
autogpt_platform/backend/backend/api/ |
FastAPI app (rest_api.py), WebSocket app (ws_api.py), features/* routers, external/ (External API v1), middleware/ |
.../backend/blocks/ |
Auto-discovered block modules (one package per provider) |
.../backend/executor/ |
Execution manager, scheduler, billing, cost tracking, cluster lock, simulator, automod |
.../backend/data/ |
Data access and domain logic (graphs, executions, credits, event bus, llm_registry/catalog.py, ...) |
.../backend/integrations/ |
ProviderName, OAuth handlers (oauth/), webhook managers (webhooks/), credential store |
.../backend/copilot/ |
AutoPilot: executor, tools, Graphiti memory, chat bots (bot/), evals |
.../backend/sdk/ |
ProviderBuilder, block SDK re-exports |
.../backend/cli/ |
Admin CLI (cli), oauth_tool, OpenAPI export |
.../backend/util/settings.py |
The Config and Secrets settings models |
autogpt_platform/backend/schema.prisma + migrations/ |
90 models, 32 enums, 219 migrations |
autogpt_platform/frontend/ |
Next.js app, Better Auth (src/lib/auth), Playwright tests |
autogpt_platform/autogpt_libs/ |
Shared auth (JWKS verification, dependencies), utils |
autogpt_platform/single-container/ |
Appliance build (docker-bake.hcl), runtime_config.py, probe.py, supervisor listeners, nginx |
autogpt_platform/installer/ |
Appliance installer scripts |
autogpt_platform/graph_templates/ |
Built-in graph templates |
autogpt_platform/analytics/ |
Analytics SQL views |
classic/ |
forge/, original_autogpt/, direct_benchmark/ |
docs/ |
platform/, integrations/ (generated block docs), content/ (classic/forge) |
2.4 Execution flow
- A run is requested via REST (
POST /api/graphs/{graph_id}/execute/{graph_version}), the External API, a schedule, a webhook trigger, or AutoPilot. - The REST layer validates inputs and credentials, enforces the payment paywall where applicable, records an
AgentGraphExecution, and publishes to RabbitMQ. - The executor consumes the message (up to
num_graph_workers, default 10), resolves starting nodes, and queues downstream nodes as their required inputs validate. - Each node execution loads its block, injects credentials (never persisted into node I/O), charges credits (
execution_cost_*settings), and recordsAgentNodeExecution+AgentNodeExecutionInputOutput. - Progress is published on the Redis event bus (
execution_event); the WebSocket server forwards it to subscribed browsers. - A block failure yields on its
errorpin; errors inheriting fromValueError(BlockInputError,BlockExecutionError) are classified as user-fixable "expected failures".
Concurrency guards in Config:
| Setting | Default | Meaning |
|---|---|---|
num_graph_workers |
10 |
Executor worker concurrency |
max_concurrent_graph_executions_per_user |
25 |
Per-user running graph cap |
num_copilot_workers |
5 |
AutoPilot executor concurrency |
max_inflight_copilot_turns_per_user |
15 |
Queued + running AutoPilot turns per user |
max_running_copilot_turns_per_user |
5 |
Concurrently running AutoPilot turns per user |
cluster_lock_timeout |
300 s |
Distributed lock TTL |
requeue_by_republishing |
True |
Requeue strategy for RabbitMQ messages |
2.5 Data Layer
- ORM: Prisma (Python client), schema
postgres/schema.prisma-style layout atbackend/schema.prisma, default DB schemaplatform(DB_SCHEMA). - Database: PostgreSQL 15 with
pgvector(embeddings for hybrid search). - Key model groups (90 models):
| Group | Models |
|---|---|
| Auth (Better Auth) | AuthUser, AuthSession, AuthAccount, AuthVerification, AuthJwks |
| Users | User, UserOnboarding, UserBalance, UserWorkspace, UserWorkspaceFile, UserWorkspaceFolder, UserAttribution, UserBriefing |
| Graphs | AgentGraph, AgentNode, AgentNodeLink, AgentBlock, AgentPreset |
| Executions | AgentGraphExecution, AgentNodeExecution, AgentNodeExecutionInputOutput, AgentNodeExecutionKeyValueData, PendingHumanReview |
| Library | LibraryAgent, LibraryFolder |
| Store / Marketplace | Profile, StoreListing, StoreListingVersion, StoreListingReview, SkillListing, SkillListingVersion, SkillListingFile, UnifiedContentEmbedding, SearchTerms |
| Billing | CreditTransaction, CreditRefundRequest, PlatformCostLog, SubscriptionTrial, SubscriptionTrialClaim, OrganizationSubscription, OrgBalance, OrgCreditTransaction |
| Orgs & teams | Organization, OrganizationAlias, OrganizationProfile, OrgMember, OrgInvitation, Team, TeamMember, TeamInvite, OrganizationSeatAssignment, TransferRequest, AuditLog |
| Integrations | IntegrationCredential, IntegrationWebhook, APIKey |
| OAuth provider | OAuthApplication, OAuthAuthorizationCode, OAuthAccessToken, OAuthRefreshToken |
| AutoPilot / chat | ChatSession, ChatMessage, SharedChatFile, ChatLinkedShare, CoPilotUnderstanding, OnboardingBrainDump |
| Experts | Expert, ExpertWorkflow, ExpertRoutine, ExpertSkillListing, ExpertCredential, ExpertPauseEvent, ExpertPod |
| Chat bots | PlatformLink, PlatformUserLink, PlatformLinkToken, BotEvent, BotGuild, BotInstall |
| Notifications | NotificationEvent, UserNotificationBatch, PushSubscription, AlertCondition |
| Analytics / experiments | AnalyticsDetails, AnalyticsMetrics, ActivityEvent, ExperimentAssignment |
| Model registry | LlmModelMigration |
Warning
Don't hand-edit rows that carry encrypted payloads (
IntegrationCredential) or Better Auth key material (AuthJwks, exposed asplatform."UserAuthJwks"in the upgrade instructions). Use the CLI (rotate-encryption-key) or the documentedDELETE FROM platform."UserAuthJwks";reset only.
Search infrastructure. api/features/search/ provides a unified embedding table (UnifiedContentEmbedding) and unified_hybrid_search (semantic + BM25 lexical + recency + category scoring) across store agents, blocks, docs, library agents, workspace files, and chat sessions, exposed at /api/search/global. New content types add a ContentType enum value, a ContentHandler subclass registered in CONTENT_HANDLERS, and a background ensure_content_embedding call on write. Embeddings use store_embedding_model (default text-embedding-3-small).
2.6 Caching
| Layer | What is cached |
|---|---|
| Redis cluster | Event bus channels (execution_event, notification_event), cluster locks, chat-bot thread subscriptions (7-day TTL), Teams activity-id dedup claims, PostHog flag definitions (posthog_flag_definition_cache=redis, refresh 30 s, TTL 600 s) |
| HTTP | SecurityHeadersMiddleware sets cache-protection headers so sensitive API responses are not cached by browsers or proxies (only explicitly cacheable paths are allowed) |
Appliance /data/cache |
Regenerable backend and Next.js caches; excluded from backups |
3. System Requirements
| Component | Requirement |
|---|---|
| Container runtime | Docker Engine or Docker Desktop; Podman is not supported |
| Docker Compose | v2 (docker compose) for the from-source deployment |
| CPU architecture (appliance) | linux/amd64 or linux/arm64 Linux containers |
| Backend Python (dev) | >=3.10,<3.14, Poetry |
| Frontend (dev) | Node.js + pnpm |
| Classic | Python 3.12+, Poetry |
| PostgreSQL | 15 with pgvector (image pgvector/pgvector:pg15) |
| RabbitMQ | rabbitmq:4.1.4 |
| Redis | redis:7 in cluster mode (3 nodes) |
| Memory (appliance) | Measured 5–6 GiB at startup/steady health, plus headroom |
| Storage (appliance) | Image + growing /data + space for one full compressed backup; SSD-class recommended |
| Windows hosts | Docker Desktop with WSL 2 engine (Hyper-V causes an unhealthy db) |
Note
There is no measured minimum CPU count or supported concurrent-run ceiling for the appliance; performance depends on enabled services and workload.
Appliance fixed ceilings
| Resource | Limit |
|---|---|
| Prisma pool per backend role | ≤ 5 connections (DB_CONNECTION_LIMIT range 1–5) |
| Scheduler job-store pools | 2 × 3 SQLAlchemy connections |
| FalkorDB | ≤ 25 queued queries, 1-second query timeout |
| Valkey / FalkorDB memory | No appliance-level ceiling or eviction policy — monitor |
4. Configuration Mastery
4.1 How configuration is loaded
| Source | Precedence (low → high) |
|---|---|
.env.default (tracked, public, no secrets) |
1 |
.env (per install, gitignored) |
2 |
Compose environment: blocks (YAML anchors) |
3 |
| Shell environment | 4 |
The backend settings are two Pydantic settings models in backend/util/settings.py: Config (behavior) and Secrets (credentials). Field names map to environment variables of the same name (conventionally upper-case, e.g. num_graph_workers ↔ NUM_GRAPH_WORKERS). .env.default only lists variables that must be set; everything else falls back to the code defaults below.
A ./secrets directory is also supported: each file ./secrets/<name> holds one secret value, loaded at startup — useful for Docker secrets.
4.2 Required settings
| Variable | Default | Notes |
|---|---|---|
DB_USER / DB_PASS / DB_NAME / DB_HOST / DB_PORT |
postgres / placeholder / postgres / localhost / 5432 |
Change DB_PASS from the published placeholder |
DB_SCHEMA |
platform |
|
DB_CONNECTION_LIMIT |
12 (.env.default); appliance 1–5, default 5 |
Per-role Prisma pool |
DB_CONNECT_TIMEOUT |
60 |
Seconds |
DB_POOL_TIMEOUT |
300 |
Seconds |
DATABASE_URL / DIRECT_URL |
built from the DB_* vars |
Includes ?schema=${DB_SCHEMA}&connect_timeout=... |
PRISMA_SCHEMA |
postgres/schema.prisma |
|
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD |
localhost / 17000 (.env.default; code default 6379) / empty |
|
RABBITMQ_DEFAULT_USER / RABBITMQ_DEFAULT_PASS |
dev values in .env.default |
Change for any shared deployment; guest is refused by the appliance |
JWT_JWKS_URL |
http://localhost:3000/api/auth/jwks |
Must be HTTPS across untrusted networks |
JWT_JWKS_ALGORITHMS |
ES256,RS256,EdDSA |
Asymmetric only |
JWKS_ALLOW_INSECURE_TRANSPORT |
false |
Allows cleartext JWKS to a non-local host (logs a warning) |
ENCRYPTION_KEY |
blank → generated | Fernet key; backend refuses to start without it |
UNSUBSCRIBE_SECRET_KEY |
blank → generated | Signs email unsubscribe links |
BETTER_AUTH_SECRET (frontend) |
blank → generated | Better Auth signing secret |
Caution
VAPID_PRIVATE_KEY/VAPID_PUBLIC_KEYship as a dev-only keypair in.env.default. Regenerate before any non-local deployment:poetry run python -c " from py_vapid import Vapid; import base64 from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat v = Vapid(); v.generate_keys() raw_priv = v.private_key.private_numbers().private_value.to_bytes(32, 'big') print('VAPID_PRIVATE_KEY=' + base64.urlsafe_b64encode(raw_priv).rstrip(b'=').decode()) raw_pub = v.public_key.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint) print('VAPID_PUBLIC_KEY=' + base64.urlsafe_b64encode(raw_pub).rstrip(b'=').decode()) "Also set
VAPID_CLAIM_EMAILto a real mailbox (defaultmailto:[email removed]in.env.default).
4.3 Config reference (behavior)
Service ports and hosts
| Setting | Default |
|---|---|
agent_api_host / agent_api_port |
0.0.0.0 / 8006 |
websocket_server_host / websocket_server_port |
0.0.0.0 / 8001 |
execution_manager_port |
8002 |
execution_scheduler_port |
8003 |
database_api_port |
8005 |
notification_service_port |
8007 |
copilot_executor_port |
8008 |
platform_linking_service_port |
8009 |
copilot_chat_bridge_port |
8010 |
batch_executor_port |
8011 |
pyro_host |
localhost |
rabbitmq_host / rabbitmq_port / rabbitmq_vhost |
localhost / 5672 / / |
redis_host / redis_port |
localhost / 6379 |
clamav_service_host / clamav_service_port |
localhost / 3310 |
ollama_host |
localhost:11434 |
Execution and concurrency
| Setting | Default |
|---|---|
num_graph_workers |
10 |
num_copilot_workers |
5 |
fastapi_thread_pool_size |
60 |
max_concurrent_graph_executions_per_user |
25 |
max_inflight_copilot_turns_per_user |
15 |
max_running_copilot_turns_per_user |
5 |
requeue_by_republishing |
True |
cluster_lock_timeout |
300 |
rpc_client_call_timeout |
300 |
pyro_client_comm_timeout / pyro_client_comm_retry / pyro_client_max_wait |
15 / 100 / 30.0 |
llm_request_timeout_seconds |
600 |
max_message_size_limit |
16 MiB |
execution_late_notification_threshold_secs |
300 |
execution_late_notification_checkrange_secs |
3600 |
Codex / ChatGPT subscription processes
| Setting | Default |
|---|---|
codex_max_active_processes |
4 |
codex_capacity_timeout_seconds |
10 |
codex_startup_timeout_seconds |
30 |
codex_control_timeout_seconds |
60 |
codex_invocation_timeout_seconds |
180 |
codex_copilot_turn_timeout_seconds |
21600 |
codex_copilot_tool_timeout_seconds |
900 |
codex_login_timeout_seconds |
900 |
codex_auth_checkpoint_interval_seconds |
0.25 |
codex_temp_root |
"" |
Credits and billing
| Setting | Default |
|---|---|
enable_auth |
True |
enable_credit |
False |
enable_subscription_credit_grant |
False |
refund_credit_tolerance_threshold |
500 |
low_balance_threshold |
500 |
execution_cost_count_threshold |
100 |
execution_cost_per_threshold |
1 |
execution_counter_expiration_time |
86400 |
expert_weekly_credit_budget_default |
500 |
expert_spend_approval_threshold_default |
250 |
expert_spend_approval_window |
week |
refund_notification_email |
[email removed] |
stripe_tier_reconcile_interval_hours |
6 |
Files, scanning, moderation
| Setting | Default |
|---|---|
upload_file_size_limit_mb |
256 |
max_file_size_mb |
100 |
clamav_service_enabled |
True |
clamav_service_timeout |
60 |
clamav_max_concurrency |
10 |
clamav_mark_failed_scans_as_clean |
False |
automod_enabled |
False |
automod_api_url |
"" |
automod_timeout / automod_retry_attempts / automod_retry_delay |
30 / 3 / 1.0 |
automod_fail_open |
False |
media_gcs_bucket_name |
"" (local store-media/) |
workspace_storage_dir |
"" |
URLs, CORS, environment
| Setting | Default |
|---|---|
app_env |
local |
behave_as |
local |
platform_base_url |
"" (.env.default: http://localhost:8006) |
frontend_base_url |
"" (.env.default: http://localhost:3000) |
trusted_frontend_origins |
[] |
backend_cors_allow_origins |
["http://localhost:3000"] |
external_oauth_callback_origins |
["http://localhost:3000"] |
platform_link_base_url |
https://platform.agpt.co/link (.env.default: http://localhost:3000/link) |
Feature flags and toggles
| Setting | Default |
|---|---|
feature_flag_backend |
launchdarkly |
posthog_flag_definition_cache |
redis |
enable_example_blocks |
False |
enable_agent_input_subtype_blocks |
True |
use_agent_image_generation_v2 |
True |
marketplace_require_canonical_category |
False |
scheduler_startup_embedding_backfill |
True |
autopilot_bot_teams_allow_unverified |
False |
Force individual flags locally with FORCE_FLAG_<NAME>=true (or FORCE_ALL_FLAGS=true when APP_ENV=local); frontend equivalents use NEXT_PUBLIC_FORCE_FLAG_<NAME>.
Periodic cleanup jobs
| Setting | Default (hours) |
|---|---|
cloud_storage_cleanup_interval_hours |
6 |
oauth_token_cleanup_interval_hours |
6 |
push_subscription_cleanup_interval_hours |
24 |
platform_link_token_cleanup_interval_hours |
6 |
block_error_rate_check_interval_secs |
86400 (seconds) |
execution_accuracy_check_interval_hours |
24 |
Alerts and email senders
| Setting | Default |
|---|---|
block_error_rate_threshold |
0.5 |
block_error_include_top_blocks |
3 |
platform_alert_discord_channel |
local-alerts |
product_alert_discord_channel |
product-alerts |
postmark_sender_email |
[email removed] |
billing_sender_email |
AutoGPT <[email removed]> |
product_sender_email |
AutoGPT <[email removed]> |
ops_sender_email |
AutoGPT Platform <[email removed]> |
postmark_transactional_stream |
outbound |
4.4 Secrets reference (credentials)
All default to empty. Only set what you use.
| Category | Variables |
|---|---|
| Core | ENCRYPTION_KEY, UNSUBSCRIBE_SECRET_KEY, RABBITMQ_DEFAULT_USER, RABBITMQ_DEFAULT_PASS, VAPID_PRIVATE_KEY, VAPID_PUBLIC_KEY, VAPID_CLAIM_EMAIL |
| LLM providers | OPENAI_API_KEY, OPENAI_INTERNAL_API_KEY, ANTHROPIC_API_KEY, GROQ_API_KEY, OPEN_ROUTER_API_KEY, LLAMA_API_KEY, AIML_API_KEY, V0_API_KEY, NVIDIA_API_KEY |
| OAuth apps | GITHUB_*, GOOGLE_*, NOTION_*, TWITTER_*, DISCORD_*, REDDIT_*, LINEAR_*, TODOIST_* (_CLIENT_ID + _CLIENT_SECRET) |
POSTMARK_SERVER_API_TOKEN, POSTMARK_WEBHOOK_TOKEN, SMTP_SERVER, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, MAILERLITE_API_TOKEN |
|
| Billing | STRIPE_API_KEY, STRIPE_WEBHOOK_SECRET |
| Chat bots | AUTOPILOT_BOT_DISCORD_TOKEN, AUTOPILOT_BOT_DISCORD_CLIENT_ID, AUTOPILOT_BOT_DISCORD_PERMISSIONS, AUTOPILOT_BOT_SLACK_TOKEN, AUTOPILOT_BOT_SLACK_SIGNING_SECRET, AUTOPILOT_BOT_SLACK_CLIENT_ID, AUTOPILOT_BOT_SLACK_CLIENT_SECRET, AUTOPILOT_BOT_TELEGRAM_TOKEN, AUTOPILOT_BOT_TELEGRAM_WEBHOOK_SECRET, AUTOPILOT_BOT_TELEGRAM_USERNAME, MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, MICROSOFT_TENANT_ID, DISCORD_BOT_TOKEN |
| Block providers | REPLICATE_API_KEY, FAL_API_KEY, IDEOGRAM_API_KEY, DID_API_KEY, ELEVENLABS_API_KEY, UNREAL_SPEECH_API_KEY, E2B_API_KEY, EXA_API_KEY, JINA_API_KEY, MEM0_API_KEY, OPENWEATHERMAP_API_KEY, GOOGLE_MAPS_API_KEY, SCREENSHOTONE_API_KEY, MEDIUM_API_KEY, MEDIUM_AUTHOR_ID, APOLLO_API_KEY, SMARTLEAD_API_KEY, ZEROBOUNCE_API_KEY, ENRICHLAYER_API_KEY, AGENTMAIL_API_KEY, AYRSHARE_API_KEY, AYRSHARE_JWT_KEY, TALLY_API_KEY, WEBSHARE_PROXY_USERNAME, WEBSHARE_PROXY_PASSWORD |
| Observability & flags | SENTRY_DSN, LAUNCH_DARKLY_SDK_KEY, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_HOST (https://cloud.langfuse.com), LANGFUSE_TRACING_ENVIRONMENT (local), POSTHOG_API_KEY, POSTHOG_HOST (https://eu.i.posthog.com), POSTHOG_PERSONAL_API_KEY |
| Moderation | AUTOMOD_API_KEY |
| Copilot feature requests | COPILOT_LINEAR_API_KEY, LINEAR_FEATURE_REQUEST_PROJECT_ID, LINEAR_FEATURE_REQUEST_TEAM_ID |
4.5 AutoPilot and memory settings
| Variable | Default | Purpose |
|---|---|---|
CHAT_USE_LOCAL |
false |
Route AutoPilot through an OpenAI-compatible endpoint |
CHAT_USE_OPENROUTER |
appliance profile setting | true → OpenRouter; false with ANTHROPIC_API_KEY → direct Anthropic |
CHAT_BASE_URL |
empty | e.g. http://host.docker.internal:11434/v1 |
CHAT_API_KEY |
empty | Must be non-empty for local servers |
CHAT_FAST_STANDARD_MODEL (and other CHAT_*_MODEL) |
— | Bare model names for local backends |
CHAT_DAILY_COST_LIMIT_MICRODOLLARS / CHAT_WEEKLY_COST_LIMIT_MICRODOLLARS |
-1 in the appliance |
Spend caps; HTTP 429 when exceeded |
GRAPHITI_FALKORDB_HOST / _PORT / _PASSWORD |
localhost / 6380 / local-dev-password |
FalkorDB connection |
GRAPHITI_LLM_MODEL |
gpt-4.1-mini |
Extraction LLM |
GRAPHITI_EMBEDDER_MODEL |
text-embedding-3-small |
Embeddings |
GRAPHITI_RERANKER_MODEL |
— | Reranker |
GRAPHITI_SEMAPHORE_LIMIT |
5 |
Graphiti concurrency |
Key fallbacks: Graphiti's LLM key falls back to CHAT_API_KEY, then OPEN_ROUTER_API_KEY, then (local) the chat config; its embedder key falls back to CHAT_OPENAI_API_KEY, then OPENAI_API_KEY, then (local) the chat config. Under CHAT_USE_LOCAL=true cloud-slug Graphiti defaults are rewritten to local-friendly slugs unless you set custom values.
Note
On the hosted cloud (
BEHAVE_AS=cloud),CHAT_*_MODELis the bottom layer of AutoPilot model resolution — the catalog routing cells inbackend/data/llm_registry/catalog.pyand the per-user LaunchDarklycopilot-model-routingflag take precedence. On self-hosted installs the catalog cells are skipped and the env vars are authoritative.
4.6 Frontend settings
| Variable | Default |
|---|---|
BETTER_AUTH_SECRET |
blank → generated |
BETTER_AUTH_URL |
http://localhost:3000 |
DATABASE_URL |
postgresql://postgres:...@localhost:5432/postgres |
AUTH_DB_SCHEMA |
platform |
AUTH_REQUIRE_EMAIL_VERIFICATION |
false |
AUTH_ALLOW_NEW_ACCOUNTS / AUTH_SIGNUP_ALLOWLIST |
commented (open signup) |
AUTH_GOOGLE_*, AUTH_GITHUB_*, AUTH_DISCORD_* |
commented (social sign-in) |
SUPABASE_JWT_SECRET / SUPABASE_BRIDGE_MAX_TOKEN_AGE_DAYS |
commented / 30 (legacy session bridge) |
NEXT_PUBLIC_AGPT_SERVER_URL |
http://localhost:8006/api |
NEXT_PUBLIC_AGPT_WS_SERVER_URL |
ws://localhost:8001/ws |
NEXT_PUBLIC_FRONTEND_BASE_URL |
http://localhost:3000 |
NEXT_PUBLIC_APP_ENV / NEXT_PUBLIC_BEHAVE_AS |
local / LOCAL |
NEXT_PUBLIC_LAUNCHDARKLY_ENABLED |
false |
NEXT_PUBLIC_TURNSTILE |
disabled |
NEXT_PUBLIC_REACT_QUERY_DEVTOOL / NEXT_PUBLIC_TOKEN_DEVTOOL |
true |
NEXT_PUBLIC_POSTHOG_KEY / NEXT_PUBLIC_POSTHOG_HOST |
empty / https://eu.i.posthog.com |
NEXT_PUBLIC_GOOGLE_CLIENT_ID, NEXT_PUBLIC_GOOGLE_API_KEY, NEXT_PUBLIC_GOOGLE_APP_ID |
empty (Google Picker) |
NEXT_PUBLIC_VAPID_PUBLIC_KEY |
dev key (replace with yours) |
OPENAI_API_KEY |
empty (server-side transcription) |
Warning
NEXT_PUBLIC_*values are compiled into the browser bundle. Never put a secret in aNEXT_PUBLIC_variable.
4.7 Single-container appliance settings
| Variable | Purpose |
|---|---|
AUTOGPT_PUBLIC_URL |
Exact browser origin (scheme + host + non-default port, no path) |
AUTH_SIGNUP_ALLOWLIST, AUTH_ALLOW_NEW_ACCOUNTS, AUTH_REQUIRE_EMAIL_VERIFICATION |
Account policy |
AUTOGPT_ENABLE_LEGACY_AUTH |
Keep false except for an intentional legacy symmetric-JWT migration |
AUTOGPT_ENABLE_BOT_SERVICES |
true starts bot services and the linking manager |
BEHAVE_AS |
local (default) or cloud |
DB_CONNECTION_LIMIT / DB_CONNECT_TIMEOUT / DB_POOL_TIMEOUT |
1–5 (5) / 1–600 (60) / 1–3600 (300) |
POSTMARK_* |
Password reset and email-change messages |
Provider keys, CHAT_*, GRAPHITI_* |
As in the backend |
runtime_config.py validates the environment at boot and raises precise errors (see Troubleshooting). Generated secrets are written once to /data/config/runtime.env (root:root, 0600); supplying a different value later fails instead of silently rotating.
4.8 Migrations
| Task | Command |
|---|---|
| Apply (Compose) | docker compose run --rm migrate |
| Apply (local dev) | make migrate (prisma migrate deploy + prisma generate + gen-prisma-stub) |
| Create during development | poetry run prisma migrate dev |
| Reset local DB | make reset-db (deletes data/db/data) |
| Appliance | Applied automatically on boot before readiness is published |
Caution
Never stop the appliance during a boot-time migration, and never run an older image against a volume migrated by a newer one. Rollback = old image + its matching pre-upgrade backup restored into a new volume.
Notable migrations: 20260716120000_copy_supabase_users_to_better_auth copies Supabase auth.users into Better Auth tables during the Supabase → Better Auth upgrade.
Model retirement (catalog-as-code): set is_enabled: False in backend/data/llm_registry/catalog.py, then migrate existing graph nodes:
python -m backend.data.llm_registry.retire <slug> --replacement <slug> --yes
It is a dry run by default and revertable.
5. Deployment
5.1 Docker Compose (multi-container, from source)
git clone https://github.com/Significant-Gravitas/AutoGPT.git
cd AutoGPT/autogpt_platform
make init-env
docker compose up -d --build
✔ Container autogpt_platform-migrate-1 Exited
✔ Container autogpt_platform-rest_server-1 Started
✔ Container autogpt_platform-frontend-1 Started
Compose profiles:
| Profile / target | Use |
|---|---|
| default | Full stack |
deps service (make start-core) |
Postgres, Redis, RabbitMQ only — for running backend on the host |
--profile local up deps_backend |
Backend dependencies for running the frontend on the host |
--profile bot |
Adds platform_linking_manager for chat bots |
Deployment checklist:
- [ ]
make init-envrun;ENCRYPTION_KEY,UNSUBSCRIBE_SECRET_KEY,BETTER_AUTH_SECRETpopulated - [ ]
DB_PASS,RABBITMQ_DEFAULT_*, VAPID keys replaced from published defaults - [ ]
FRONTEND_BASE_URL,PLATFORM_BASE_URL,BACKEND_CORS_ALLOW_ORIGINSmatch real origins - [ ]
JWT_JWKS_URLis HTTPS if backend and frontend are not on one host - [ ] OAuth apps registered with callback
<frontend>/auth/integrations/oauth_callback - [ ] Only
3000(and, if needed,8006/8001) exposed through a TLS proxy; infrastructure ports not public - [ ] Backups scheduled for Postgres (and FalkorDB if memory matters)
5.2 Docker: single-container appliance
docker run --detach --name autogpt \
--restart unless-stopped \
--shm-size 2g \
--ulimit nofile=65536:65536 \
--log-driver json-file \
--log-opt max-size=50m \
--log-opt max-file=5 \
--env-file autogpt.env \
--publish 127.0.0.1:3000:3000 \
--volume autogpt-data:/data \
"${IMAGE}"
Internals:
- Supervisor runs process groups; names are group-qualified (
runtime:rest,state:postgres).supervisorctl statuslists them. - Shutdown is tuned to fit Docker's stock 10-second timeout: runtime processes are signalled first; PostgreSQL, RabbitMQ, Valkey, and FalkorDB get at most five seconds each; the event listener stops last (measured ~8.4 s). Do not shorten Docker's timeout.
- A watchdog allows 600 seconds for initial full health, then stops the container so
--restart unless-stoppedretries. - A fatal-event listener (
fatal_listener.py) and probes (probe.py: HTTP, AMQP, Redis/cluster) backautogpt-healthcheck. - nginx and Next.js run under separate Unix identities; the frontend reaches PostgreSQL via a passwordless local peer role restricted to Better Auth tables/columns.
/data layout
| Path | Contents |
|---|---|
/data/config |
runtime.env (generated secrets), backend.json |
/data/postgres |
Auth and platform data |
/data/rabbitmq |
Queue state (mnesia) |
/data/valkey |
Three Valkey nodes (17000, 17001, 17002) |
/data/falkordb |
Graphiti memory |
/data/workspaces |
User workspaces |
/data/store-media |
Marketplace media when GCS isn't configured |
/data/home, /data/frontend-home |
Application homes |
/data/cache |
Regenerable caches (excluded from backups) |
Warning
Never mount one
/datavolume into two running containers, and never selectively mix service directories from different backups.
Optional processes: FalkorDB is mandatory. Chat-bot services default off; set AUTOGPT_ENABLE_BOT_SERVICES=true after configuring an adapter (Discord: AUTOPILOT_BOT_DISCORD_TOKEN; Telegram: token + webhook secret + a public HTTPS webhook).
Local models: on Docker Engine add --add-host host.docker.internal:host-gateway (Docker Desktop provides the hostname already).
5.3 Reverse Proxy / Load Balancing
Appliance. Keep the container bound to loopback and terminate TLS in a reverse proxy outside the container, forwarding to 127.0.0.1:3000; the appliance routes internally. Set AUTOGPT_PUBLIC_URL to the HTTPS origin:
AUTOGPT_PUBLIC_URL=https://agents.example.com
Example (nginx on the host):
server {
listen 443 ssl;
server_name agents.example.com;
ssl_certificate /etc/ssl/agents.crt;
ssl_certificate_key /etc/ssl/agents.key;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
Important
The bundled nginx records your proxy as the client. Your proxy must keep its own client-attribution logs and enforce per-client IP rate limits and access rules.
Caution
On Linux, Docker-managed port forwarding can bypass firewall rules expressed only through UFW. The
127.0.0.1:in--publishis the exposure control; publishing on a non-loopback address can expose the app regardless of INPUT-chain rules.
Compose. Route https://<host>/ → frontend :3000, and expose the backend API (:8006) and WebSocket (:8001) either on their own hostnames or paths, then set:
| Setting | Value |
|---|---|
NEXT_PUBLIC_AGPT_SERVER_URL |
https://api.example.com/api |
NEXT_PUBLIC_AGPT_WS_SERVER_URL |
wss://ws.example.com/ws |
FRONTEND_BASE_URL / NEXT_PUBLIC_FRONTEND_BASE_URL / BETTER_AUTH_URL |
https://app.example.com |
PLATFORM_BASE_URL |
https://api.example.com |
BACKEND_CORS_ALLOW_ORIGINS |
["https://app.example.com"] |
JWT_JWKS_URL |
https://app.example.com/api/auth/jwks |
Note
backend/api/utils/cors.pyrejects localhost origins in production (Production environment cannot allow localhost origins), including via regex patterns.
Horizontal scaling: webhook-style chat adapters ride the N-replica REST deployment (no dedicated pod); socket adapters (Discord Gateway, Slack Socket Mode) run in a separate copilot-bot process. Executors scale by adding executor replicas consuming the same RabbitMQ queues; cluster locks live in Redis.
6. Security
6.1 Authentication
| Layer | Mechanism |
|---|---|
| End-user sign-in | Better Auth embedded in the Next.js frontend (email/password; optional social providers via AUTH_*_CLIENT_ID/SECRET) |
| Backend request auth | Asymmetric JWTs (ES256 by default) verified against JWT_JWKS_URL by autogpt_libs.auth |
| Legacy bridge | Old Supabase JWT cookies are exchanged for a Better Auth session while SUPABASE_JWT_SECRET is set |
| API keys | X-API-Key header, stored as APIKey rows with permissions (e.g. EXECUTE_GRAPH); validated by api/utils/api_key_auth.py |
| OAuth provider | AutoGPT is itself an OAuth 2.0 authorization server (/api/oauth/token, /introspect, /revoke) with mandatory PKCE S256; tokens agpt_xt_... (1 h), refresh agpt_rt_... (30 d), codes (10 min) |
| Admin CLI for OAuth apps | poetry run oauth-tool generate-app ... |
Caution
The backend trusts whatever keys
JWT_JWKS_URLreturns. Over any untrusted network use HTTPS; a cleartext fetch lets an attacker substitute keys and forge tokens for any user. The backend refuses to boot with a cleartext non-local JWKS URL unlessJWKS_ALLOW_INSECURE_TRANSPORT=true.
Account policy (appliance): allowlist by exact email or @domain; passwords ≥ 12 characters; AUTH_ALLOW_NEW_ACCOUNTS=false after bootstrap. Allowlisting compares the email asserted at signup — without email verification it is not proof of mailbox ownership.
6.2 Authorization & Access Control
| Control | Detail |
|---|---|
| Route guards | Security(requires_user) / admin dependencies on FastAPI routers (e.g. presets router) |
| Admin role | Granted by autogpt-admin promote (appliance); admin routers under /api/admin |
| API key permissions | Per-route require_permission(APIKeyPermission.X) on the External API |
| OAuth scopes | IDENTITY, EXECUTE_GRAPH, READ_GRAPH, WRITE_GRAPH, EXECUTE_BLOCK, READ_BLOCK, READ_STORE, WRITE_LIBRARY, USE_TOOLS, MANAGE_INTEGRATIONS, READ_INTEGRATIONS, DELETE_INTEGRATIONS |
| Org scoping | Org-scoped API keys attribute executions to their org; team-restricted keys pin to that team |
| Entitlements | BEHAVE_AS=cloud enforces subscription entitlements; local exempts every defined entitlement |
| Paywall | enforce_payment_paywall() on execute routes (returns 503 on tier-lookup failure rather than failing open) |
| Marketplace | Submissions require human review; listings are read-only in libraries until duplicated |
| Experts | Per-expert credential allowlists (ExpertCredential) and spend approval thresholds |
Warning
BEHAVE_AS=localalso enables blocks disabled in hosted mode, self-host model routing, and different diagnostics/telemetry. Any multi-tenant deployment must useBEHAVE_AS=cloud— and even then the appliance frontend is compiled in local mode, so the appliance is not a turnkey multi-tenant distribution.
6.3 TLS / Certificates
- AutoGPT does not terminate TLS itself; terminate at a reverse proxy.
- For LAN splits, use locally trusted certificates (e.g. mkcert) and point
JWT_JWKS_URLat thehttps://URL. - Production OAuth redirect URIs must be HTTPS.
- Telegram and Teams webhooks require public HTTPS endpoints.
6.4 Secrets handling
| Secret | Protection |
|---|---|
| Integration credentials | Encrypted at rest with Fernet ENCRYPTION_KEY; injected into blocks at run time |
.env.default files |
Must stay secret-free; enforced by .gitleaks.toml, detect-secrets, the check-env-defaults-blank pre-commit hook, and a unit test over BLANK_IN_ENV_DEFAULT |
| Appliance runtime secrets | Generated on first boot into /data/config/runtime.env (0600, root) |
| Frontend process | Receives only an allowlisted env: BETTER_AUTH_SECRET, AUTH_* client secrets, optional OPENAI_API_KEY, TRANSCRIPTION_API_KEY, legacy SUPABASE_JWT_SECRET — never the Postgres superuser, RabbitMQ/Valkey/FalkorDB passwords, or encryption keys |
| Templates / exports | Store credential references only |
Suspected exposure of appliance secrets: there is no in-place rotation. Isolate the installation, revoke external provider and OAuth credentials, build a new installation on a new volume, move only non-secret agent definitions via export/import, and reconnect credentials. Restoring an older backup does not rotate anything.
6.5 Input validation and network exposure
| Risk | Mitigation in source |
|---|---|
| SSRF from blocks | backend.util.request.Requests validates URLs, resolves DNS, blocks private ranges (BLOCKED_IP_NETWORKS), disables redirects by default, supports trusted_origins |
| Malicious uploads | ClamAV scanning (clamav_* settings; failed scans are not marked clean by default). The appliance has no antivirus — treat uploads as trusted input there |
| Content moderation | Optional automod_* integration (fail-closed by default) |
| Browser caching of sensitive data | SecurityHeadersMiddleware |
| CORS | Production rejects localhost origins |
| Webhook forgery | Providers with signatures override verify_signature using hmac.compare_digest (GitHub X-Hub-Signature-256, Airtable X-Airtable-Content-MAC, Slant3D HMAC-SHA256 with ms timestamp, Slack signing secret); unsigned providers rely on the unguessable webhook UUID |
| Teams bot | Inbound Bot Framework JWT validated; serviceUrl claim bound to the token and outbound hosts allowlisted |
| Internal RPC | Appliance binds AppService RPC to container loopback; Valkey requires auth |
| Shell tool | Local bash_exec fallback relies on Bubblewrap user/network namespaces — do not make the appliance privileged to work around a host that disables them |
| Postgres config tampering | Restore validation rejects non-loopback listen_addresses, include files, preload libraries, WAL archiving, and weakened pg_hba.conf |
6.6 Security hardening checklist
- [ ] Loopback-only publish + external TLS proxy
- [ ] Signup allowlist during bootstrap, then
AUTH_ALLOW_NEW_ACCOUNTS=false - [ ] No published defaults in use (
DB_PASS, RabbitMQ creds, VAPID keypair, pre-v0.7.4ENCRYPTION_KEY) - [ ] HTTPS
JWT_JWKS_URLfor any split deployment - [ ]
BEHAVE_AS=cloudfor anything multi-tenant - [ ] ClamAV enabled (Compose) or uploads restricted (appliance)
- [ ] Unauthenticated local model servers not exposed to the internet
- [ ] Backups encrypted (they contain plaintext secrets and user content)
- [ ] Webhook URLs for unsigned providers treated as secrets
7. Operations
7.1 Start, stop, restart
| Task | Compose | Appliance |
|---|---|---|
| Start | docker compose up -d |
docker run ... (Quick start) or docker start autogpt |
| Stop | docker compose down |
docker stop autogpt |
| Restart one role | docker compose restart rest_server |
docker exec autogpt supervisorctl restart runtime:rest |
| Rebuild after upgrade | git pull && docker compose up -d --build |
Replace container with new image (see Upgrade) |
| Status | docker compose ps |
docker inspect --format '{{.State.Health.Status}}' autogpt |
Note
Agent runs executing when services stop are abandoned: queue messages can be dropped and rows can stay
RUNNING. They do not resume.
7.2 Upgrades
Compose:
git pullthe release.- Diff each
.envagainst its.env.defaultand copy new keys (make init-envwon't merge them). docker compose build migrate rest_server && docker compose run --rm migrate.docker compose up -d --build.
Appliance:
- Record the running image reference and ID:
docker inspect --format '{{.Config.Image}} {{.Image}}' autogpt. - Pull/build the new image while the old one runs.
export RESTART_AFTER_BACKUP=false, run the cold-backup block once, thenunset RESTART_AFTER_BACKUP.docker rm autogpt(stopped container only).- Re-run the original
docker runwith the new image reference. - Wait for health; test login, memory, one agent execution, streaming, WebSockets, and persistence across one restart.
Secret-generation upgrade (installs from before per-install secrets): stop, export OLD_ENCRYPTION_KEY (for never-set keys it's the .env.default value at tag autogpt-platform-beta-v0.7.4), blank the three secret lines, make init-env, build + migrate, run cli rotate-encryption-key (dry run) then --apply, clear platform."UserAuthJwks" if BETTER_AUTH_SECRET changed, and start. Do the re-encryption before starting the stack on the new key.
Supabase → Better Auth upgrade: the database moves to pgvector/pgvector:pg15 at autogpt_platform/data/db/data; old data remains at autogpt_platform/db/docker/volumes/db/data. Either reuse the data directory (same major version; may fail on missing Supabase extensions/roles) or dump/restore with --no-owner --no-privileges, dropping the auth shim schema first. Users are copied by migration 20260716120000_copy_supabase_users_to_better_auth. frontend/scripts/migrate-supabase-auth.ts is only for live cutovers. Neither data path has been validated against a real old volume — back up first.
7.3 Logging
| Where | How |
|---|---|
| Compose | docker compose logs -f <service>; make logs-core for core deps |
| Appliance | docker logs --follow --tail 100 autogpt; json-file driver capped at 5 × 50 MB |
| Error tracking | SENTRY_DSN |
| LLM tracing / prompts | Langfuse (LANGFUSE_*); also manages the AutoPilot system prompt externally |
| Product analytics | PostHog (POSTHOG_*) |
| Chat inspection | poetry run cli chat list / cli chat view SESSION_ID [RANGE] --json |
Log style (backend convention): %s deferred interpolation in debug, f-strings elsewhere; error messages use os.path.basename() to avoid leaking paths.
7.4 Monitoring & Health Checks
| Endpoint / command | What it proves |
|---|---|
GET :8006/health |
REST server up and DB connected ({"status":"healthy"}; raises UnhealthyServiceError("Database is not connected") otherwise) |
GET :8001/health (and /) |
WebSocket server up |
Appliance GET /healthz |
nginx only — not whole-appliance readiness |
docker exec autogpt autogpt-healthcheck |
Every bundled dependency and application role |
| Compose healthchecks | rabbitmq-diagnostics -q ping, DB and Redis checks gate dependent services (service_healthy) |
curl -s http://localhost:8006/health
{"status":"healthy"}
Built-in alerting (via configured Discord channels / notifications):
| Signal | Setting |
|---|---|
| Block error rate | block_error_rate_threshold 0.5, checked every block_error_rate_check_interval_secs (24 h), top 3 blocks reported |
| Late executions | Queued longer than execution_late_notification_threshold_secs (300 s) within a 1-hour window |
| Low balance | low_balance_threshold (500) |
| Execution accuracy | Every execution_accuracy_check_interval_hours (24) |
Load testing: autogpt_platform/backend/load-tests/ (k6). Targets: core API P95 < 2 s, marketplace P95 < 5 s, success > 95 %.
cd autogpt_platform/backend/load-tests
node generate-tokens.js --count=160
node orchestrator/orchestrator.js DEV local
7.5 Backup & Restore
Compose. Back up PostgreSQL (and FalkorDB if you rely on memory) with service-native tools:
docker compose exec db pg_dump -U postgres -d postgres -Fc -f /tmp/autogpt.dump
docker compose cp db:/tmp/autogpt.dump ./autogpt.dump
Also preserve backend/.env — especially ENCRYPTION_KEY, without which restored credentials are unreadable.
Appliance cold backup. The documented block (in docs/platform/single-container.md):
- refuses anonymous volumes and a stopped/crashed appliance;
- takes an atomic lock (a stopped helper container named
autogpt-backup-lock); - captures the exact image ID/digest, stops the appliance, and tars
/dataread-only with--network none, excluding./cache; - writes
autogpt-data-<UTC timestamp>.tgzplus.sha256, promoting from.partialonly on success; - restarts the appliance unless
RESTART_AFTER_BACKUP=false.
Caution
Backups are plaintext and contain user content, provider credentials, auth keys, and database passwords. Encrypt them and delete staging copies. Stale
*.partialfiles from interrupted runs may also contain secrets. After aSIGKILL/host crash, confirm no backup is running, then remove a stale lock withdocker rm --volumes autogpt-backup-lock.
There is no supported hot backup for the appliance's coupled volume.
Restore always goes into a new named volume (autogpt-data-restored-<ts>-<pid>-<random>), verifies the SHA-256, labels the volume with a per-run owner, extracts with --network none, then validates the layout offline (runtime.env, backend.json, PG_VERSION, Postgres configs, RabbitMQ mnesia, three Valkey dirs, FalkorDB, workspaces, store-media, homes) and rejects unsafe Postgres configuration. Only then launch with the recorded image, env file, publish spec, and optional ADD_HOST_SPEC.
Warning
tarruns as root during restore and preserves ownership and setuid bits. Only restore archives from a trusted backup process. A full recovery rehearsal boots live schedules and credentials — do it on an egress-filtered host after revoking production credentials.
8. Performance Tuning
| Lever | Setting | Default | Guidance |
|---|---|---|---|
| Graph worker concurrency | num_graph_workers |
10 |
Raise with CPU and DB headroom; add executor replicas to scale out |
| AutoPilot workers | num_copilot_workers |
5 |
Bounded also by per-user caps |
| Per-user graph cap | max_concurrent_graph_executions_per_user |
25 |
Protects shared capacity |
| AutoPilot per-user caps | max_inflight_copilot_turns_per_user / max_running_copilot_turns_per_user |
15 / 5 |
|
| FastAPI threadpool | fastapi_thread_pool_size |
60 |
For sync handlers |
| DB pool | DB_CONNECTION_LIMIT |
12 (Compose), 5 max (appliance) |
Every role holds its own pool — total = roles × limit; stay under Postgres max_connections |
| DB timeouts | DB_CONNECT_TIMEOUT / DB_POOL_TIMEOUT |
60 / 300 |
Lowering pool timeout fails faster; it doesn't add capacity |
| LLM calls | llm_request_timeout_seconds |
600 |
|
| RPC | rpc_client_call_timeout, pyro_client_* |
300, 15/100/30.0 |
|
| Graphiti | GRAPHITI_SEMAPHORE_LIMIT |
5 |
|
| ClamAV | clamav_max_concurrency, clamav_service_timeout |
10, 60 |
|
| Uploads | upload_file_size_limit_mb, max_file_size_mb |
256, 100 |
|
| Codex processes | codex_max_active_processes |
4 |
Bounded by --shm-size in the appliance |
Tip
If requests stall under concurrent runs, inspect backend and PostgreSQL logs for pool exhaustion before changing limits. On the appliance, the fixed pools are the ceiling — move to a distributed deployment when they're insufficient.
Batch LLM work: the BatchExecutor polls submitted LLM batches (Anthropic) so slow batch polls never starve the scheduler's cron tick; the memory "dream pass" uses it when an Anthropic key is configured and falls back to a synchronous baseline otherwise.
9. Integrations
9.1 API Internals
The backend is one FastAPI app (backend/api/rest_api.py) with feature routers mounted under /api, the External API mounted as a sub-app at /external-api, and /health.
Router mount map (selected)
| Prefix | Feature |
|---|---|
/api |
Graphs (/api/graphs...), executions, blocks, v1 features, experts, memory, home, desktop preview, trials |
/api/library |
Library agents, folders, presets |
/api/store |
Marketplace (profiles, agents, creators, submissions, media) |
/api/store/skills |
Skill listings |
/api/builder |
Builder helpers |
/api/credits |
Credits and billing |
/api/executions |
Admin execution analytics |
/api/integrations |
Credentials, OAuth callbacks, webhook ingress (/generic_webhook/webhooks/{id}/ingress), providers |
/api/api-keys |
API key management |
/api/skills |
Skills |
/api/copilot |
AutoPilot |
/api/admin |
Admin routes |
/api/review |
Human review (pending reviews) |
/api/auth/email |
Auth email actions |
/api/analytics, /api/experiments |
Analytics and experiments |
/api/oauth/* |
OAuth provider (token, introspect, revoke) |
/api/copilot-webhooks/teams/messages |
Teams bot messaging endpoint |
/external-api/v1 |
Public External API |
Graph routes (/api)
| Method | Path |
|---|---|
GET |
/api/graphs |
POST |
/api/graphs |
GET |
/api/graphs/{graph_id} |
PUT |
/api/graphs/{graph_id} |
DELETE |
/api/graphs/{graph_id} |
GET |
/api/graphs/{graph_id}/versions |
GET |
/api/graphs/{graph_id}/versions/{version} |
PUT |
/api/graphs/{graph_id}/versions/active |
PATCH |
/api/graphs/{graph_id}/settings |
POST |
/api/graphs/{graph_id}/execute/{graph_version} |
Library routes (/api/library)
| Method | Path | Handler |
|---|---|---|
GET |
/agents |
list_library_agents |
GET |
/agents/favorites |
list_favorite_library_agents |
GET |
/agents/{library_agent_id} |
get_library_agent |
GET |
/agents/by-graph/{graph_id} |
get_library_agent_by_graph_id |
GET |
/agents/marketplace/{store_listing_version_id} |
get_library_agent_by_store_listing_version_id |
POST |
/agents |
add_marketplace_agent_to_library |
PATCH |
/agents/{library_agent_id} |
update_library_agent |
DELETE |
/agents/{library_agent_id} |
delete_library_agent |
POST |
/agents/{library_agent_id}/fork |
fork_library_agent |
GET |
/agents/{library_agent_id}/triggers |
list_trigger_agents |
GET |
/folders |
list_folders |
GET |
/folders/tree |
get_folder_tree |
GET |
/folders/{folder_id} |
get_folder |
POST |
/folders |
create_folder |
PATCH |
/folders/{folder_id} |
update_folder |
POST |
/folders/{folder_id}/move |
move_folder |
DELETE |
/folders/{folder_id} |
delete_folder |
POST |
/folders/agents/bulk-move |
bulk_move_agents |
GET |
/presets |
list_presets |
GET |
/presets/{preset_id} |
get_preset |
POST |
/presets |
create_preset |
POST |
/presets/setup-trigger |
setup_trigger |
PATCH |
/presets/{preset_id} |
update_preset |
DELETE |
/presets/{preset_id} |
delete_preset |
POST |
/presets/{preset_id}/execute |
execute_preset |
External API v1 (/external-api/v1)
| Method | Path | Permission / scope |
|---|---|---|
GET |
/me |
IDENTITY |
GET |
/blocks |
READ_BLOCK |
POST |
/blocks/{block_id}/execute |
EXECUTE_BLOCK |
POST |
/graphs |
WRITE_GRAPH + WRITE_LIBRARY |
POST |
/graphs/{graph_id}/execute/{graph_version} |
EXECUTE_GRAPH — body {"node_input": {...}}, returns {"id": "<graph_exec_id>"} |
GET |
/graphs/{graph_id}/executions/{graph_exec_id}/results |
READ_GRAPH — includes status; 404 if graph or execution missing |
GET |
/store/agents |
Any valid auth (public data; auth required as anti-DDoS) |
GET |
/store/agents/{username}/{agent_name} |
Any valid auth |
GET |
/store/creators |
Any valid auth |
GET |
/store/creators/{username} |
Any valid auth |
Additional External API modules (external/v1/integrations.py, tools.py) expose integration management and platform tools under the same prefix; the Swagger UI at /external-api/docs is authoritative.
Export the OpenAPI schema:
cd autogpt_platform/backend
poetry run export-api-schema --output openapi.json --pretty
The frontend's typed client is generated with pnpm generate:api-client.
Error semantics: 400 bad parameters, 401 invalid/expired credentials, 403 missing scope/permission, 404 missing resource, 429 AutoPilot spend cap, 503 paywall tier-lookup failure on execute.
9.2 Webhooks
Inbound triggers. A webhook-triggered block declares webhook_config (BlockWebhookConfig), an event filter input (a Pydantic model of booleans whose field name matches webhook_config.event_filter_input), a payload input, and a credentials input with scopes sufficient to manage webhooks. A provider's WebhooksManager (subclass of BaseWebhooksManager in integrations/webhooks/_base.py) registers/deregisters webhooks with the provider and validates payloads; register it in load_webhook_managers in integrations/webhooks/__init__.py. Webhook records live in IntegrationWebhook.
Generic ingress URL:
https://<backend>/api/integrations/generic_webhook/webhooks/<webhook-id>/ingress
Important
Override
verify_signaturewithhmac.compare_digestfor any provider that signs deliveries and raisefastapi.HTTPException(403)on failure. For unsigned providers, the webhook UUID is a bearer secret — document that.
Stripe billing webhooks use STRIPE_WEBHOOK_SECRET; Postmark webhooks use POSTMARK_WEBHOOK_TOKEN.
Chat-bot webhooks. copilot/bot/ implements a connector taxonomy:
| Adapter type | Platforms | Runs in |
|---|---|---|
SocketAdapter |
Discord Gateway, Slack Socket Mode | copilot-bot process (start/stop) |
WebhookAdapter |
Slack Events API, Telegram, Microsoft Teams (WhatsApp next) | Mounted on the main REST API via register_webhook_adapters |
Factories: app.py::_build_socket_adapters, webhook_routes.py::_build_webhook_adapters — each gated on its tokens being set. Messaging: link check → Link Account prompt or thread creation → Redis-subscribed thread (7-day TTL) → streamed AutoPilot reply chunked at chunk_flush_at → messages arriving mid-stream batched into one follow-up turn.
Teams specifics: signed Bot Framework JWT (auth the sender, not the body — serviceurl claim binding closes replay); replies go to the activity's serviceUrl (host-allowlisted); single-tenant only (MICROSOFT_TENANT_ID mandatory since 2025-07-31); no native slash commands in channels (must @mention); group chats accepted and ignored; at-most-once delivery via a Redis activity-id claim; the learned serviceUrl map is per process. Local testing with the M365 Agents Playground requires both APP_ENV=local and AUTOPILOT_BOT_TEAMS_ALLOW_UNVERIFIED=true.
9.3 Plugin / Extension System: blocks
Blocks are the extension point. Every .py under backend/blocks/ is auto-imported at startup (except __init__.py and test_* files); no registration needed.
Block anatomy
| Element | Requirement |
|---|---|
| Class | Subclass Block (backend.blocks._base or backend.sdk) |
Input |
BlockSchemaInput with SchemaField(...) fields (advanced=True hides from basic UI; ge/le constraints) |
Output |
BlockSchemaOutput (the error pin is predefined) |
id |
A real uuid.uuid4() — never invented |
categories |
BlockCategory values (e.g. SEARCH, AI, PRODUCTIVITY) |
run() |
async def run(self, input_data, *, credentials=..., **kwargs) -> BlockOutput, yielding (name, value) |
| Tests | test_input, test_output (values or types), test_mock, test_credentials |
Runtime kwargs available to run(): user_id, graph_id, graph_exec_id, node_exec_id, node_id, execution_context (ExecutionContext: user_id, graph_exec_id, workspace_id, session_id — required for file handling).
Yield rules: prefer one result object at a time; for lists, yield each item and optionally the whole list. Yielding error stops the node and marks it failed; prefer raising.
Errors: raise BlockInputError (invalid input) or BlockExecutionError (user-addressable runtime failure) from backend.util.exceptions; bare ValueError is auto-wrapped. Don't wrap logic in blanket try/except, and don't catch infrastructure failures (out of credits, DB down, internal 5xx) — let them surface.
Files: store_media_file(file=..., execution_context=..., return_format=...):
return_format |
Returns | Use |
|---|---|---|
for_local_processing |
Local path | ffmpeg, MoviePy, PIL |
for_external_api |
Data URI | Replicate, OpenAI |
for_block_output |
workspace:// in AutoPilot, data URI in graphs |
Always for outputs |
Credentials
| Pattern | How |
|---|---|
| API key only (recommended) | Add ProviderName member → _auth.py (CredentialsMetaInput[Literal[ProviderName.X], Literal["api_key"]], a field factory, TEST_CREDENTIALS, TEST_CREDENTIALS_INPUT) → _config.py with ProviderBuilder(...).with_description(...).with_supported_auth_types("api_key").build() |
| SDK provider | ProviderBuilder("x").with_api_key(ENV, title).with_base_cost(1, BlockCostType.RUN).build(); fields via provider.credentials_field() |
| OAuth2 | OAuthHandler subclass of BaseOAuthHandler, added to HANDLERS_BY_NAME (integrations/oauth/__init__.py) and {provider}_client_id/secret in Secrets; or .with_oauth(Handler, scopes=..., client_id_env_var=..., client_secret_env_var=...) |
| Multiple credentials | Field names end with _credentials and match run() parameter names |
| Other | .with_user_password(), .with_webhook_manager() |
Use credentials.auth_header() or credentials.api_key.get_secret_value() / credentials.access_token.get_secret_value(). Blocks that need OAuth with no API-key fallback should disable themselves when OAuth isn't configured (Google uses GOOGLE_OAUTH_IS_CONFIGURED).
Frontend: add frontend/public/integrations/{provider_name}.png (missing icon = broken image in the Blocks menu). Provider names, descriptions, and auth types are fetched from GET /integrations/providers — no frontend registration needed.
Networking: always use backend.util.request.Requests / backend.sdk.Requests (SSRF protection).
Docs sync (CI-enforced):
cd autogpt_platform/backend
poetry run python scripts/generate_block_docs.py
Writes docs/integrations/block-integrations/{provider}/{module}.md; the "Block Documentation Sync Check" workflow fails PRs whose docs drift. Preserve hand-written content between <!-- MANUAL: use_case --> … <!-- END MANUAL --> (sections how_it_works, use_case, extras, file_description, additional_content).
Integration checklist
- [ ] Provider name registered (
ProviderNameorProviderBuilder) - [ ] Credentials in
_auth.py/ SDK config; description + auth types in_config.py - [ ] Input/Output schemas, real UUID, categories, async
run() - [ ]
BlockInputError/BlockExecutionErrorfor user-fixable errors - [ ] Inline tests and/or
{name}_test.py - [ ] Icon PNG added
- [ ] Block docs regenerated
Reference implementations: blocks/firecrawl/ (simple API key), blocks/linear/ (OAuth + API key), blocks/exa/ (webhooks), blocks/github/ (triggers + OAuth), blocks/zerobounce/ (_auth.py/_config.py pattern), blocks/typesafe/ and blocks/slant3d/ (documented provider packages).
9.4 LLM model catalog
Models, costs, and AutoPilot routing are catalog-as-code in backend/data/llm_registry/catalog.py. Block-selectable models also need a line in backend/data/llm_registry/llm_models.py (an import-time check enforces pairing). Catalog-only diffs may ship via hotfix/* → master.
9.5 MCP integrations
Hosted MCP services appear in Settings → Integrations with an MCP badge; catalog maintenance is documented in docs/platform/contributing/hosted-mcp-catalog.md. Open issue #15032 notes that AutoPilot's find_capability doesn't yet search user-connected custom MCP servers.
10. Developer Internals
10.1 Branching and contribution
| Rule | Detail |
|---|---|
| Main dev branch | dev (all PRs target it) |
| Production | master |
| Hotfix exception | LLM-catalog-only diffs via hotfix/* → master |
| PR structure | Why / What / How; one concern per PR; conventional commits |
| TDD | Failing test first (@pytest.mark.xfail / Playwright .fixme), then fix, then remove marker |
10.2 Backend code conventions (from backend/AGENTS.md)
- Top-level, absolute imports (single-dot relative allowed within a package).
- No duck typing for dispatch; Pydantic models over dicts/dataclasses.
- No linter suppressors (
# type: ignore,# noqa). - Files under ~300 lines; functions under ~40 lines; top-down ordering.
Security()(notDepends()) for auth dependencies so OpenAPI shows security.- Redis pipelines with
transaction=Truefor multi-step atomicity; TOCTOU awareness for file access and credit charging;max(0, value)guards. - SSE:
data:lines for parsed events (must match the frontend Zod schema),: commentlines for heartbeats.
10.3 Key classes
| Class | Module | Role |
|---|---|---|
AgentServer |
api/rest_api.py |
REST process |
WebsocketServer |
api/ws_api.py |
WebSocket process |
ExecutionManager, Scheduler |
executor/ |
Graph execution and scheduling |
BatchExecutor |
executor/batch_executor.py |
LLM batch polling |
DatabaseManager |
data/db_manager.py |
DB RPC service |
NotificationManager |
notifications/notifications.py |
Email/push |
PlatformLinkingManager |
platform_linking/manager.py |
Chat account linking |
CoPilotExecutor / CoPilotChatBridge |
copilot/executor/manager.py / copilot/bot/app.py |
AutoPilot turns / chat bridge |
SecurityHeadersMiddleware |
api/middleware/security.py |
Cache-protection headers |
Block, BlockSchemaInput, BlockSchemaOutput, BlockWebhookConfig |
blocks/_base.py |
Block framework |
ProviderBuilder |
sdk/ |
Provider registration |
BaseOAuthHandler / BaseWebhooksManager |
integrations/oauth/base.py / integrations/webhooks/_base.py |
Extension interfaces |
Config, Secrets |
util/settings.py |
Settings |
10.4 Classic AutoGPT internals
| Part | Summary |
|---|---|
forge/ |
Component-based agent framework: BaseAgent auto-discovers AgentComponent attributes; ConfigurableComponent[BM] for Pydantic-configured components; built-in components (file manager, action history, watchdog, system, archive handler, data processor) |
original_autogpt/ |
CLI (autogpt run/serve/config) and Agent Protocol server (AP_SERVER_PORT, AP_SERVER_DB_URL, AP_SERVER_CORS_ALLOWED_ORIGINS) |
direct_benchmark/ |
Benchmark harness (strategies, models, categories, external benchmarks gaia/swe-bench/agent-bench) |
| Config | .env → .autogpt/autogpt.yaml → .autogpt/agents/{id}/permissions.yaml; SMART_LLM (gpt-4o), FAST_LLM (gpt-4o-mini), EMBEDDING_MODEL, DATABASE_STRING (sqlite:///agent.db), PORT (8000), FILE_STORAGE_BACKEND (local/s3/gcs), DISABLED_COMMANDS, RESTRICT_TO_WORKSPACE (True), TELEMETRY_OPT_IN |
| Permissions | command_name(glob) patterns; {workspace}, **, *; agent deny → workspace deny → agent allow → workspace allow → prompt |
| URL safety | forge/utils/url_validator.py blocks local files and private addresses |
Caution
Classic has known vulnerabilities in its dependencies and will not be updated. Don't deploy it on a network-reachable host.
10.5 Testing Strategy
| Layer | Tooling | Command |
|---|---|---|
| Backend unit/integration | pytest, colocated *_test.py, snapshot tests |
poetry run test or poetry run pytest path::test -xvs |
| Snapshots | pytest snapshot | poetry run pytest path --snapshot-update (review diffs) |
| All blocks | Inline block fixtures | poetry run pytest backend/blocks/test/test_block.py -xvs |
| One block | poetry run pytest 'backend/blocks/test/test_block.py::test_available_blocks[MyBlock]' -xvs |
|
| Block helper | execute_block_test(block) |
In a *_test.py |
| Frontend | pnpm test; Playwright E2E (PLAYWRIGHT_BASE_URL, PLAYWRIGHT_WORKERS, PLAYWRIGHT_RETRIES) |
pnpm test |
| Load | k6 orchestrator (12 tests; local 5 VUs × 30 s, cloud 80–160 VUs × 3–6 min) | node orchestrator/orchestrator.js DEV local |
| Appliance | single-container/tests/ (incl. test_runtime_config.py enforcing blank secrets) |
pytest |
| AutoPilot quality | Expert style eval | poetry run expert-style-eval --dry-run / --write-baseline (paid, roughly $1–2 per expert) |
| Classic | pytest | poetry run pytest forge/tests/ etc. |
Mocking rule: patch where a symbol is used (e.g. backend.blocks.my_provider.my_block.Requests.post), use AsyncMock for async. Block test files ending _test.py are auto-imported at startup — keep them side-effect-free, or name them test_*.py to opt out.
11. Troubleshooting
Boot and configuration
Error: ENCRYPTION_KEY is not set
Cause: Blank ENCRYPTION_KEY. Solution: make init-env, restart. Prevention: Include make init-env in provisioning.
Error: ENCRYPTION_KEY is set to a value that was published…
Cause: Pre-v0.7.4 default key. Solution: Run the secret-generation upgrade with OLD_ENCRYPTION_KEY and cli rotate-encryption-key --apply.
Error: ENCRYPTION_KEY is not set, so there is no key to re-encrypt under.
Cause: rotate-encryption-key run before a new key was set. Solution: Set the new ENCRYPTION_KEY first.
Error: --old-key is the configured ENCRYPTION_KEY. Change ENCRYPTION_KEY first, then pass the previous value here.
Solution: Put the new key in ENCRYPTION_KEY; pass the old one via --old-key/OLD_ENCRYPTION_KEY.
Error: Not a valid encryption key: ...
Solution: Generate a Fernet key: poetry run cli gen-encrypt-key.
Error: ENCRYPTION_KEY must be a Fernet-compatible key / must decode to exactly 32 bytes
Solution: Same — use a Fernet key, not an arbitrary string.
Error: JWT_JWKS_URL must be set to the JWKS endpoint of the platform auth service ...
Solution: Set JWT_JWKS_URL (e.g. http://frontend:3000/api/auth/jwks inside Compose).
Error: JWT_JWKS_URL fetches keys over cleartext http:// from a non-local host ('...')
Solution: Use HTTPS, or on a trusted isolated network set JWKS_ALLOW_INSECURE_TRANSPORT=true.
Error: Invalid JWT_JWKS_ALGORITHMS entry: '...'
Solution: Only asymmetric algorithms (ES256, RS256, EdDSA).
Error: 'cryptography' package is required for JWT verification but not installed
Solution: Reinstall backend dependencies (poetry install).
Error: Production environment cannot allow localhost origins
Also ... via regex: <pattern> and Production regex pattern matches localhost/127.0.0.1: <pattern>.
Solution: Remove localhost entries from BACKEND_CORS_ALLOW_ORIGINS in production.
Error: <Class>.expected_token is not set; either specify it or provide a custom validator
Cause: An API-key-protected internal route has no expected token configured. Solution: Set the corresponding token (e.g. POSTMARK_WEBHOOK_TOKEN for Postmark webhooks).
Error: Database is not connected (HTTP 5xx from /health)
Cause: Postgres unreachable or wrong DATABASE_URL. Solution: Check db health and credentials; confirm migrate completed.
Error: the specified Containerfile or Dockerfile does not exist
Cause: Podman. Solution: Use Docker.
db unhealthy on Windows
Solution: Switch Docker Desktop to the WSL 2 engine.
Nobody can reach the backend after rotating BETTER_AUTH_SECRET
Solution: DELETE FROM platform."UserAuthJwks"; then restart; keys regenerate on next sign-in.
Credentials marked revoked after starting on a new key
Solution: Stop, run rotate-encryption-key --apply, restart; users who reconnected in between must reconnect older credentials.
Supabase data directory restart-loops on pgvector/pgvector:pg15
Solution: Use the dump/restore fallback; drop the auth shim schema before pg_restore; verify select count(*) from auth.users before migrating.
Frontend (outside Docker) can't authenticate
Cause: Next.js reads only .env. Solution: make init-env; ensure DATABASE_URL and BETTER_AUTH_SECRET are in frontend/.env.
Appliance runtime configuration
Error: AUTOGPT_PUBLIC_URL must use http or https
Siblings: must include a host, must not include credentials, must be an origin without path, query, or fragment, has an invalid port, has an invalid host. Solution: A bare origin.
Error: <NAME> differs from the value persisted on first boot; restore the original value or start with a new data volume
Solution: Remove the override; generated secrets cannot be rotated in place.
Error: runtime configuration has missing or unknown keys / unsupported runtime configuration version / invalid runtime configuration line N
Cause: /data/config/runtime.env was edited or is from an incompatible version. Solution: Don't edit runtime.env; restore it from backup or start a new volume.
Error: runtime configuration is not a regular file: <path> / refusing symlink at <path>
Solution: Replace the symlink/special file with the original regular file.
Error: RABBITMQ_DEFAULT_USER may not use the built-in guest account / contains unsupported characters
Solution: Pick another username.
Error: <NAME> must be at least 32 URL-safe characters / invalid URL-safe base64 value
Solution: Provide a longer URL-safe value, or let the appliance generate it.
Error: VAPID_PRIVATE_KEY and VAPID_PUBLIC_KEY must be set together
Also VAPID_PRIVATE_KEY must decode to exactly 32 bytes, VAPID_PUBLIC_KEY must be an uncompressed P-256 public key, cryptography is required to generate VAPID keys. Solution: Generate a proper pair or set neither.
Startup rejects DB_CONNECTION_LIMIT / DB_CONNECT_TIMEOUT / DB_POOL_TIMEOUT
Solution: Ranges 1–5, 1–600, 1–3600.
Startup rejects legacy JWT secrets
Solution: Remove JWT_VERIFY_KEY and SUPABASE_JWT_SECRET on fresh installs; for legacy migration set AUTOGPT_ENABLE_LEGACY_AUTH=true and both to the same ≥32-character secret.
Startup stops because email verification is enabled
Solution: AUTH_REQUIRE_EMAIL_VERIFICATION=false (unsupported in the appliance).
Health probe errors: AMQP credentials are missing / AMQP connection failed
Solution: Check RabbitMQ state in /data/rabbitmq and logs for the state:rabbitmq process.
Health probe errors: Redis authentication failed / Redis cluster is not healthy / Redis did not return PONG / Redis closed the connection
Solution: Inspect Valkey process logs; confirm the three nodes (17000–17002) started; check disk space in /data/valkey.
Health probe error: HTTP <status> from <url>
Solution: The named internal HTTP service is failing; read its supervisor log.
Supervisor errors: Supervisor event payload is too large / ended unexpectedly / has an unsupported type / has an invalid payload length
Cause: The fatal-event listener received malformed events. Solution: Restart the container; if recurring, capture logs for an issue report.
Container stays starting / becomes unhealthy
Solution: docker exec autogpt autogpt-healthcheck, then the logs for the first failed service. The watchdog stops the container after 600 s.
OOM-killed during startup
Solution: More memory; the appliance needs more than 5–6 GiB.
Interrupted migration blocks startup
Solution: Empty install → discard volume; existing → restore backup. prisma migrate resolve only from a separate recovery environment after verifying the DB state.
Data missing after replacing the container
Solution: Reattach the original named volume (check with the /data mount inspect command).
Backup refuses to run
Messages: Refusing backup because /data uses an anonymous volume, ... another backup may be running or its lock is stale, ... the autogpt container is not running, Refusing to overwrite an existing backup. Solution: Use a named volume; clear a stale autogpt-backup-lock only after confirming no backup is running; start and verify health first.
Restore refuses to run
Messages: Backup checksum verification failed, Refusing to reuse existing volume, ... ownership cannot be verified. Solution: Use a trusted archive/checksum pair and a fresh volume name.
Runtime and capacity
Runs stuck in RUNNING after restart
Solution: Start new runs; abandoned runs never resume.
Requests stall under concurrent runs
Solution: Check for pool exhaustion; reduce concurrency or scale out (appliance pools are capped at 5).
Valkey or FalkorDB memory/disk keeps growing
Cause: No appliance-level ceiling or eviction. Solution: Monitor, back up, and move to a distributed deployment for growth.
/setup fails with httpx.ConnectError
Solution: Start platform_linking_manager (--profile bot).
Teams bot replies 404 for some tenants
Cause: Per-process serviceUrl map; a cold replica falls back to the default host. Solution: Keep replies reactive; persist the mapping in Redis before enabling proactive sends.
Teams bot drops a turn
Cause: At-most-once delivery (claim before processing). Solution: Ask the user to resend; release the claim on failure if you prefer retries over duplicates.
AutoPilot 401 / 429
Solution: 401 → set the transport's key (OPEN_ROUTER_API_KEY for the default route, OPENAI_API_KEY for memory); 429 → spend cap reached.
Local memory ingestion fails
Solution: Pull the embedding model; set GRAPHITI_LLM_MODEL, GRAPHITI_RERANKER_MODEL, GRAPHITI_EMBEDDER_MODEL to slugs your server serves.
ValueError: graph_exec #<id> not found for user #<user> (WebSocket subscribe)
Cause: Client subscribed to an execution it doesn't own or that doesn't exist. Solution: Verify the execution ID and user.
ValueError: Execution <id> not found
Solution: The execution was deleted or belongs to another user.
Schedule fires after its expert workflow was removed
Cause: Open issue #14607. Solution: Delete the schedule manually.
Development
Block shows a broken icon
Solution: Add frontend/public/integrations/{provider}.png.
CI "Block Documentation Sync Check" fails
Solution: poetry run python scripts/generate_block_docs.py, commit.
Block test fails with a type error on credentials
Cause: Missing CredentialsMetaInput[Literal[ProviderName.X], Literal["api_key"]] type hint. Solution: Add the full type hint.
Block module side effects run at startup
Cause: *_test.py files are auto-imported. Solution: Keep them side-effect-free or rename to test_*.py.
prisma generate writes to the global interpreter
Solution: pip uninstall prisma, rerun poetry run prisma generate.
OAuth tool: At least one scope is required / Invalid scope: ...
Solution: Pass --scopes with valid scope names (e.g. EXECUTE_GRAPH,READ_GRAPH).
CLI: Invalid --range '...'; use forms like '7', '6-10', '6-', '-10'. / start is after end
Solution: Fix the cli chat view range.
Load tests: No valid authentication token available / Token has expired
Solution: node generate-tokens.js --count=160 (24-hour tokens).
Load tests show 5 VUs in k6 cloud
Solution: k6 cloud run --env K6_ENVIRONMENT=DEV --env VUS=160 test.js.
Direct benchmark: Unknown benchmark: <name>. Available: ... / Workspace not initialized
Solution: Use gaia, swe-bench, or agent-bench; pass a valid --workspace.
12. Potential Improvements
| Area | Observation | Suggestion |
|---|---|---|
| Scheduling correctness | Issue #14607: a schedule survives removal of its workflow from an expert because execution doesn't check membership | Validate expert-workflow membership at fire time; delete schedules on workflow removal |
| Block authoring | Issue #15025: no scaffolder; block ID collisions are possible and the pairing of structural and dynamic tests is manual | Add a generator that mints the UUID, checks collisions, and creates tests + docs stubs |
| AutoPilot discovery | Issues #15032 / #14829: find_capability doesn't search user-connected custom MCP servers (skills search was a prior gap) |
Index connected MCP tools in the capability search |
| Appliance resource bounds | Valkey and FalkorDB have no memory ceiling/eviction | Ship default maxmemory policies and alerts |
| Appliance backup | Cold backup only; coupled volume | Offer per-service hot backup (e.g. pg_basebackup) for larger installs |
| Appliance secrets | No in-place rotation of generated secrets | Add a supported rotation command mirroring rotate-encryption-key |
| Appliance uploads | No malware scanning | Optional bundled ClamAV profile |
| Email verification | Unsupported in the appliance | Support required verification via Postmark |
| Appliance → distributed migration | No in-place conversion; accounts, runs, schedules, credentials, memory aren't migrated | Provide an export/import path for full state |
| Supabase upgrade | Both data-migration routes are unvalidated against real old volumes | Add an automated, tested migration tool |
| Teams bot | At-most-once delivery; per-process serviceUrl map |
Persist mapping in Redis; configurable retry semantics |
| Published dev keys | .env.default still ships a dev VAPID keypair and a RabbitMQ dev password |
Move them to BLANK_IN_ENV_DEFAULT and generate at init-env |
| Pool sizing | Per-role pools multiply connections; appliance capped at 5 | Add pgbouncer or a shared pool for the appliance |
| In-flight runs | Abandoned on shutdown; rows remain RUNNING |
Reconcile orphaned executions on startup |
| Classic | Unsupported with known vulnerable dependencies | Archive into a separate repository or pin/scan dependencies |
| Hosted installer | Not yet live; README points to the manual path | Complete release gates for the appliance installer |
13. Quick Reference
Paths
| Item | Path |
|---|---|
| Compose project | autogpt_platform/ |
| Backend env | autogpt_platform/backend/.env |
| Frontend env | autogpt_platform/frontend/.env |
| Postgres data (Compose) | autogpt_platform/data/db/data |
| Old Supabase data | autogpt_platform/db/docker/volumes/db/data |
| Blocks | autogpt_platform/backend/backend/blocks/ |
| Settings model | autogpt_platform/backend/backend/util/settings.py |
| Prisma schema | autogpt_platform/backend/schema.prisma |
| Model catalog | autogpt_platform/backend/backend/data/llm_registry/catalog.py |
| Appliance secrets | /data/config/runtime.env |
Ports
| Port | Service |
|---|---|
| 3000 | Frontend / appliance nginx |
| 8001 | WebSocket |
| 8002 | Executor |
| 8003 | Scheduler |
| 8005 | Database manager |
| 8006 | REST API |
| 8007 | Notifications |
| 8008 | AutoPilot executor |
| 8009 | Platform linking manager |
| 8010 / 8011 | Chat bridge / batch executor (config defaults) |
| 5432 | PostgreSQL |
| 5672 | RabbitMQ |
| 17000–17002 | Redis cluster |
| 6380 / 3001 | FalkorDB / FalkorDB UI |
| 3310 | ClamAV |
Commands
| Task | Command |
|---|---|
| Initialize env | make init-env |
| Start stack | docker compose up -d --build |
| Migrate | docker compose run --rm migrate |
| Health | curl http://localhost:8006/health |
| New encryption key | poetry run cli gen-encrypt-key |
| Rotate key | docker compose run --rm --no-deps -e OLD_ENCRYPTION_KEY rest_server cli rotate-encryption-key --apply |
| Reset JWKS | docker compose exec db psql -U postgres -c 'DELETE FROM platform."UserAuthJwks";' |
| Register OAuth app | poetry run oauth-tool generate-app --name ... --redirect-uris ... --scopes ... |
| Export OpenAPI | poetry run export-api-schema --output openapi.json --pretty |
| Test all blocks | poetry run pytest backend/blocks/test/test_block.py -xvs |
| Regenerate block docs | poetry run python scripts/generate_block_docs.py |
| Appliance admin | docker exec autogpt autogpt-admin promote EMAIL |
| Appliance health | docker exec autogpt autogpt-healthcheck |
| Appliance processes | docker exec autogpt supervisorctl status |
Critical settings
| Setting | Value |
|---|---|
ENCRYPTION_KEY |
Generated Fernet key — back it up |
JWT_JWKS_URL |
https://<frontend>/api/auth/jwks when split |
BEHAVE_AS |
local single-tenant / cloud multi-tenant |
AUTOGPT_PUBLIC_URL |
Exact browser origin |
AUTH_ALLOW_NEW_ACCOUNTS |
false after bootstrap |
DB_CONNECTION_LIMIT |
≤ 5 on the appliance |