Warm Runtime (Daemon)

Keep provider clients and MCP connections warm across praisonai run calls

python
from praisonaiagents import Agent

agent = Agent(name="daemon-agent", instructions="Run as a background daemon process.")
agent.start("Start the agent daemon and listen for incoming tasks.")

praisonai daemon keeps provider clients and MCP connections hot in memory so repeated praisonai run calls skip cold-start entirely.

The user runs repeated praisonai run commands; the warm daemon forwards work to hot provider and MCP connections.

Diagram

With Daemon (Warm Path)

Yes

No / Stale

praisonai run

Lockfile?

Forward via HTTP

Warm Agent

Result

In-Process Fallback

Without Daemon (Cold Start Every Time)

praisonai run

Init Provider

Init MCP

Agent.start

Result

Quick Start

  1. Start the daemon in the background
    bash
    praisonai daemon start --background
    ✓ Warm runtime started in background at http://127.0.0.1:54321 (pid 12345)

    The daemon writes a project-local lockfile and binds to a free loopback port. All subsequent praisonai run calls in the same project directory automatically detect and attach to it.

    Edited commands, agents, skills, tools, and rules files (including AGENTS.md / CLAUDE.md) are picked up on the next prompt. The daemon drops its warm agents and rebuilds them, and session history is rehydrated from the project session store. See Live edits during interactive sessions.

  2. Run prompts — no extra flags needed
    bash
    praisonai run "Write a haiku about clouds"
    praisonai run "Now make it rhyme"
    praisonai run "Translate to Spanish"

    Each call transparently attaches to the warm runtime. Provider and MCP clients are already initialised — only the prompt is forwarded.

  3. Check status and stop
    bash
    praisonai daemon status
    ✓ Warm runtime running at http://127.0.0.1:54321 (pid 12345).
    bash
    praisonai daemon stop
    ✓ Stopped warm runtime (pid 12345).

How It Works

Diagram
Warm AgentWarmRuntime (HTTP)Lockfilepraisonai runUserWarm AgentWarmRuntime (HTTP)Lockfilepraisonai runUseralt[session_id present][anonymous]If lockfile missing, stale pid, orruntime unreachable → in-process fallbackpraisonai run “prompt”Read runtime.json{host, port, token, pid}pid alive?POST /healthz (Bearer token){ok: true}POST /run {prompt, session_id?, event_id?}_get_session_agent(session_id, model)rehydrate once, retain history_get_agent(model)per-model stateless, cleared post-callagent.start(prompt)result{ok: true, result}prints result
ComponentRole
Lockfile (runtime.json)Stores {host, port, token, pid} at <project_data_dir>/runtime/runtime.json. Mode 0600 — token is never world-readable.
WarmRuntimeHolds two agent caches: (1) one stateless warm Agent per model for anonymous (no-session) calls — history cleared after each call; (2) one stateful warm Agent per session id for --continue/--session runs — history rehydrated once and retained across turns, persisted per-turn through the project session store. Both caches evict on turn failure to prevent state bleed.
RuntimeClientThin stdlib (urllib) HTTP client. Raises RuntimeUnavailable on any error — run then falls back in-process.
Idle watcherBackground thread shuts down the server after --idle-timeout seconds of inactivity (default 30 min).

Configuration Options

praisonai daemon start

FlagTypeDefaultDescription
--host, -hstr127.0.0.1Loopback host to bind. Non-loopback addresses are rejected.
--port, -pint0Port to bind. 0 = auto-select a free port.
--model, -mstrNoneDefault model for the warm agent.
--idle-timeoutfloat1800.0Seconds idle before auto-shutdown. 0 disables auto-shutdown.
--background, -bboolFalseDetach and run in the background.

praisonai daemon status

FlagTypeDefaultDescription
--jsonboolFalseOutput JSON for scripting. Returns {running, host, port, pid, base_url}.
bash
praisonai daemon status --json
json
{
  "running": true,
  "host": "127.0.0.1",
  "port": 54321,
  "pid": 12345,
  "base_url": "http://127.0.0.1:54321"
}

praisonai daemon stop

No flags. Sends SIGTERM after a health-check ping to guard against PID reuse. Cleans up the lockfile.


When to Use Foreground vs Background

Diagram

Everyday workflow

Debugging / watching logs

How will you use the daemon?

–background

Foreground default

Starts detached process

Returns immediately

Persists across terminal sessions

Logs visible in terminal

Ctrl-C to stop

Blocks the shell


When --continue / --session Attach Warm


When run Stays In-Process

praisonai run skips the daemon and runs locally whenever you pass any of these flags:

Flag(s)Why it stays in-process
--mcp, --tools, --toolsetPer-invocation tool overrides need in-process state.
--approval, --approve-all-toolsApproval flow requires interactive in-process handling.
--memoryMemory store is managed in-process.
--permissions overridesSecurity policy must be enforced locally.
--forkThe forked session id is minted in-process; subsequent turns against the forked id attach warm.
--thinking, --worktreeReasoning-effort and isolated git-worktree runs need in-process state.
--output actions, json, stream, stream-jsonStructured output modes need richer in-process event bridging.

In all these cases, praisonai run behaves exactly as it did before the daemon feature. No flags are needed to opt out — it happens automatically.


Common Patterns

Iterating on prompts in a shell loop
bash
praisonai daemon start --background

for topic in clouds mountains rivers; do
  praisonai run "Write a haiku about $topic"
done

praisonai daemon stop

Only the first call pays setup cost. The loop body is fast — just HTTP over loopback.

Auto-shutdown at night with –idle-timeout
bash
# Shut down after 1 hour of inactivity (3600 seconds)
praisonai daemon start --background --idle-timeout 3600

# Or disable auto-shutdown entirely (not recommended for long sessions)
praisonai daemon start --background --idle-timeout 0

The default is 1800 seconds (30 minutes). The daemon shuts itself down silently when the idle timer expires.

Scripting status checks
bash
STATUS=$(praisonai daemon status --json)
RUNNING=$(echo "$STATUS" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['running'])")

if [ "$RUNNING" = "True" ]; then
  echo "Daemon is up"
else
  praisonai daemon start --background
fi

The --json flag returns {running, host, port, pid, base_url} — safe for jq or any JSON parser.

Using a specific model
bash
praisonai daemon start --background --model gpt-4o

# All runs that don't specify --model will use gpt-4o from the warm agent
praisonai run "summarize this document"

Security


Best Practices

Use –background for everyday workflows

Foreground mode is useful for debugging (you can see log output). For all other use cases, --background is simpler: it returns immediately and the daemon persists across terminal sessions.

Tune –idle-timeout carefully

The default 30-minute timeout is a good balance between warmth and resource usage. Setting --idle-timeout 0 means the daemon never shuts down automatically — only use this if you understand it will consume memory indefinitely.

One daemon per project

The lockfile is stored under the project data directory, scoped to the current project. Running two daemons in the same project will print a warning and exit. Each project directory gets its own independent daemon.

Check status before starting
bash
praisonai daemon status
# → No warm runtime is running.

praisonai daemon start --background

Starting a daemon when one is already running prints a warning and exits cleanly — there is no risk of running two daemons accidentally.


Related