Operating locally
Asterel is designed to be operated by one person, or a small trusted team, on a machine they control. The local daemon is the center of that deployment. It combines the gateway, channels, scheduler, heartbeat, and companion turn runtime.
cargo run -- daemon --host 127.0.0.1 --port 3000Use agent for a quick direct conversation loop. Use daemon when you are exercising the product shape: Discord text, gateway routes, background tasks, and operator surfaces all around the same runtime.
If you are setting up for the first time, read Getting started before this page. If Discord is the next step, use Run Discord after the daemon passes health checks.
First checks
Section titled “First checks”After onboarding, these commands are the fastest way to separate configuration problems from runtime problems:
cargo run -- config validatecargo run -- doctorcargo run -- statuscargo run -- channel listUse doctor --repair only for safe local repairs. If the issue is an external service, credential, or database, fix that dependency rather than treating the runtime as broken.
Cron and scheduler operations that persist durable job state require PostgreSQL
configuration through ASTEREL_POSTGRES_URL or memory.postgres_url. Without
that state, read-only cron status can report unavailable/degraded instead of
pretending scheduled jobs are active.
Local gateway model
Section titled “Local gateway model”The gateway defaults to 127.0.0.1:3000. That is intentional. Admin routes are not public routes, and /admin/v1/* requires pairing plus tenant scope:
Authorization: Bearer <token>X-Asterel-Tenant: <tenant-id>Pairing gives a client permission to talk to the daemon. Tenant scope tells admin routes which operator workspace context they are acting on. This is not a SaaS tenant boundary; it is local operator scoping.
Discord operation
Section titled “Discord operation”Discord text is the primary product surface. The operational path is:
Discord event -> channel adapter -> pickup / ingress policy -> shared companion turn -> reply delivery -> post-turn memory and relationship updateIf a Discord message does not produce a reply, check the decision points in that order:
- The Discord bot token and guild/application restrictions are correct.
- The channel is enabled and not disabled by operator state.
- The message passes the pickup policy.
- The user is allowed if
allowed_usersis configured. - The provider can complete the turn.
- The pre-send verifier allows the response.
Do not loosen pickup or allowlists just to get visible activity. A companion that speaks too eagerly in a public room breaks the product promise.
Desktop operation
Section titled “Desktop operation”The desktop app is a secondary operator console. Run it against a daemon:
cargo run -- daemon --host 127.0.0.1 --port 3000pnpm --dir desktop tauri devUse desktop for governance, diagnostics, session review, memory review/correction/forget, exposure diagnostics, channel health, and companion admin workflows. It is not the primary user-facing companion surface, and it should not become the owner of runtime state. See Desktop console for the operator model.
Memory review loop
Section titled “Memory review loop”When behavior feels wrong, avoid jumping straight to prompt edits. First ask whether the runtime remembered the wrong thing, recalled it in the wrong context, or exposed it on the wrong surface. The operator loop is:
inspect compact memory -> check provenance -> correct / forget / approve -> verify the next turn uses the updated projectionSee Memory review for the public-safe model.
Useful local gates
Section titled “Useful local gates”For code changes, the local Rust gate is:
cargo fmt -- --checkcargo clippy -- -D warningscargo check-allcargo testFor docs changes:
pnpm --dir docs buildFor desktop changes:
pnpm --dir desktop exec oxfmtpnpm --dir desktop exec oxlint --react-plugin srcpnpm --dir desktop buildUse the smaller focused gate that matches the change first. Run the full gate before release-quality handoff.
What healthy operation looks like
Section titled “What healthy operation looks like”A healthy local deployment has these properties:
- The daemon starts without falling back to a surprise config.
- The provider, memory backend, gateway, and primary channel are all explicit.
- Discord messages become turns only when pickup policy accepts them.
- Every accepted turn passes through enrichment, pre-send verification, and post-turn update.
- Memory consolidation and hygiene can run without blocking the live turn path.
- Admin access requires pairing and tenant scope.
- Desktop reads runtime/admin state; it does not fork a second runtime truth.