-
Notifications
You must be signed in to change notification settings - Fork 0
Daemon and Serve Commands
Relevant source files
The following files were used as context for generating this wiki page:
- cmd/axis/daemon.go
- cmd/axis/daemon_refresh_support.go
- cmd/axis/daemon_refresh_support_test.go
- cmd/axis/daemon_test.go
- cmd/axis/serve.go
- internal/daemon/handlers.go
- internal/daemon/handlers_test.go
- internal/discovery/discovery_test.go
- internal/discovery/udp.go
- internal/mesh/mesh.go
- internal/runtimectx/context.go
- internal/runtimectx/context_test.go
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.
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.
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
Sources: cmd/axis/serve.go:48-91, internal/daemon/handlers.go:49-78
The axis serve command is the main process that hosts the AXIS environment. It performs the following tasks:
- Token Generation: Generates or loads an API token for authenticating requests cmd/axis/serve.go:52-55.
-
Daemon Orchestration: Initializes the
SnapshotCacheand starts background refresh loops cmd/axis/serve.go:57-58. -
Watchers: Sets up filesystem watchers for
nodes.yaml,state.json, andskills.jsonto trigger immediate cache refreshes when configuration or state changes cmd/axis/serve.go:59-62. - Mesh Networking: If enabled, starts the gossip-based peer discovery cmd/axis/serve.go:65-73.
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 daemon subcommand group provides administrative control over the running axis serve process.
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.
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.
-
Implementation: Sends a POST request to
/refreshcmd/axis/daemon.go:247-259.
Clears the current ClusterSnapshot from memory, forcing the next request to wait for a fresh discovery cmd/axis/daemon.go:83-95.
-
Implementation: Sends a POST request to
/invalidatecmd/axis/daemon.go:241-245.
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
The daemon exposes a structured API used by the CLI and AI agents.
| 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. |
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)
Sources: cmd/axis/daemon.go:143-163, internal/daemon/handlers.go:170-187, internal/auth/auth.go:1-30
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. |
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
While AXIS is a single binary, it is designed to run as a persistent service.
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.targetOn 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