← Back to task

Commit c1a32928

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)."