commit c1a3292875464f6d6aa2379763bbf57422657137
Author: Coder Agent <coder@agents.omni>
Date: Wed Apr 15 22:04:47 2026
feat(agentd): remove daemon command and deployment path
Drop the daemon subcommand from agentd.
Make deploy-agentd.sh a no-op with CLI guidance.
Task-Id: t-801
diff --git a/Omni/Agentd.hs b/Omni/Agentd.hs
index 416251d7..53992bc4 100755
--- a/Omni/Agentd.hs
+++ b/Omni/Agentd.hs
@@ -172,12 +172,6 @@ data Command
cleanupDryRun :: Bool
}
| Agent AgentCommand
- | Daemon
- { daemonPort :: Int,
- daemonDbPath :: Maybe FilePath,
- daemonLogRoot :: Maybe FilePath,
- daemonWorkspace :: Maybe FilePath
- }
| Notifyd
| Test
deriving (Show)
@@ -658,42 +652,6 @@ cleanupParser =
<> Opt.help "Show matching workspaces without deleting"
)
--- | Parser for the 'daemon' command
-daemonParser :: Opt.Parser Command
-daemonParser =
- Daemon
- </ Opt.option
- Opt.auto
- ( Opt.long "port"
- <> Opt.short 'p'
- <> Opt.metavar "PORT"
- <> Opt.value 8400
- <> Opt.showDefault
- <> Opt.help "HTTP API port"
- )
- <*> optional
- ( Opt.strOption
- ( Opt.long "db"
- <> Opt.metavar "PATH"
- <> Opt.help "SQLite database path (default: AGENTD_DB_PATH or user data dir)"
- )
- )
- <*> optional
- ( Opt.strOption
- ( Opt.long "log-root"
- <> Opt.metavar "PATH"
- <> Opt.help "Log directory (default: AGENTD_LOG_ROOT or user state dir)"
- )
- )
- <*> optional
- ( Opt.strOption
- ( Opt.long "workspace"
- <> Opt.short 'w'
- <> Opt.metavar "PATH"
- <> Opt.help "Workspace root for auto-created agents"
- )
- )
-
notifydParser :: Opt.Parser Command
notifydParser = pure Notifyd
@@ -720,7 +678,6 @@ commandParser =
<> Opt.command "images" (Opt.info (pure Images) (Opt.progDesc "List available toolchain images"))
<> Opt.command "top" (Opt.info topParser (Opt.progDesc "Live TUI dashboard of running agents"))
<> Opt.command "cleanup" (Opt.info cleanupParser (Opt.progDesc "Remove old agent workspaces"))
- <> Opt.command "daemon" (Opt.info daemonParser (Opt.progDesc "Run as a daemon with HTTP API for agent lifecycle management"))
<> Opt.command "notifyd" (Opt.info notifydParser (Opt.progDesc "Bridge persistent agent JSONL events to Ava maildir notifications"))
<> Opt.command "test" (Opt.info (pure Test) (Opt.progDesc "Run tests"))
)
@@ -2828,20 +2785,6 @@ main = do
<> ")"
TextIO.putStrLn <| actionLabel <> " " <> tshow (length removed) <> " workspaces"
Agent agentCmd -> runAgentCommand agentCmd
- Daemon port mDbPath mLogRoot mWorkspace -> do
- workspaceRoot <- maybe Daemon.defaultWorkspaceRoot Dir.makeAbsolute mWorkspace
- defaultDb <- Daemon.defaultDaemonDbPath
- defaultLogs <- Daemon.defaultDaemonLogRoot
- bundledAgentCmd <- Text.unpack </ Daemon.resolveBundledAgentCommand
- let config =
- Daemon.DaemonConfig
- { Daemon.dcPort = port,
- Daemon.dcDbPath = fromMaybe defaultDb mDbPath,
- Daemon.dcLogRoot = fromMaybe defaultLogs mLogRoot,
- Daemon.dcWorkspace = workspaceRoot,
- Daemon.dcAgentCmd = bundledAgentCmd
- }
- Daemon.runDaemon config
Notifyd -> Daemon.runNotifyDaemon
Replay Nothing _filterType -> do
logRoot <- getLogRoot
diff --git a/Omni/Agentd/Daemon.hs b/Omni/Agentd/Daemon.hs
index 8b970a7b..11f5aaa1 100644
--- a/Omni/Agentd/Daemon.hs
+++ b/Omni/Agentd/Daemon.hs
@@ -28,19 +28,13 @@
-- : dep unix
-- : run Omni/Agent.hs
module Omni.Agentd.Daemon
- ( -- * Running the daemon
- runDaemon,
- DaemonConfig (..),
- defaultDaemonConfig,
+ ( -- * Runtime defaults
defaultDaemonDbPath,
defaultDaemonLogRoot,
defaultWorkspaceRoot,
resolveBundledAgentCommand,
- -- * API Types
- SpawnRequest (..),
- SpawnResponse (..),
- SendRequest (..),
+ -- * Agent/runtime types
AgentStatus (..),
AgentInfo (..),
@@ -51,6 +45,7 @@ module Omni.Agentd.Daemon
createAgent,
listPersistentAgents,
getPersistentAgent,
+ getPersistentMessages,
startPersistentAgent,
stopPersistentAgent,
restartPersistentAgent,
@@ -1448,6 +1443,22 @@ getPersistentAgent mDbPath runId =
Nothing -> pure Nothing
Just cfg -> Just </ hydratePersistentAgent conn cfg
+getPersistentMessages :: Maybe FilePath -> Text -> IO [Aeson.Value]
+getPersistentMessages mDbPath runId =
+ withAgentDb mDbPath <| \conn -> do
+ rows <- getRunMessages conn runId
+ pure
+ <| map
+ ( \(msgId, role, content, createdAt) ->
+ Aeson.object
+ [ "id" .= (msgId :: Int),
+ "role" .= (role :: Text),
+ "content" .= (content :: Text),
+ "created_at" .= (createdAt :: Text)
+ ]
+ )
+ rows
+
runSystemctlMutation :: Text -> [String] -> IO (Either Text ())
runSystemctlMutation runId args = do
(exitCode, _out, err) <- runSystemctlUser args
@@ -2741,20 +2752,8 @@ deleteHandler state runId = do
Right () -> pure <| Aeson.object ["status" .= ("removed" :: Text)]
messagesHandler :: DaemonState -> Text -> Handler [Aeson.Value]
-messagesHandler state runId = do
- let conn = dsDbConn state
- rows <- liftIO <| getRunMessages conn runId
- pure
- <| map
- ( \(msgId, role, content, createdAt) ->
- Aeson.object
- [ "id" .= (msgId :: Int),
- "role" .= (role :: Text),
- "content" .= (content :: Text),
- "created_at" .= (createdAt :: Text)
- ]
- )
- rows
+messagesHandler state runId =
+ liftIO <| getPersistentMessages (Just (dcDbPath (dsConfig state))) runId
healthHandler :: Handler Aeson.Value
healthHandler = pure <| Aeson.object ["status" .= ("ok" :: Text)]
@@ -2774,45 +2773,11 @@ generateAndStoreTitle conn runId prompt toolSummary = do
-- * Main Entry Point
--- | Run the daemon
+-- | HTTP daemon mode was removed; agentd now runs CLI-only.
runDaemon :: DaemonConfig -> IO ()
-runDaemon config = do
- -- Ensure directories exist
- Dir.createDirectoryIfMissing True (dcLogRoot config)
- Dir.createDirectoryIfMissing True (takeDirectory (dcDbPath config))
-
- -- Initialize database
- conn <- SQL.open (dcDbPath config)
- initDb conn
-
- -- Initialize state
- runningVar <- STM.newTVarIO Map.empty
- let state =
- DaemonState
- { dsRunning = runningVar,
- dsConfig = config,
- dsDbConn = conn
- }
-
- -- Shutdown signal (t-564): MVar to coordinate graceful exit
- shutdownSignal <- MVar.newEmptyMVar
-
- -- Handle SIGTERM/SIGINT gracefully (t-564)
- let onSignal = do
- alreadyShutting <- not </ MVar.tryPutMVar shutdownSignal ()
- unless alreadyShutting <| do
- gracefulShutdown state
- Exit.exitSuccess
- _ <- Signals.installHandler Signals.sigTERM (Signals.Catch onSignal) Nothing
- _ <- Signals.installHandler Signals.sigINT (Signals.Catch onSignal) Nothing
-
- -- Start server
- putText <| "Starting agentd daemon on port " <> tshow (dcPort config)
- putText <| " Database: " <> Text.pack (dcDbPath config)
- putText <| " Log root: " <> Text.pack (dcLogRoot config)
- putText <| " Workspace: " <> Text.pack (dcWorkspace config)
- putText <| " Agent command: " <> Text.pack (dcAgentCmd config)
- Warp.run (dcPort config) (serve agentAPI (server state))
+runDaemon _ = do
+ TextIO.hPutStrLn IO.stderr "agentd daemon mode has been removed. Use the agentd CLI control plane instead."
+ Exit.exitWith (Exit.ExitFailure 1)
-- | Graceful shutdown: stop all running agents, close handles (t-564)
gracefulShutdown :: DaemonState -> IO ()
@@ -2836,19 +2801,7 @@ gracefulShutdown state = do
-- * Tests
main :: IO ()
-main = do
- args <- Env.getArgs
- case args of
- ["daemon", "--port", portStr, "--db", dbPath, "--log-root", logRoot, "--workspace", workspace] ->
- runDaemon
- DaemonConfig
- { dcPort = fromMaybe 8400 (Read.readMaybe portStr),
- dcDbPath = dbPath,
- dcLogRoot = logRoot,
- dcWorkspace = workspace,
- dcAgentCmd = "agent"
- }
- _ -> Test.run test
+main = Test.run test
test :: Test.Tree
test =
diff --git a/Omni/Ide/deploy-agentd.sh b/Omni/Ide/deploy-agentd.sh
index 2dd8a8ee..988cc1e9 100755
--- a/Omni/Ide/deploy-agentd.sh
+++ b/Omni/Ide/deploy-agentd.sh
@@ -1,65 +1,12 @@
#!/usr/bin/env bash
-# Deploy agentd via Omni deployer with hermetic store-path references.
+# agentd HTTP daemon was removed.
#
-# This script is the canonical, repo-tracked way to publish agentd service config.
-# agentd carries agent as a local runtime dependency via bild metadata.
+# Persistent sessions are managed directly via `agentd` CLI commands and
+# per-agent user systemd units. There is no long-running agentd daemon
+# service to deploy anymore.
set -euo pipefail
-CODEROOT=${CODEROOT:?must set CODEROOT}
-cd "$CODEROOT"
-
-bild Omni/Agentd.hs
-bild Omni/Deploy/Manifest.hs
-
-agentd_store=$(readlink "$CODEROOT/_/nix/Omni/Agentd.hs")
-manifest_store=$(readlink "$CODEROOT/_/nix/Omni/Deploy/Manifest.hs")
-revision=$(git rev-parse --short HEAD)
-
-service_json=$(jq -n \
- --arg store_path "$agentd_store" \
- --arg revision "$revision" \
- '{
- name: "agentd",
- artifact: { type: "nix-closure", storePath: $store_path },
- hosts: ["beryllium"],
- exec: {
- command: "agentd daemon --port 8400 --db /var/lib/omni/agentd.db --log-root /var/log/agentd --workspace /var/lib/omni/agentd/workspaces",
- user: "ben",
- group: "users",
- workingDirectory: "/home/ben/omni/live"
- },
- env: {
- HOME: "/home/ben",
- CODEROOT: "/home/ben/omni/live",
- LANG: "en_US.utf8",
- LC_ALL: "en_US.utf8",
- PATH: "/run/current-system/sw/bin:/usr/bin:/bin",
- AGENTD_STATE_DIR: "/var/lib/omni/agentd-agents"
- },
- envFile: null,
- http: null,
- systemd: {
- after: ["network-online.target"],
- requires: [],
- restart: "on-failure",
- restartSec: 5,
- type: "simple"
- },
- hardening: {
- dynamicUser: false,
- privateTmp: false,
- protectSystem: "strict",
- protectHome: false,
- noNewPrivileges: false,
- readWritePaths: ["/tmp", "/var/lib/omni", "/var/log/agentd", "/home/ben/omni"],
- readOnlyPaths: ["/home/ben/work"]
- },
- revision: $revision,
- forceRedeploy: true
- }')
-
-"$manifest_store/bin/deploy-manifest" add-service "$service_json"
-
-echo "Updated manifest for agentd."
-echo "Deployer will reconcile on its next timer tick (or run: /run/wrappers/bin/sudo systemctl start deployer)."
+echo "agentd daemon has been removed."
+echo "No deploy step is required for a daemon service."
+echo "Use 'agentd' CLI commands directly (start/create/status/send/logs/watch/top)."