Skip to content

Daemon and Serve Commands

William Smith edited this page Jul 13, 2026 · 1 revision

Daemon and Serve Commands

Relevant source files

The following files were used as context for generating this wiki page:

The AXIS daemon is a long-lived process that maintains a cached view of the cluster state (the ClusterSnapshot), manages a double-entry resource reservation ledger, and exposes a unified HTTP API for cluster operations. This page covers the lifecycle management of the daemon via the axis daemon and axis serve commands.

Overview of Serve and Daemon

AXIS operates in two primary modes: a stateless CLI mode that discovers the cluster on every command, and a daemonized mode that provides low-latency access to cluster state and coordinated resource management.

  • axis serve: The primary entry point to start the AXIS API and background refresh loops.
  • axis daemon: A management utility for interacting with an already-running daemon (status, manual refresh, restart).
  • HTTP API: A REST-like interface exposed via a Unix Domain Socket (default) or TCP, allowing both internal AXIS components and external tools to query the cluster.

Component Relationship

The following diagram illustrates how the axis serve command initializes the core daemon entities and how they relate to the underlying code.

Daemon Initialization and Entity Mapping

graph TD
    subgraph "Natural Language Space"
        Start["Start AXIS Daemon"]
        Cache["Snapshot Cache"]
        MeshNet["Gossip Mesh"]
        API["HTTP API"]
    end

    subgraph "Code Entity Space"
        Start --> runServeCommand["runServeCommand() [cmd/axis/serve.go]"]
        runServeCommand --> NewDefault["daemon.NewDefault() [internal/daemon/daemon.go]"]
        runServeCommand --> ServeWithContext["api.ServeWithContext() [internal/api/api.go]"]
        
        NewDefault --> SnapshotCache["SnapshotCache (Interface) [internal/daemon/daemon.go]"]
        NewDefault --> Mesh["mesh.Mesh [internal/mesh/mesh.go]"]
        
        SnapshotCache --> RefreshNow["RefreshNow() [internal/daemon/daemon.go]"]
        SnapshotCache --> Invalidate["Invalidate() [internal/daemon/daemon.go]"]
    end
Loading

Sources: cmd/axis/serve.go:48-91, internal/daemon/handlers.go:49-78


The axis serve Command

The axis serve command is the main process that hosts the AXIS environment. It performs the following tasks:

  1. Token Generation: Generates or loads an API token for authenticating requests cmd/axis/serve.go:52-55.
  2. Daemon Orchestration: Initializes the SnapshotCache and starts background refresh loops cmd/axis/serve.go:57-58.
  3. Watchers: Sets up filesystem watchers for nodes.yaml, state.json, and skills.json to trigger immediate cache refreshes when configuration or state changes cmd/axis/serve.go:59-62.
  4. Mesh Networking: If enabled, starts the gossip-based peer discovery cmd/axis/serve.go:65-73.

API Listening

By default, the daemon listens on a Unix Domain Socket at ~/.axis/axis.sock. This can be overridden to a TCP address using the --addr flag cmd/axis/serve.go:106-106.

Flag Default Description
--addr api.DefaultAddr() Listen address (Unix socket or host:port)
--refresh 1m Interval for background cluster discovery cmd/axis/serve.go:107-107
--pprof false Enable Go profiling endpoints at /debug/pprof cmd/axis/serve.go:108-108

Sources: cmd/axis/serve.go:93-110, internal/api/api.go:1-50


The axis daemon Command Surface

The daemon subcommand group provides administrative control over the running axis serve process.

axis daemon status

Queries the daemon's metadata to report health, version, and cache staleness cmd/axis/daemon.go:36-63. It fetches data from the /snapshot/meta endpoint cmd/axis/daemon.go:43-43.

axis daemon refresh

Forces an immediate re-discovery of all nodes in the cluster. This is useful if a node was just powered on and you do not want to wait for the next background interval cmd/axis/daemon.go:98-110.

axis daemon invalidate

Clears the current ClusterSnapshot from memory, forcing the next request to wait for a fresh discovery cmd/axis/daemon.go:83-95.

axis daemon restart

Performs a graceful restart of the daemon by sending a signal to the running process to re-exec itself with the current binary cmd/axis/daemon.go:111-119.

Sources: cmd/axis/daemon.go:27-122, internal/daemon/handlers.go:189-216


HTTP API and Socket

The daemon exposes a structured API used by the CLI and AI agents.

Key Endpoints

Endpoint Method Description
/snapshot GET Returns the full ClusterSnapshot JSON internal/daemon/handlers.go:170-187.
/snapshot/meta GET Returns metadata about the cache (age, last refresh trigger) internal/daemon/handlers.go:189-201.
/run POST Executes a guarded task on the cluster internal/daemon/handlers.go:76-76.
/knowledge GET Aggregates snapshot, skills, and failure records for AI context internal/daemon/handlers.go:75-75.
/mesh GET Returns the list of peers discovered via gossip internal/daemon/handlers.go:77-77.

Request Flow: CLI to Daemon

This diagram shows the path of a request from a CLI command (like axis status) through the daemon's API handlers.

sequenceDiagram
    participant CLI as "axis CLI [cmd/axis/daemon.go]"
    participant Auth as "Auth [internal/auth/auth.go]"
    participant Mux as "HTTP Mux [internal/daemon/handlers.go]"
    participant Cache as "SnapshotCache [internal/daemon/daemon.go]"

    CLI->>Auth: LoadOrGenerateToken()
    CLI->>Mux: GET /snapshot (with Bearer Token)
    Mux->>Mux: Authorize(token)
    Mux->>Cache: Snapshot()
    Cache-->>Mux: *models.ClusterSnapshot
    Mux-->>CLI: 200 OK (JSON)
Loading

Sources: cmd/axis/daemon.go:143-163, internal/daemon/handlers.go:170-187, internal/auth/auth.go:1-30


Daemon Refresh Triggers

The daemon cache is not just updated on a timer; it responds to various "triggers" to ensure the cluster view remains accurate.

Trigger Origin Description
timer Internal Periodic background refresh based on --refresh flag.
config-change FS Watcher Triggered when nodes.yaml is modified cmd/axis/serve.go:59-59.
state-change FS Watcher Triggered when state.json is modified (e.g., manual task updates) cmd/axis/serve.go:60-60.
execution-finished CLI/API Triggered after a task finishes to reclaim resources immediately internal/execution/run.go:1-50.
manual CLI Triggered via axis daemon refresh cmd/axis/daemon.go:98-110.

Best-Effort Refresh Signaling

CLI commands often signal the daemon to refresh using scheduleBestEffortDaemonRefresh. This function runs in a background goroutine and suppresses errors if the daemon socket is missing, ensuring that CLI operations aren't slowed down by daemon unavailability cmd/axis/daemon_refresh_support.go:18-29.

Sources: cmd/axis/daemon_refresh_support.go:1-46, cmd/axis/serve.go:57-63


System Integration (systemd / launchd)

While AXIS is a single binary, it is designed to run as a persistent service.

systemd (Linux)

To run the AXIS daemon on Linux, create a service file at ~/.config/systemd/user/axis.service:

[Unit]
Description=AXIS Cluster Daemon

[Service]
ExecStart=%h/bin/axis serve --addr unix://%h/.axis/axis.sock
Restart=always

[Install]
WantedBy=default.target

launchd (macOS)

On macOS, use a Property List file in ~/Library/LaunchAgents/com.axis.daemon.plist:

<dict>
    <key>Label</key>
    <string>com.axis.daemon</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/axis</string>
        <string>serve</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>

Sources: cmd/axis/serve.go:76-79, internal/api/api.go:20-40


Clone this wiki locally