commit c9281bcefd906a04ba515c7c16a31e08aa11d391
Author: Coder Agent <coder@agents.omni>
Date: Wed Apr 15 09:18:29 2026
feat(agentd): bundle agent runtime and drop AGENTD_AGENT_COMMAND
Add local run dep on Omni/Agent.hs for agentd binaries.
Bake resolved agent path into persistent runtime wrapper.
Task-Id: t-794
diff --git a/Omni/Agentd.hs b/Omni/Agentd.hs
index 859cd0e7..cba9394b 100755
--- a/Omni/Agentd.hs
+++ b/Omni/Agentd.hs
@@ -15,6 +15,7 @@
-- : dep yaml
-- : dep brick
-- : dep vty
+-- : run Omni/Agent.hs
module Omni.Agentd
( main,
test,
@@ -2518,13 +2519,14 @@ main = 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 = "agent"
+ Daemon.dcAgentCmd = bundledAgentCmd
}
Daemon.runDaemon config
Notifyd -> Daemon.runNotifyDaemon
diff --git a/Omni/Agentd/Daemon.hs b/Omni/Agentd/Daemon.hs
index 4192cd30..28dc10b3 100644
--- a/Omni/Agentd/Daemon.hs
+++ b/Omni/Agentd/Daemon.hs
@@ -26,6 +26,7 @@
-- : dep time
-- : dep uuid
-- : dep unix
+-- : run Omni/Agent.hs
module Omni.Agentd.Daemon
( -- * Running the daemon
runDaemon,
@@ -34,6 +35,7 @@ module Omni.Agentd.Daemon
defaultDaemonDbPath,
defaultDaemonLogRoot,
defaultWorkspaceRoot,
+ resolveBundledAgentCommand,
-- * API Types
SpawnRequest (..),
@@ -914,8 +916,8 @@ resolveNotifydCommand = do
mResolved <- Dir.findExecutable "agentd"
pure (Text.pack (fromMaybe "agentd" mResolved))
-renderAgentExecScript :: Text
-renderAgentExecScript =
+renderAgentExecScript :: Text -> Text
+renderAgentExecScript agentCmd =
Text.unlines
[ "#!/usr/bin/env bash",
"set -euo pipefail",
@@ -945,7 +947,6 @@ renderAgentExecScript =
"exec 3<>\"$FIFO\"",
"exec > >(tee -a \"$SESSION_FILE\")",
"",
- "AGENTD_AGENT_COMMAND=\"${AGENTD_AGENT_COMMAND:-agent}\"",
"RESUME_ARGS=()",
"if [[ -f \"$SESSION_CHECKPOINT\" ]]; then",
" RESUME_ARGS=(--resume \"$SESSION_CHECKPOINT\")",
@@ -956,7 +957,7 @@ renderAgentExecScript =
" EXTRA_ARGS=(${AGENTD_EXTRA_ARGS})",
"fi",
"",
- "exec \"$AGENTD_AGENT_COMMAND\" \\",
+ "exec \"" <> agentCmd <> "\" \\",
" --provider \"${AGENTD_PROVIDER}\" \\",
" --model \"${AGENTD_MODEL}\" \\",
" --run-id \"${AGENTD_AGENT_NAME}\" \\",
@@ -1023,10 +1024,11 @@ ensurePersistentRuntimeAssets = do
notifydUnitPath <- notifydSystemdUnitPath
stateDir <- agentStateDir
notifydCmd <- resolveNotifydCommand
+ agentCmd <- resolveBundledAgentCommand
Dir.createDirectoryIfMissing True envDir
Dir.createDirectoryIfMissing True stateDir
Dir.createDirectoryIfMissing True (takeDirectory unitPath)
- TextIO.writeFile execPath renderAgentExecScript
+ TextIO.writeFile execPath (renderAgentExecScript agentCmd)
(chmodCode, _chmodOut, chmodErr) <- Process.readProcessWithExitCode "chmod" ["0755", execPath] ""
when (chmodCode /= Exit.ExitSuccess) <| Exception.throwIO <| IOError.userError ("chmod failed for " <> execPath <> ": " <> chmodErr)
TextIO.writeFile unitPath (renderAgentSystemdUnit envDir execPath)
@@ -1203,14 +1205,12 @@ queryMainPid name = do
then pure (Read.readMaybe (Text.unpack (Text.strip (Text.pack out))))
else pure Nothing
-resolvePersistentAgentCommand :: IO Text
-resolvePersistentAgentCommand = do
- mOverride <- Env.lookupEnv "AGENTD_AGENT_COMMAND"
- case mOverride of
- Just cmd -> pure (Text.pack cmd)
- Nothing -> do
- mResolved <- Dir.findExecutable "agent"
- pure (Text.pack (fromMaybe "agent" mResolved))
+resolveBundledAgentCommand :: IO Text
+resolveBundledAgentCommand = do
+ mResolved <- Dir.findExecutable "agent"
+ case mResolved of
+ Nothing -> Exception.throwIO <| IOError.userError "agent executable not found on PATH (expected bundled runtime dep)"
+ Just rawPath -> Text.pack </ Dir.canonicalizePath rawPath
resolvePersistentStateDir :: IO Text
resolvePersistentStateDir = Text.pack </ agentStateDir
@@ -1220,7 +1220,6 @@ writeAgentEnvFile cfg = do
dir <- agentEnvDir
Dir.createDirectoryIfMissing True dir
path <- agentEnvPath (acName cfg)
- agentCmd <- resolvePersistentAgentCommand
stateDir <- resolvePersistentStateDir
let baseLines =
[ "AGENTD_PROVIDER=" <> sanitizeEnvValue (acProvider cfg),
@@ -1228,7 +1227,6 @@ writeAgentEnvFile cfg = do
"AGENTD_CWD=" <> sanitizeEnvValue (Text.pack (acCwd cfg)),
"AGENTD_THINKING=" <> sanitizeEnvValue (acThinking cfg),
"AGENTD_EXTRA_ARGS=" <> maybe "" sanitizeEnvValue (acExtraArgs cfg),
- "AGENTD_AGENT_COMMAND=" <> sanitizeEnvValue agentCmd,
"AGENTD_STATE_DIR=" <> sanitizeEnvValue stateDir
]
extraLines = map (\(k, v) -> k <> "=" <> sanitizeEnvValue v) (Map.toAscList (acExtraEnv cfg))
@@ -2664,7 +2662,7 @@ test =
Test.assertBool "updated_at key should be present" (isJust (KeyMap.lookup "updated_at" obj))
Just _ -> Test.assertFailure "Expected object JSON for AgentInfo",
Test.unit "persistent runtime script uses agent stdin mode" <| do
- let script = renderAgentExecScript
+ let script = renderAgentExecScript "/nix/store/abc-agent/bin/agent"
Test.assertBool "script should launch agent with json output" ("--json" `Text.isInfixOf` script)
Test.assertBool "script should forward run-id" ("--run-id \"${AGENTD_AGENT_NAME}\"" `Text.isInfixOf` script)
Test.assertBool "script should append stdout to per-agent sessions jsonl" ("exec > >(tee -a \"$SESSION_FILE\")" `Text.isInfixOf` script)
@@ -2672,6 +2670,8 @@ test =
Test.assertBool "script should persist checkpoints" ("--checkpoint-dir \"$CHECKPOINT_DIR\"" `Text.isInfixOf` script)
Test.assertBool "script should look for latest session checkpoint" ("SESSION_CHECKPOINT=\"${CHECKPOINT_DIR}/session-latest.json\"" `Text.isInfixOf` script)
Test.assertBool "script should wire resume args" ("RESUME_ARGS=(--resume \"$SESSION_CHECKPOINT\")" `Text.isInfixOf` script)
+ Test.assertBool "script should execute bundled agent path" ("exec \"/nix/store/abc-agent/bin/agent\" \\" `Text.isInfixOf` script)
+ Test.assertBool "script should not require AGENTD_AGENT_COMMAND env var" (not ("AGENTD_AGENT_COMMAND" `Text.isInfixOf` script))
Test.assertBool "script should not reference legacy agentd-rpc" (not ("agentd-rpc" `Text.isInfixOf` script))
Test.assertBool "script should not use rpc mode flag" (not ("--mode rpc" `Text.isInfixOf` script)),
Test.unit "notify parser extracts completion events" <| do
diff --git a/Omni/Agentd/SPEC.md b/Omni/Agentd/SPEC.md
index 1f0ac9cf..e82a3a8a 100644
--- a/Omni/Agentd/SPEC.md
+++ b/Omni/Agentd/SPEC.md
@@ -110,6 +110,9 @@ Persistent sessions also persist agent checkpoints under `$AGENTD_STATE_DIR/chec
The runtime wrapper always passes `--checkpoint-dir` and auto-adds `--resume .../session-latest.json`
when that file exists, so `agentd restart` restores prior conversation context.
+The agent executable path is baked into the generated runtime wrapper from agentd's bundled
+runtime dependency, so persistent sessions do not rely on `AGENTD_AGENT_COMMAND` or ambient PATH drift.
+
Persistent runtime assets are generated by `agentd` itself on create/start:
- `~/.config/systemd/user/agentd-agent@.service`
diff --git a/Omni/Ide/deploy-agentd.sh b/Omni/Ide/deploy-agentd.sh
index 15c8a8d0..2dd8a8ee 100755
--- a/Omni/Ide/deploy-agentd.sh
+++ b/Omni/Ide/deploy-agentd.sh
@@ -2,25 +2,22 @@
# Deploy agentd via Omni deployer with hermetic store-path references.
#
# This script is the canonical, repo-tracked way to publish agentd service config.
-# It ensures both agentd and agent runtime paths are absolute Nix store paths.
+# agentd carries agent as a local runtime dependency via bild metadata.
set -euo pipefail
CODEROOT=${CODEROOT:?must set CODEROOT}
cd "$CODEROOT"
-bild Omni/Agent.hs
bild Omni/Agentd.hs
bild Omni/Deploy/Manifest.hs
-agent_store=$(readlink "$CODEROOT/_/nix/Omni/Agent.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 agent_cmd "$agent_store/bin/agent" \
--arg revision "$revision" \
'{
name: "agentd",
@@ -38,7 +35,6 @@ service_json=$(jq -n \
LANG: "en_US.utf8",
LC_ALL: "en_US.utf8",
PATH: "/run/current-system/sw/bin:/usr/bin:/bin",
- AGENTD_AGENT_COMMAND: $agent_cmd,
AGENTD_STATE_DIR: "/var/lib/omni/agentd-agents"
},
envFile: null,