Repository navigation
cmd doctor
Run full system diagnostics.
nself doctor <subcommand> [flags]
nself doctor checks everything ɳSelf needs to function correctly and reports issues with actionable fix suggestions. It covers infrastructure prerequisites (Docker, Docker Compose, Git), Docker daemon health and permissions, disk and memory availability, network connectivity, configuration correctness, running container health, and plugin schema placement.
Run nself doctor when something is not working as expected, before deploying to a new environment, or as part of an automated health check pipeline. The --fix flag enables automatic remediation of common problems.
The --deep flag runs all 12 subsystem checks including open port analysis, weak cipher detection, exposed service bindings, container-level security, and a CIS container benchmark subset. The deep scan runs without a license key: all hardening checks are free by design.
The Generated files section compares recorded file hashes in .nself/state/generated.json with the files on disk, without querying Docker or rendering a fresh build. It lists changed or deleted recorded paths and marks changed files as hand-edited. If there is no project root, the check is skipped. nself doctor --fix repairs through the build reconcile path; a second run has no generated-file changes. nself doctor --fix --plan prints the repair plan without writing. On prod or staging, a noninteractive repair needs --yes; overwriting a hand-edited generated file needs --force in v1.5 mode.
Deep mode's automatic fixes run only validated nself commands and docker restart for containers whose Compose project label matches this project. Suggestions with shell syntax, system commands, and Docker prune are shown as manual steps. The human and JSON reports show which fixes ran or failed.
In v1.5 mode, standard and deep diagnostics report untracked manifest tables for installed plugins that declare migrations.apply: boot. For an offline install, run nself start, then nself doctor --fix: the repair waits for the affected plugins' boot migrations, tracks missing tables on Hasura's default source, and verifies the result. It never starts the stack. Already tracked plugins need no readiness wait or metadata write. Metadata repairs on prod or staging require --yes or terminal confirmation even when generated files have no drift. --fix --plan remains an offline generated-file plan; it does not inspect or repair live Hasura metadata. Deep mode includes this check with --only plugins or no section filter.
| Code | Meaning |
|---|---|
0 |
All checks passed |
1 |
One or more checks failed |
2 |
Warnings only, no failures |
| Code | Meaning |
|---|---|
0 |
All checks passed |
1 |
One or more failures (no critical findings) |
2 |
One or more CRITICAL security findings |
CRITICAL findings include: world-readable secret files, sensitive ports bound on 0.0.0.0, missing JWT secrets, and weak SSL cipher suites. These indicate an immediate security risk and must be resolved before the service is considered safe to run.
| Category | What is Checked |
|---|---|
| Infrastructure |
docker, docker compose, git are installed |
| Docker | Daemon running, BuildKit available, Compose v2 |
| Disk | At least 5 GB free space recommended |
| Memory | At least 2 GB RAM recommended (with --full) |
| Network | Internet connectivity, Docker Hub reachable (with --full) |
| Configuration |
.env exists, required vars set, password strength meets requirements, default Postgres credentials warned in prod/staging |
| Containers | Health status of running containers, error logs for unhealthy services |
| Plugin schemas | Warns if np_* tables are in the public schema instead of plugin schemas |
| License | License cache age and tier |
| TLS | Certificate each served host actually presents: expiry, served vs on disk, renewed but not installed (see below) |
The TLS section asks the nginx that is actually serving your stack, not the files on disk, which certificate it presents. For every server_name in a 443 block of the served nginx/sites/*.conf and nginx/conf.d/*.conf it opens a TLS connection with that name as SNI and prints one line:
TLS api.example.com: R11 expires 2026-12-30 (88 days)
Wildcards, IP addresses, localhost, _ and the .local, .localhost and .test names are not checked. Names that appear only in a certificate's alternative names reach the default server and are not listed.
| Condition | Result |
|---|---|
| 21 or more days left | pass |
| Fewer than 21 days left | warn |
| Fewer than 7 days left, or already expired | fail |
| nginx is running but does not answer a TLS handshake on its configured address (a wrong port included) | fail; when the address refuses or times out, the remaining hosts fail with the same message without dialling again |
| The served certificate does not cover the host name (a wildcard covers one label) | fail, on a separate TLS <host> name line |
| More than one running nginx container matches the stack | fail, naming the containers |
Two further warnings can follow a host line:
-
Served differs from disk. The certificate nginx presents is not the file named by that host's own
ssl_certificateline (mapped from/etc/nginx/sslonto the stack'sssl/directory). nginx has not been reloaded since the file changed. Fix: reload nginx. Generated route hosts such asapi.<base domain>use the base domain's certificate directory, and are compared against that file. -
Renewed but not installed. A newer certificate covering the host exists in
<ssl dir>/.acme/certificates/or in a readable/etc/letsencrypt/live/*/cert.pem, while nginx still serves an older one. The warning names both expiry dates. Fix: install the renewed certificate into the stack'sssl/directory and reload nginx.
A chain that does not verify against the system roots warns on a separate TLS <host> chain line when SSL_MODE=letsencrypt (a common cause is serving cert.pem instead of fullchain.pem). For other modes, such as a private CA, it is printed as detail and does not change the verdict.
A conf that cannot be read, or a TLS host whose block names no ssl_certificate (for example one set through include), produces a warning for that file or host; the other hosts are still checked. An ssl_certificate set at http or file level is inherited by the servers below it.
Fronted projects. When NGINX_FRONTED_BY is set (the production layout, a project in nself-web/backend served by the nginx of nself-web), the check uses the fronting stack's nginx/ confs, ssl/ directory, .env files and nginx container. The dial address comes from that stack's .env, then .env.<ENV>: NGINX_HTTPS_PORT, else NGINX_SSL_PORT, else 443 on NGINX_BIND_IP (127.0.0.1 when unset or 0.0.0.0). Only that address is contacted; no public DNS or internet probe is made.
For a project that runs its own nginx, the port and bind IP come from the project's full env cascade (so .env.local overrides count), the same values compose publishes.
Skips. The section prints a single TLS: skipped (<reason>) line, and the line never affects the exit code, when SSL_MODE is local or none, when no nginx container is running for the stack, when Docker cannot be queried, when the fronting layout cannot be resolved, or when no TLS host is configured. A skip is never counted as a pass.
Because a warning or failure here is a normal doctor result, nself doctor exits 2 (warnings) or 1 (failures) when a certificate is close to expiry.
| Section | What is Checked |
|---|---|
host |
Disk free, swap usage, CPU load, clock sync, kernel tainted flag |
docker |
Storage driver, dangling images, container health, proxy-docker-socket (see below) |
postgres |
pg_isready, longest running query, dead tuples, last vacuum |
hasura |
/healthz endpoint, metadata consistency |
nginx |
Config syntax test, served certificate expiry per domain (a TLS handshake against the served nginx, not a file probe inside the container) |
ssl |
Certbot timer active, last renewal age |
ping |
ping.nself.org reachable |
plugins |
Plugin container health endpoints |
license |
License cache present and not in grace period |
monitoring |
Prometheus, Grafana, Loki reachable |
backups |
Last backup age (must be under 26 hours) |
security |
JWT secret, container user, secret file permissions, exposed ports, weak SSL ciphers, SEC-GITIGNORE-01 certificate keys and .env.secrets kept out of git (see below) |
ai-safety |
AI plugin moderation wire-up gap (see below) |
performance |
PERF-POOL-01: pgxpool connection cap vs postgres_max_connections |
security |
PERM-RLS-01: RLS enforcement for np_* tables (see below) |
Fires during nself doctor --deep in the docker section. No generated stack mounts the Docker socket into a proxy or plugin container, because the socket is root-equivalent on the host. The check inspects the live containers of the project (running, restarting and paused ones) and fails when a proxy (nginx, traefik) or a plugin container holds the socket: a bind of docker.sock or of a directory that holds it (/var/run, /run, /, and the /private alias on macOS), including a bind source that is a symlink to one of those, a named volume that Compose declares as backed by the socket or such a directory, or a DOCKER_HOST that points at a unix socket.
A plugin container is every service that neither the generated core stack nor the service catalog declares. A name that only docker-compose.override.yml mentions does not count as core, so a plugin whose fragment was disabled or deleted is still checked, and a label such as nself.plugin never earns an exception. The core admin service and your own CS_N custom services are not judged. Other daemon sockets (podman) and Docker data directories are not part of this check.
| Result | Meaning |
|---|---|
pass |
No proxy or plugin container holds the socket |
warn |
Only plugins in the build guard's exception table hold it; the message names the plugin, the nself version where the exception ends (v1.5.0 for forgejo and monitoring) and the ticket that removes it |
fail |
A proxy, or a plugin without a live exception, holds it; the message names the plugin, service and container. A proxy never gets an exception, and neither does a service that two plugins declare |
unknown |
Docker could not be inspected, a container field was missing (a mount without a source, destination or type), or the container's inspect output has an empty environment or mount list: the docker package returns empty values for omitted fields, so empty cannot prove absence and a judged container is unknown unless it lists both a non-empty environment and non-empty mounts. Bind sources this host cannot verify and every volume mount are unknown too: the docker package cannot show a volume's live backing, so a Compose declaration or a name never proves it safe. Unproven evidence outranks an exception (unknown, not warn), and a known exposure outranks both (fail). Never reported as pass |
skip |
The project has no docker-compose.yml
|
nself build enforces the same rule before it writes anything. It reads the generated stack, every enabled plugin fragment and docker-compose.override.yml together, resolves YAML anchors and merge keys, and expands ${VAR} from the process environment, the project .env files and the computed plugin variables. A plugin fragment, override or stack that gives the socket to nginx, traefik or a plugin service stops the build with E130, naming the plugin and service. Relative bind paths resolve against the project directory, ~ is your home directory, and symlinks are followed before the check, so ../../var/run or a ./run link to /var/run is refused; a symlink that cannot be resolved is refused too. A named volume that is external and mounted by a proxy or plugin service is refused, because the build cannot show what backs it; an ordinary named data volume stays allowed, including one renamed with name: alone (the shipped forgejo fragment does this). A volume (renamed or not) whose device is the socket or a directory holding it is a confirmed socket exposure, like a direct bind. A service with a non-empty secrets or configs list is refused as well, because a secret or config file: can be the socket and the build does not follow them (no shipped plugin uses either; empty lists are safe), and use_api_socket set to anything but a false value (or a variable that cannot be resolved) is refused because the provider mounts the engine API socket itself. None of these can be waived by an exception, and an external volume stays unprovable even when it also names a socket device. An environment list entry is interpolated as a whole, key included (a map key is not), so ${KEY}=unix://… is judged by what KEY resolves to, and a key that cannot be resolved stops the build. DOCKER_HOST is judged by its effective value: a DOCKER_HOST entry without a value (or DOCKER_HOST: with null) forwards the environment's value, so a unix socket there is refused, and an unset or tcp:// value is accepted. ${VAR} resolves the way Compose does, from the process environment, then the .nself/compose.env this build is about to write, then the project .env. The guard runs the real compose.env writer in memory (the same plugin variables, secrets, DATABASE_URL, DOCKER_NETWORK, Hasura flags and URL-encoded twins) and uses its output, so a stale .env field never stands in for what the build writes; the previous .nself/compose.env on disk is never read, and no secret is printed or sent anywhere. A .env value that itself contains $ is trusted only when every variable it names, and every variable those names depend on in turn, is defined earlier in the same file, is defined nowhere else (no other env file, no computed value), and the process environment does not hold a different value for it (the parser expands each file alone, so anything else may not match what Compose resolves); otherwise it counts as unresolved and the build stops with E130 where the value feeds a socket mount, device or DOCKER_HOST. Doctor judges the live containers instead of predicting their environment. Long-syntax type: bind sources and volume device paths resolve against the project directory even without a leading ./. An env_file is inspected for its effective DOCKER_HOST; explicit environment values take precedence. A missing env file cannot start a container and introduces no socket exposure; present malformed or unreadable files are refused. A variable that cannot be resolved, extends, volumes_from, include and a malformed volumes or environment block also stop the build, because the build cannot show they are safe. An exception waives only a confirmed socket exposure on the excepted plugin's own service; an unresolved value or backing, an external volume, extends, volumes_from, secrets, configs or use_api_socket is refused even for forgejo and monitoring, and a proxy never gets an exception. Build and doctor use matching exception policies, checked by parity tests, so a plugin that builds with one warning shows warn here, and both turn into a refusal at the version the exception ends. Fix: remove the socket volume and the unix DOCKER_HOST from the plugin's docker-compose.plugin.yml, or remove the plugin, then run nself build. Read-only planning defers malformed override YAML to the container-impact check, which reports unknown; a write-mode build still refuses it with E130. Valid socket exposures are refused in both modes.
Fires during nself doctor --deep in the ai-safety section.
What it checks: If the ai plugin is loaded AND the deployment binds on a non-loopback address (e.g., 0.0.0.0) AND the moderation plugin is NOT loaded, emit a WARN.
Self-hosted single-user deployments on loopback are explicitly exempted, this is a legitimate use case.
| Status | Meaning |
|---|---|
pass |
ai not loaded, or deployment is loopback-bound, or moderation is wired |
warn |
ai loaded on public-bound deployment without moderation , consider installing the moderation plugin |
Fix:
nself plugin install moderation
nself build && nself startThe check reads NSELF_AI_LOADED, PLUGIN_AI_INTERNAL_URL, NSELF_MODERATION_LOADED, PLUGIN_MODERATION_INTERNAL_URL, and NSELF_BIND_ADDRESS from the environment.
Detection fixture:
set -a && source test/fixtures/ai-public-no-mod.env && set +a
nself doctor --deep
# Emits: "moderation not wired on public-bound deployment with ai loaded"Fires during nself doctor --deep in the performance section.
What it checks: Total configured pgxpool MaxConns across all active services must not exceed POSTGRES_MAX_CONNECTIONS. Default Postgres ships with max_connections=100. With 23 enabled services at the default cap of 10 connections each, total = 230, exceeding the limit causes random 503 errors under load.
Recommended cap formula: min(10, floor(postgres_max_connections / num_active_services))
| Status | Meaning |
|---|---|
pass |
Total pool capacity ≤ postgres_max_connections |
warn |
Total pool capacity > postgres_max_connections , reduce per-service pool or raise POSTGRES_MAX_CONNECTIONS
|
Fix: Raise POSTGRES_MAX_CONNECTIONS in .env or reduce per-plugin pool size. The check emits a FixCmd suggestion with the exact value to set.
# Skip the pool sizing check (not recommended in production)
nself doctor --deep --skip-poolFires during nself doctor --deep in the security section.
What it checks:
- For every
np_*table:pg_class.relrowsecurity = true(RLS enabled) and at least one policy exists. - For every
np_*table with atenant_idcolumn:pg_class.relforcerowsecurity = true(FORCE RLS, prevents table owner from bypassing policies). - For every
np_*table with atenant_idcolumn: Hasura metadata has aselectpermission for theuserrole with atenant_idrow filter ({"tenant_id": {"_eq": "X-Hasura-Tenant-Id"}}).
Security-Always-Free Doctrine: this check runs without a license key.
| Status | Meaning |
|---|---|
pass |
All np_* tables have RLS enabled, at least one policy, and Hasura tenant_id filters where applicable |
warn |
Violation found (default); use --strict to escalate to fail
|
fail |
Violation found with --strict flag |
Violation output format:
RLS-DISABLED table=np_chat_messages
RLS-FORCE-MISSING table=np_claw_cost_events role=user
HASURA-FILTER-MISSING table=np_claw_cost_events role=user
Env vars read:
-
NSELF_DB_URLorDATABASE_URL, Postgres connection string -
HASURA_GRAPHQL_URL, Hasura endpoint (default:http://127.0.0.1:8080) -
HASURA_GRAPHQL_ADMIN_SECRET, required for Hasura metadata query; if absent, Hasura filter check is skipped with a warning
Fix:
# Fix missing FORCE RLS on a table — enables RLS and applies FORCE ROW LEVEL
# SECURITY plus the four standard Hasura-compatible policies
nself db rls apply-table public np_chat_messages
# Re-run the check after fixing
nself doctor --deep --only securitySee also: multi-tenant conventions for the canonical wall doc on source_account_id vs tenant_id.
Fires during nself doctor --deep in the security section.
nself init writes /ssl/ and .env.secrets into the .gitignore of a new project only. A project created before that, or one whose .gitignore was edited, can still commit ssl/certificates/<domain>/privkey.pem. The check asks git itself, so nested .gitignore files, ! negations and your global excludes count the way git counts them:
-
git check-ignore --no-indexonssl/privkey.pem,ssl/certificates/x/privkey.pemand.env.secrets: each must be ignored. -
git ls-files -- ssl/ .env.secrets: must list nothing.
It reads only; it never edits .gitignore or the index. Outside a git work tree, or without git installed, it passes as skipped.
| Status | Meaning |
|---|---|
pass |
All three paths are ignored and nothing under ssl/ or .env.secrets is tracked |
warn |
A path is not ignored, or a key or secret file is already tracked |
Fix:
# 1. Ignore the paths (a leading / keeps src/ssl/ trackable)
printf '/ssl/\n.env.secrets\n' >> .gitignore
# 2. If the check listed tracked files, untrack them (the files stay on disk)
git rm --cached -r --ignore-unmatch -- ssl/ .env.secrets
git commit -m "chore: stop tracking certificate keys and secrets"A key or secret that was committed stays in git history, and anyone with a clone has it. Rotate it: replace the certificate with one issued on a new private key, and replace every secret that was in the committed file.
Fires during nself doctor (standard and deep) in the Configuration section.
What it checks: If POSTGRES_USER equals the default value postgres and NSELF_ENV is prod or staging, the check emits a WARN. The default is appropriate for dev; in production it is a predictable attack surface.
This does not change the default or block deployment — it is an advisory warning only.
| Status | Meaning |
|---|---|
pass |
POSTGRES_USER is not the default postgres, or environment is dev
|
warn |
POSTGRES_USER=postgres in prod or staging — set a unique username |
Fix: Set POSTGRES_USER=<unique-name> in your .env before nself build:
# .env
POSTGRES_USER=myprod_db_userThen rebuild: nself build && nself start.
nself doctor --install-check runs a focused readiness check that maps to the 6-stage onboarding funnel. It is invoked automatically by the Homebrew post_install hook after brew install nself. You can also run it manually at any time.
$ nself doctor --install-check
Onboarding Funnel Check
Stage 1 — Install v1.1.1 (darwin/arm64)
Stage 2 — Activation 2 projects initialized
Stage 3 — First-use first start 3 days ago
Stage 4 — First-plugin no plugins installed
→ Run: nself plugin install ai (or any plugin)
Stage 5 — First-value (skipped, prior stage failed)
Stage 6 — Habit (skipped, prior stage failed)
Funnel position: Stage 3/6. Next: nself plugin install ai (or any plugin)
Each stage prints PASS, FAIL, UNKNOWN, or SKIPPED:
| Status | Meaning |
|---|---|
| PASS | Stage completed |
| FAIL | Not yet reached , remediation hint shown |
| UNKNOWN | Cannot determine (e.g. Stage 5 when Hasura telemetry hook is not wired) |
| SKIPPED | A prior stage failed; this stage was not evaluated |
Stage 5 shows UNKNOWN (not FAIL) when the query-count file is absent. This avoids penalising self-hosters who have not wired the optional Hasura telemetry hook.
Pass --json for machine-readable output:
nself doctor --install-check --jsonExit codes: 0 = all 6 stages pass; 1 = one or more stages fail.
nself doctor --check-legacy scans the host machine for stale v0.9 global paths that persist after migration:
| Path scanned | What it indicates |
|---|---|
~/.nself/ |
v0.9 global config directory |
~/.nself/plugins/ |
v0.9 plugin install directory |
~/.config/nself |
v0.9 XDG config file (v1 uses a directory) |
/usr/local/share/nself |
v0.9 shared data directory |
For each path found, the output shows the path, its type, and a cleanup hint. The check is read-only: it never deletes anything automatically.
$ nself doctor --check-legacy
WARNING: Found 2 v0.9 stale artifact(s) on this host:
[dir] /Users/me/.nself — safe to remove: rm -rf ~/.nself (after verifying no custom config)
[file] /usr/local/share/nself — safe to remove: sudo rm -f /usr/local/share/nself
Run the cleanup commands above, then re-run `nself doctor --check-legacy` to confirm.
If no stale paths are found, the command exits 0 with No v0.9 global artifacts detected. Clean install.
This flag exits early without running any other doctor checks. Combine with other checks by running them separately.
When --json is passed, the command writes a single JSON object to stdout and produces no other output. The JSON schema is:
{
"timestamp": "2026-04-17T12:00:00Z",
"checks": [
{
"name": "[security] Exposed port 5432 (Postgres)",
"status": "critical",
"message": "Postgres port 5432 is bound on 0.0.0.0 — bind to 127.0.0.1",
"detail": "docker stop nself_postgres && nself build && nself start"
}
],
"summary": {
"total": 42,
"passed": 39,
"warnings": 1,
"failed": 1,
"critical": 1
}
}Status values: pass, warn, fail, critical.
With NSELF_V15=1 (the default from v1.5.0), doctor --json and doctor --format json write the v1 envelope instead of the bare report (see JSON-Output). data is the report above plus state, and passed-check lines go to stderr so stdout stays one document:
{ "schema_version": "1", "command": "doctor", "data": { "timestamp": "...", "checks": [], "summary": {}, "state": "warnings" } }data.state |
Meaning | Exit status (v1.5 mode) |
|---|---|---|
ok |
every check passed | 0 |
warnings |
warnings only, no failures | 12 |
unhealthy |
at least one check failed | 10 |
In v1.4 mode --json prints the bare report and exits 0, and human mode exits 1 (failures) or 2 (warnings only). NSELF_V15=1 NSELF_JSON_LEGACY=1 prints the bare report without state for one more minor release (removed in v1.6.0). --install-check and --ai keep their own JSON shapes. The schema is schemas/commands/doctor.v1.schema.json. See Exit-Codes.
| Name | Shorthand | Type | Default | Env | Escalates to | JSON override | Description |
|---|---|---|---|---|---|---|---|
--ai |
bool |
false |
write |
legacy |
Run the AI first-run wizard (install Ollama, setup Gemini pool, verify) | ||
--alerts |
bool |
false |
Check monitoring alert rules are loaded | ||||
--check-legacy |
bool |
false |
Scan host for v0.9 stale paths (global scan, not per-project) | ||||
--deep |
bool |
false |
Alias for --full (run all checks) | ||||
--fix |
bool |
false |
write |
Auto-fix safe issues | |||
--force |
bool |
false |
With --fix, overwrite hand-edited generated files | ||||
--format |
string |
"" |
Output format: json, text (default text) | ||||
--full |
bool |
false |
Run all checks including network and memory (slower) | ||||
--headless |
bool |
false |
Print OAuth URL instead of opening browser (for SSH/headless servers) | ||||
--install-check |
bool |
false |
legacy |
Run 6-stage onboarding funnel check (used by Homebrew post-install hook) | |||
--json |
bool |
false |
JSON output | ||||
--only |
string |
"" |
Run only a specific subsystem check (host, docker, postgres, hasura, nginx, ssl, ping, plugins, license, monitoring, backups, security) | ||||
--plan |
bool |
false |
With --fix, show generated-file repair plan without writing | ||||
--quick |
bool |
false |
Fast check: infrastructure, disk, ports, config, plugins, license, container health only (the default check set; explicit opt-in overrides --full/--deep) | ||||
--section |
string |
"" |
Run only a specific section (system, core, backups, license, plugins, monitoring, security) | ||||
--skip |
stringSlice |
[] |
Skip specific check sections | ||||
--skip-ollama |
bool |
false |
Skip local Ollama installation step | ||||
--skip-pool |
bool |
false |
Skip Gemini pool setup step | ||||
--verbose |
bool |
false |
Detailed diagnostics | ||||
--yes |
bool |
false |
Non-interactive mode: accept all defaults (for CI/scripts) | ||||
--help |
-h |
bool |
false |
Show help |
| Name | Description |
|---|---|
heal |
Run targeted self-healing routines for ɳSelf components |
images |
Check availability of every locked image |
report |
Write a redacted support bundle (tar.gz) to share in an issue |
security |
Diagnose server security |
-
Side effect:
read -
Output:
document -
JSON:
envelope(data schema) -
Exit codes:
10:one or more checks failed,12:warnings only, no failures
# Quick diagnostic
nself doctor
# Full diagnostic (includes network and memory checks)
nself doctor --full
# Full hardening scan across all 12 subsystems
nself doctor --deep
# Deep scan, one subsystem only
nself doctor --deep --only security
# Verbose output with details per check
nself doctor --verbose
# JSON output for automated monitoring
nself doctor --json
# Auto-fix safe issues
nself doctor --fix
# Deep scan with JSON output, useful for CI security gates
nself doctor --deep --json
# First-run AI wizard (installs Ollama, sets up Gemini pool)
nself doctor --ai
# First-run AI wizard, non-interactive
nself doctor --ai --yes- Commands — full command index
- Core-Services — what a stack is made of
Getting Started
Commands
- Commands, Overview
- Lifecycle: cmd-init · cmd-build · cmd-start · cmd-stop · cmd-restart · cmd-dev
- Monitoring: cmd-status · cmd-logs · cmd-health · cmd-urls · cmd-doctor · cmd-monitor · cmd-alerts · cmd-sentry · cmd-watchdog
- Data: cmd-db · cmd-backup · cmd-dr · cmd-queue · cmd-webhooks
- Config: cmd-config · cmd-service · cmd-env · cmd-promote
- Networking: cmd-ssl · cmd-trust · cmd-dns-setup
- Security: cmd-access · cmd-security · cmd-secrets
- Tenancy: cmd-tenant · cmd-billing
- Plugins: cmd-plugin · cmd-license · cmd-dogfood (extracted, CLI-R11) · cmd-k8s (extracted, CLI-R11) · cmd-encryption (extracted, CLI-R11) · cmd-waf (extracted, CLI-R11) · cmd-federation (extracted, CLI-R11) · cmd-mail (extracted, CLI-R11) · cmd-dlq (extracted, CLI-R11)
- AI: cmd-ai · cmd-claw · cmd-model
- Templates: cmd-template
- Utilities: cmd-exec · cmd-clean · cmd-reset · cmd-update · cmd-upgrade · cmd-version · cmd-admin · cmd-migrate · cmd-migrate-firebase · cmd-migrate-supabase · cmd-completion
Features
- Features, Overview
- Feature-Auth
- Feature-Storage
- Feature-Search
- Feature-Functions
- Feature-Email
- Feature-Monitoring
- Feature-Plugins
- Feature-nClaw, AI Assistant
- Feature-nChat, Messaging
- Feature-nFamily, Family Social
- Feature-nCloud, Managed Hosting
- Feature-Memory-Rooms, Knowledge Organization
- Feature-Agent-Dashboard, Agent Metrics
- Feature-Image-Generation, AI Image Generation
Configuration
- Configuration, Overview
- Config-Env-Vars
- Config-Postgres
- Config-Hasura
- Config-Auth
- Config-Nginx
- Shared-Proxy
- Config-Optional-Services
- Config-Custom-Services
- Config-System
Plugins (87 + 10 monitoring)
- Plugin-Overview
- Plugin-Catalog
- Plugin-Install
- Plugin-Licensing
- Plugin-Architecture
- Plugin-Dev-Guide
- Plugin-Migrations-Contract
Free (25)
- plugin-backup
- plugin-content-acquisition
- plugin-content-progress
- plugin-cron
- plugin-donorbox
- plugin-feature-flags
- plugin-github
- plugin-github-runner
- plugin-invitations
- plugin-jobs
- plugin-link-preview
- plugin-mdns
- plugin-mlflow
- plugin-monitoring
- plugin-notifications
- plugin-notify
- plugin-paypal
- plugin-search
- plugin-shopify
- plugin-stripe
- plugin-subtitle-manager
- plugin-tokens
- plugin-torrent-manager
- plugin-vpn
- plugin-webhooks
Pro (62)
- plugin-access-controls
- plugin-activity-feed
- plugin-admin-api
- plugin-analytics
- plugin-auth
- plugin-bots
- plugin-browser
- plugin-calendar
- plugin-cdn
- plugin-chat
- plugin-claw
- plugin-claw-budget
- plugin-claw-news
- plugin-claw-web
- plugin-cloudflare
- plugin-cms
- plugin-compliance
- plugin-ddns
- plugin-devices
- plugin-documents
- plugin-entitlements
- plugin-file-processing
- plugin-game-metadata
- plugin-geocoding
- plugin-geolocation
- plugin-google
- plugin-home
- plugin-idme
- plugin-knowledge-base
- plugin-linkedin
- plugin-livekit
- plugin-media-processing
- plugin-meetings
- plugin-moderation
- plugin-mux
- plugin-object-storage
- plugin-observability
- plugin-photos
- plugin-podcast
- plugin-post
- plugin-realtime
- plugin-retro-gaming
- plugin-rom-discovery
- plugin-social
- plugin-sports
- plugin-support
- plugin-tmdb
- plugin-voice
- plugin-web3
- plugin-workflows
Planned (26)
plugin-auditplugin-blogplugin-checkoutplugin-commerceplugin-drmplugin-exportplugin-flowplugin-importplugin-ldapplugin-mailgunplugin-mediaplugin-oauth-providersplugin-pagesplugin-postmarkplugin-rate-limitplugin-reportsplugin-samlplugin-schedulerplugin-sendgridplugin-ssoplugin-subscriptionplugin-thumbplugin-transcoderplugin-twilioplugin-wafplugin-watermark
Guides
- Guide-Production-Deployment
- Guide-SSL-Setup
- Guide-Multi-Tenancy
- Guide-Security-Hardening
- Guide-Monitoring-Setup
- Guide-Backup-Restore
- Guide-Custom-Services
- Guide-Migration-from-v1
Architecture
- Architecture
- Architecture-Guardrails
- Service-Graph
- Compose-Generation
- Nginx-Generation
- Plugin-Architecture
Reference
Machine interface
-
JSON-Output,
--jsonenvelope -
Command-Registry,
nself help --json - Exit-Codes
- error-codes, Error Codes
-
Compat-V15,
NSELF_V15gate
Licensing
Security
Brand
Operations
- operations/release-cascade, Release Cascade
- operations/self-healing, Self-Healing Schema
- operations/redis-tuning, Redis Pool Tuning
- operations/meilisearch-warmup, MeiliSearch Warm-Up
- operations/jwt-rotation, JWT Key Rotation
- operations/windows-wsl2-setup, Windows / WSL2 Setup
- operations/gemini-oauth-reauth, Gemini OAuth Reauth
Contributing
Admin
- USER-ACTION-QUEUE, Pending Admin Actions
All commands (21)
- A: cmd-add · cmd-admin
- B: cmd-backup · cmd-build
- C: cmd-clean · cmd-config
- D: cmd-db · cmd-deploy · cmd-doctor
- E: cmd-exec
- I: cmd-init
- L: cmd-license · cmd-logs
- M: cmd-mcp
- R: cmd-remove · cmd-reset · cmd-restart
- S: cmd-start · cmd-status · cmd-stop
- U: cmd-update