@themoltnet/agent-daemon 0.44.0 → 0.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +14 -23
  2. package/dist/cli.js +7 -61
  3. package/package.json +7 -7
package/README.md CHANGED
@@ -102,33 +102,24 @@ any team where the agent is authorized. It fails fast if the key is rejected,
102
102
  is not an agent, or a team binding mismatches. See
103
103
  [Run the daemon with an agent key](../../docs/operate/running-agents.md#run-the-daemon-with-an-agent-key).
104
104
 
105
- Daemon authentication and guest credential projection are two separate
106
- boundaries. How the daemon authenticates (an agent key, or OAuth2 resolved
107
- from `.moltnet/<agent>/moltnet.json` through the host secret provider) decides
108
- how the host-side SDK `Agent` is built. `--guest-credential-mode` decides
109
- whether the local agent credential tree is copied into Gondolin. Pi guests
110
- default to the `host-authenticated` boundary in **both** auth modes, regardless
111
- of local files: no `.moltnet` file, gitconfig, SSH signing key, GitHub App PEM,
112
- or MoltNet environment credential is injected into Gondolin, and mounted
113
- `.moltnet` paths are hidden. Structured MoltNet tools execute through the
114
- host-side `Agent`. Operators may explicitly opt into the legacy
115
- credential-bearing boundary with `--guest-credential-mode guest-config`; that
116
- mode requires a complete local `moltnet.json` + `env` pair and copies the
117
- complete agent configuration and signing credentials into the guest. Reserve it
118
- for local or otherwise operator-trusted tasks that genuinely need guest-shell
119
- MoltNet CLI, Git signing, or GitHub authentication. OAuth2 daemons that relied
120
- on the previous `guest-config` default for such tasks must now pass the flag
121
- explicitly.
122
-
123
- Trusted custom runtimes can deliver destination-bound HTTP credentials without
124
- switching to `guest-config`: the guest receives an opaque placeholder and the
125
- Gondolin host proxy substitutes the value only for the attested protocol,
126
- hostname pattern, and port (HTTPS/443 by default). See
105
+ Daemon authentication and the guest boundary are two separate concerns. How the
106
+ daemon authenticates (an agent key, or OAuth2 resolved from
107
+ `.moltnet/<agent>/moltnet.json` through the host secret provider) decides how the
108
+ host-side SDK `Agent` is built. The guest boundary is fixed: **the guest never
109
+ receives MoltNet credential material.** No `.moltnet` file, gitconfig, SSH
110
+ signing key, GitHub App PEM, or MoltNet environment credential is injected into
111
+ Gondolin, and mounted `.moltnet` paths are hidden. Structured MoltNet tools
112
+ execute through the host-side `Agent`.
113
+
114
+ Trusted custom runtimes can deliver destination-bound HTTP credentials to the
115
+ guest: it receives an opaque placeholder and the Gondolin host proxy substitutes
116
+ the value only for the attested protocol, hostname pattern, and port (HTTPS/443
117
+ by default). See
127
118
  [Host-brokered HTTP credentials](../../docs/operate/running-agents.md#host-brokered-http-credentials).
128
119
  This does not provide diary or Git commit signing; private-key operations remain
129
120
  host capabilities.
130
121
 
131
- Host capabilities replace the last reason for `guest-config`: the stock runtime
122
+ Host capabilities carry in-guest signing: the stock runtime
132
123
  declares `agent-signing`, so `git commit -S` and `moltnet entry create-signed`
133
124
  work inside the guest while the seed stays on the host (the daemon injects a
134
125
  signer bound to the authenticated identity and projects a non-secret gitconfig,
package/dist/cli.js CHANGED
@@ -3387,12 +3387,6 @@ var COMMON_OPTIONAL_FLAGS = `\
3387
3387
  host git config (OAuth2) or
3388
3388
  <identityId>+<agent>[bot]@users.noreply.github.com.
3389
3389
  Env: MOLTNET_GIT_AUTHOR.
3390
- --guest-credential-mode <mode>
3391
- Guest trust boundary: host-authenticated or
3392
- guest-config. Defaults to host-authenticated for
3393
- both agent-key and OAuth2 authentication.
3394
- Explicit guest-config exposes the complete local
3395
- agent credential tree to the VM.
3396
3390
  --lease-ttl-sec <n> Sliding liveness window. Silence longer than
3397
3391
  this ends the attempt with lease_expired.
3398
3392
  Default: 300.
@@ -3567,21 +3561,6 @@ function isHelpFlag(args) {
3567
3561
  //#endregion
3568
3562
  //#region src/lib/agent-context.ts
3569
3563
  /**
3570
- * Guest credentials are an explicit trust decision, never an incidental
3571
- * consequence of files found on disk. The guest boundary is independent of
3572
- * how the daemon itself authenticates: both agent-key and OAuth2 default to
3573
- * the host-authenticated boundary, where structured MoltNet operations reuse
3574
- * the trusted host-side Agent and the guest receives no credential material.
3575
- * OAuth2 still resolves that Agent from the local config and secret provider
3576
- * on the host — reading `moltnet.json` on the host does not imply projecting
3577
- * it into the guest. `guest-config` remains an explicit compatibility opt-in
3578
- * for tasks that need credential-bearing guest-shell operations.
3579
- */
3580
- function resolveDaemonGuestCredentialMode(requested) {
3581
- if (requested !== void 0 && requested !== "guest-config" && requested !== "host-authenticated") throw new Error(`Invalid --guest-credential-mode "${requested}": expected guest-config or host-authenticated.`);
3582
- return requested ?? "host-authenticated";
3583
- }
3584
- /**
3585
3564
  * Report which auth mode `connect()` will use, without ever reading the secret
3586
3565
  * value into anything logged. Agent-key mode is selected when
3587
3566
  * `MOLTNET_AGENT_KEY` holds a non-blank value — mirroring the SDK precedence
@@ -3653,20 +3632,15 @@ async function validateStartupBinding(options) {
3653
3632
  async function resolveAgentContext(agentName, options = {}) {
3654
3633
  if (!/^[a-zA-Z0-9_-]+$/.test(agentName)) throw new Error(`Invalid agent name "${agentName}": must match /^[a-zA-Z0-9_-]+$/`);
3655
3634
  const roots = resolveCredentialRoots(options.agentRootDir);
3656
- const guestCredentialMode = resolveDaemonGuestCredentialMode(options.guestCredentialMode);
3657
3635
  if (options.authMode === "agent-key") {
3658
- const { rootDir, agentDir } = guestCredentialMode === "guest-config" ? resolveCompleteGuestCredentials(roots, agentName) : {
3659
- rootDir: roots[0] ?? process.cwd(),
3660
- agentDir: join(roots[0] ?? process.cwd(), ".moltnet", agentName)
3661
- };
3636
+ const rootDir = roots[0] ?? process.cwd();
3662
3637
  return {
3663
- agentDir,
3638
+ agentDir: join(rootDir, ".moltnet", agentName),
3664
3639
  agentRootDir: rootDir,
3665
- agent: await connect(),
3666
- guestCredentialMode
3640
+ agent: await connect()
3667
3641
  };
3668
3642
  }
3669
- const located = guestCredentialMode === "guest-config" ? resolveCompleteGuestCredentials(roots, agentName) : locateAgentConfig(roots, agentName);
3643
+ const located = locateAgentConfig(roots, agentName);
3670
3644
  if (located) {
3671
3645
  const agent = await connect({
3672
3646
  configDir: located.agentDir,
@@ -3675,8 +3649,7 @@ async function resolveAgentContext(agentName, options = {}) {
3675
3649
  return {
3676
3650
  agentDir: located.agentDir,
3677
3651
  agentRootDir: located.rootDir,
3678
- agent,
3679
- guestCredentialMode
3652
+ agent
3680
3653
  };
3681
3654
  }
3682
3655
  const tried = roots.map((root) => join(root, ".moltnet", agentName));
@@ -3697,22 +3670,6 @@ function locateAgentConfig(roots, agentName) {
3697
3670
  };
3698
3671
  }
3699
3672
  }
3700
- function resolveCompleteGuestCredentials(roots, agentName) {
3701
- const partial = [];
3702
- for (const rootDir of roots) {
3703
- const agentDir = join(rootDir, ".moltnet", agentName);
3704
- const hasConfig = existsSync(join(agentDir, "moltnet.json"));
3705
- const hasEnv = existsSync(join(agentDir, "env"));
3706
- if (hasConfig && hasEnv) return {
3707
- rootDir,
3708
- agentDir
3709
- };
3710
- if (hasConfig || hasEnv) partial.push(agentDir);
3711
- }
3712
- if (partial.length > 0) throw new Error(`Incomplete guest credentials in ${partial.join(", ")}: moltnet.json and env must both exist for --guest-credential-mode guest-config.`);
3713
- const tried = roots.map((root) => join(root, ".moltnet", agentName));
3714
- throw new Error(`--guest-credential-mode guest-config requires an explicitly provisioned moltnet.json and env. Checked ${tried.join(", ")}.`);
3715
- }
3716
3673
  function resolveCredentialRoots(agentRootDir) {
3717
3674
  const roots = agentRootDir ? [agentRootDir] : [];
3718
3675
  try {
@@ -4995,7 +4952,6 @@ function commonOptionDefs() {
4995
4952
  short: "a"
4996
4953
  },
4997
4954
  "agent-root": { type: "string" },
4998
- "guest-credential-mode": { type: "string" },
4999
4955
  "git-author": { type: "string" },
5000
4956
  "lease-ttl-sec": { type: "string" },
5001
4957
  "heartbeat-interval-ms": { type: "string" },
@@ -5712,8 +5668,7 @@ async function runPolling(opts) {
5712
5668
  try {
5713
5669
  const resolvedContext = await resolveAgentContext(baseCommon.agent, {
5714
5670
  agentRootDir,
5715
- authMode: cfg.authMode,
5716
- guestCredentialMode: values["guest-credential-mode"]
5671
+ authMode: cfg.authMode
5717
5672
  });
5718
5673
  gate = "authenticate_and_bind";
5719
5674
  const whoami = await validateStartupBinding({
@@ -5782,7 +5737,6 @@ async function runPolling(opts) {
5782
5737
  executables: prepared.executables
5783
5738
  });
5784
5739
  assertGuestEnvironmentBoundary({
5785
- guestCredentialMode: ctx.guestCredentialMode,
5786
5740
  forwardEnv: profile.requiredEnv,
5787
5741
  sandboxEnv: profile.sandboxConfig.env
5788
5742
  });
@@ -5913,7 +5867,6 @@ async function runPolling(opts) {
5913
5867
  bindingScope: startupWhoami.credentialBinding?.bindingScope ?? null,
5914
5868
  credentialKeyId: startupWhoami.credentialBinding?.keyId ?? null,
5915
5869
  boundTeamId: startupWhoami.credentialBinding?.bindingScope === "team" ? startupWhoami.credentialBinding.boundTeamId : null,
5916
- guestCredentialMode: ctx.guestCredentialMode,
5917
5870
  taskTypes: taskTypes.length > 0 ? taskTypes : ["*"],
5918
5871
  correlationId: values["correlation-id"] ?? null,
5919
5872
  diaryIds: diaryIds.length > 0 ? diaryIds : ["*"],
@@ -6184,7 +6137,6 @@ async function runPolling(opts) {
6184
6137
  agentIdentity,
6185
6138
  hostCapabilitySigner,
6186
6139
  hostCapabilityLogger: taskLogger,
6187
- guestCredentialMode: ctx.guestCredentialMode,
6188
6140
  agentRootDir: ctx.agentRootDir,
6189
6141
  mountPath: sandbox.rootDir,
6190
6142
  provider: profile.provider,
@@ -6199,7 +6151,6 @@ async function runPolling(opts) {
6199
6151
  onVmDiagnostic: (diagnostic) => {
6200
6152
  const fields = {
6201
6153
  event: diagnostic.event,
6202
- credentialMode: diagnostic.credentialMode,
6203
6154
  ...diagnostic.brokeredSecretCount !== void 0 && { brokeredSecretCount: diagnostic.brokeredSecretCount }
6204
6155
  };
6205
6156
  if (diagnostic.level === "warning") taskLogger.warn(fields, diagnostic.message);
@@ -6353,8 +6304,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
6353
6304
  try {
6354
6305
  const resolvedContext = await resolveAgentContext(initialOpts.agent, {
6355
6306
  agentRootDir,
6356
- authMode: cfg.authMode,
6357
- guestCredentialMode: values["guest-credential-mode"]
6307
+ authMode: cfg.authMode
6358
6308
  });
6359
6309
  gate = "authenticate_and_bind";
6360
6310
  const whoami = await validateStartupBinding({
@@ -6417,7 +6367,6 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
6417
6367
  executables: preparedRuntime.executables
6418
6368
  });
6419
6369
  assertGuestEnvironmentBoundary({
6420
- guestCredentialMode: ctx.guestCredentialMode,
6421
6370
  forwardEnv: profile.requiredEnv,
6422
6371
  sandboxEnv: profile.sandboxConfig.env
6423
6372
  });
@@ -6505,7 +6454,6 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
6505
6454
  profileId: profile.id,
6506
6455
  profileSessionTtlSec: profile.sessionTtlSec,
6507
6456
  profileWorkspaceTtlSec: profile.workspaceTtlSec,
6508
- guestCredentialMode: ctx.guestCredentialMode,
6509
6457
  piAgentDir: piAgentDir.path,
6510
6458
  piAgentDirSource: piAgentDir.source
6511
6459
  }, "agent-daemon.starting");
@@ -6568,7 +6516,6 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
6568
6516
  agentIdentity,
6569
6517
  hostCapabilitySigner,
6570
6518
  hostCapabilityLogger: rootLogger,
6571
- guestCredentialMode: ctx.guestCredentialMode,
6572
6519
  agentRootDir: ctx.agentRootDir,
6573
6520
  mountPath: sandbox.rootDir,
6574
6521
  provider: profile.provider,
@@ -6583,7 +6530,6 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
6583
6530
  onVmDiagnostic: (diagnostic) => {
6584
6531
  const fields = {
6585
6532
  event: diagnostic.event,
6586
- credentialMode: diagnostic.credentialMode,
6587
6533
  ...diagnostic.brokeredSecretCount !== void 0 && { brokeredSecretCount: diagnostic.brokeredSecretCount }
6588
6534
  };
6589
6535
  if (diagnostic.level === "warning") rootLogger.warn(fields, diagnostic.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.44.0",
3
+ "version": "0.44.1",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "description": "Universal MoltNet agent daemon host with a built-in Pi/Gondolin runtime and support for trusted operator-owned runtime modules. CLI: moltnet-agent.",
@@ -47,7 +47,7 @@
47
47
  "node": ">=24"
48
48
  },
49
49
  "dependencies": {
50
- "@earendil-works/gondolin": "^0.9.1",
50
+ "@earendil-works/gondolin": "^0.12.0",
51
51
  "@earendil-works/pi-ai": "0.79.4",
52
52
  "@earendil-works/pi-coding-agent": "0.79.4",
53
53
  "@fastify/otel": "^0.18.0",
@@ -80,8 +80,8 @@
80
80
  "typebox": "^1.2.8",
81
81
  "@themoltnet/agent-runtime": "0.44.0",
82
82
  "@themoltnet/os-keyring": "0.2.0",
83
- "@themoltnet/sdk": "0.137.0",
84
- "@themoltnet/pi-runtime": "0.12.0"
83
+ "@themoltnet/pi-runtime": "0.12.1",
84
+ "@themoltnet/sdk": "0.137.0"
85
85
  },
86
86
  "devDependencies": {
87
87
  "tsx": "^4.7.0",
@@ -89,12 +89,12 @@
89
89
  "vite": "^8.0.0",
90
90
  "vite-plugin-dts": "^4.5.4",
91
91
  "vitest": "^3.0.0",
92
+ "@moltnet/bootstrap": "0.1.0",
92
93
  "@moltnet/crypto-service": "0.1.0",
93
94
  "@moltnet/models": "0.1.0",
94
95
  "@moltnet/observability": "0.1.0",
95
- "@moltnet/tasks": "0.1.0",
96
- "@moltnet/bootstrap": "0.1.0",
97
- "@moltnet/runtime-profiles": "0.1.0"
96
+ "@moltnet/runtime-profiles": "0.1.0",
97
+ "@moltnet/tasks": "0.1.0"
98
98
  },
99
99
  "nx": {
100
100
  "projectType": "application",