@thirdfy/agent-cli 0.1.38 → 0.1.40

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.40] - 2026-05-17
8
+
9
+ ### Fixed
10
+
11
+ - Email login and bootstrap commands now persist agent credentials from nested API response shapes such as `registration.registration.agentApiKey`, so owner-session onboarding can resolve the hidden execution identity without requiring users to pass a raw agent API key manually.
12
+
13
+ ## [0.1.39] - 2026-05-17
14
+
15
+ ### Added
16
+
17
+ - Framework guidance for Hermes, OpenClaw, and Claude Managed Agents in `help onboarding`, README, and command reference so agents can choose CLI/MCP rails correctly.
18
+ - Gator-style `delegation grant` alias and clearer external-wallet delegation next steps.
19
+
20
+ ### Changed
21
+
22
+ - Fresh solo profiles now default to `agent_wallet`, persist/resolve owner `userDid`, and use owner-matched mirror scope for hybrid validation.
23
+
7
24
  ## [0.1.38] - 2026-05-17
8
25
 
9
26
  ### Fixed
package/README.md CHANGED
@@ -9,12 +9,13 @@ Use it to:
9
9
  - run governance preflight checks
10
10
  - queue execute-intent requests with idempotency
11
11
  - poll intent status with stable JSON output for automation
12
- - choose execution topology with one switch: `thirdfy`, `self`, or `hybrid`
12
+ - choose execution topology with one switch: `agent_wallet`, `self`, `hybrid`, or `thirdfy`
13
13
  - configure profile-driven defaults (`personal`, `builder`, `network`)
14
14
 
15
15
  If you want the full developer docs, start here:
16
- - [Thirdfy Agent CLI docs](https://docs.thirdfy.com/api/thirdfy-agent-cli)
17
- - [API Reference home](https://docs.thirdfy.com/api)
16
+ - [Thirdfy Agent CLI hub](https://docs.thirdfy.com/documentation/agent-cli) (guided chapters)
17
+ - [Thirdfy Agent CLI — full reference](https://docs.thirdfy.com/documentation/api/thirdfy-agent-cli)
18
+ - [API Reference home](https://docs.thirdfy.com/documentation/api/api-reference)
18
19
  - [LLM docs map (llms.txt)](https://docs.thirdfy.com/llms.txt)
19
20
  - [LLM full API snapshot (llms-full.txt)](https://docs.thirdfy.com/llms-full.txt)
20
21
  - [Provider docs index (repo)](./docs/providers/index.md)
@@ -41,7 +42,7 @@ npx @thirdfy/agent-cli --help
41
42
 
42
43
  ## Release notes
43
44
 
44
- Version history and highlights: [CHANGELOG.md](./CHANGELOG.md). **v0.1.38** is a **documentation and metadata patch**: it republishes to npm so the package homepage matches the updated `README.md` on `main`, and aligns root `package-lock.json` version fields with `package.json`. **v0.1.37** adds **email OTP** `thirdfy-agent login email` (send code, then complete with `--code --accept-terms`), **`help onboarding`**, **`doctor auth`**, **`wallet list`**, and **masked `whoami`** output so agents and operators get first-run guidance without dumping secrets. **v0.1.35** extended `thirdfy-agent actions` hints for Polymarket Gamma-style discovery (`gamma_search_*` where catalog-backed) and legacy `search_polymarket` / `get_polymarket_*` reads, with public docs aligned to the deposit-wallet (pUSD / POLY_1271) operator path. Earlier releases added provider discovery parity, portfolio analytics, managed-wallet swap normalization, and **self/build-tx** swap human-decimal `amountIn` parity when using `amountInHuman` + `tokenInDecimals`.
45
+ Version history and highlights: [CHANGELOG.md](./CHANGELOG.md). **v0.1.40** fixes email/bootstrap credential persistence when the API returns nested registration payloads, so owner-session onboarding can save the hidden execution identity without exposing a raw agent API key. **v0.1.39** makes `agent_wallet` the fresh solo default, adds framework guidance for Hermes/OpenClaw/Claude Managed Agents, clarifies Gator/ERC-7710 delegation flows, and keeps BYOW/self plus hybrid/thirdfy mode switching explicit. **v0.1.38** is a **documentation and metadata patch**: it republishes to npm so the package homepage matches the updated `README.md` on `main`, and aligns root `package-lock.json` version fields with `package.json`. **v0.1.37** adds **email OTP** `thirdfy-agent login email` (send code, then complete with `--code --accept-terms`), **`help onboarding`**, **`doctor auth`**, **`wallet list`**, and **masked `whoami`** output so agents and operators get first-run guidance without dumping secrets. Earlier releases added provider discovery parity, portfolio analytics, managed-wallet swap normalization, and **self/build-tx** swap human-decimal `amountIn` parity when using `amountInHuman` + `tokenInDecimals`.
45
46
 
46
47
  **Maintainers — npm:** follow [docs/releasing.md](./docs/releasing.md). From a clone with gitignored `.env`, use `npm run publish:npm:local -- --dry-run` then `npm run publish:npm:local`. Or run `npm run release:npm` after exporting tokens in the shell. Never commit npm tokens — use [.env.example](./.env.example) as a template only.
47
48
 
@@ -103,7 +104,7 @@ thirdfy-agent logout --json
103
104
  thirdfy-agent logout --all --json
104
105
  ```
105
106
 
106
- `login email` is a two-step headless-safe flow. Without `--code`, the CLI asks the Thirdfy API onboarding broker to send a Privy email OTP and exits with the exact next command. With `--code --accept-terms`, it stores a short-lived owner session in `~/.thirdfy/config.json`, records linked EVM/Solana wallets when Privy returns them, and stores a new agent API key when first-run bootstrap issues one. Use `--not-interactive` / `--ni` in automation so missing input fails fast instead of prompting — place **`--ni` after the `login email` subcommand** (for example `thirdfy-agent login email you@example.com --code … --accept-terms --ni`); a leading `thirdfy-agent --ni login email …` is parsed incorrectly because `--ni` would consume the `login` token as its value.
107
+ `login email` is a two-step headless-safe flow. Without `--code`, the CLI asks the Thirdfy API onboarding broker to send a Privy email OTP and exits with the exact next command. With `--code --accept-terms`, it stores a short-lived owner session in `~/.thirdfy/config.json`, records linked EVM/Solana wallets plus the owner `userDid` when Privy returns them, stores a new agent API key when first-run bootstrap issues one, and defaults new solo profiles to `agent_wallet`. Use `--not-interactive` / `--ni` in automation so missing input fails fast instead of prompting — place **`--ni` after the `login email` subcommand** (for example `thirdfy-agent login email you@example.com --code … --accept-terms --ni`); a leading `thirdfy-agent --ni login email …` is parsed incorrectly because `--ni` would consume the `login` token as its value.
107
108
 
108
109
  `logout --all` is provider-agnostic: it attempts owner-session revocation when a session token exists, then always clears local credentials.
109
110
 
@@ -149,15 +150,17 @@ thirdfy-agent bootstrap complete --agent-key "0xYOUR_AGENT_KEY" --challenge-id "
149
150
 
150
151
  `thirdfy-agent` supports one command surface with four run modes:
151
152
 
152
- - `--run-mode thirdfy` -> Thirdfy-governed execute-intent rail (default for `profile=network`)
153
- - `--run-mode self` -> self-custody rail (`build-tx` flow; default for `profile=personal`)
153
+ - `--run-mode agent_wallet` -> managed solo wallet execution rail and fresh email-login default
154
+ - `--run-mode self` -> self-custody rail (`build-tx` flow)
154
155
  - `--run-mode hybrid` -> self-custody + governance mirror metadata (default for `profile=builder`)
155
- - `--run-mode agent_wallet` -> managed wallet execution rail for Claude-friendly hosted execution
156
+ - `--run-mode thirdfy` -> Thirdfy-governed execute-intent rail (default for `profile=network`)
156
157
 
157
158
  | Goal | Recommended mode | Why |
158
159
  | --- | --- | --- |
160
+ | Fast solo managed-wallet trading | `agent_wallet` | Uses `/execution-wallet` + `/execute`; owner `userDid` comes from login config. |
159
161
  | BYOW signing and local custody | `self` | Keeps signing and broadcast on your wallet path. |
160
- | Managed delegated execution | `thirdfy` | Uses delegated governance rail for hosted execution. |
162
+ | External wallet delegated execution | `hybrid` or `thirdfy` after `delegation create/activate` | Uses Gator/ERC-7710 authority from the user wallet to the Thirdfy/session executor. |
163
+ | Publisher fan-out / subscriber execution | `thirdfy` | Uses delegated governance rail and active `delegation_bindings`. |
161
164
  | Self execution plus governance mirror checks | `hybrid` | Preserves local execution while emitting managed-lane mirrors. |
162
165
  | Managed wallet primary + governance mirror checks | `hybrid --hybrid-wallet-mode agent_wallet` | Uses managed wallet as primary hybrid path while still running Thirdfy mirror checks. |
163
166
 
@@ -166,7 +169,7 @@ Auth expectations by mode:
166
169
  - `self`: requires execution identity (`agentApiKey`) today; keyless self lane is blocked with deterministic `SELF_OPEN_DISABLED`.
167
170
  - `hybrid`: requires execution identity and governed mirror semantics (`--hybrid-wallet-mode self|agent_wallet`, default `self`).
168
171
  - `thirdfy`: requires execution identity and delegated governance path.
169
- - `agent_wallet`: requires execution identity and delegated managed-wallet path.
172
+ - `agent_wallet`: requires execution identity and owner `userDid`, but does not require subscriber delegation when the owner identity matches the agent wallet/creator.
170
173
  - custody mode defaults are profile-aware:
171
174
  - `managed` default for `thirdfy`
172
175
  - `external` default for `self` and `hybrid`
@@ -177,7 +180,7 @@ Selection precedence:
177
180
  1. `--run-mode`
178
181
  2. `THIRDFY_RUN_MODE`
179
182
  3. saved profile config (`~/.thirdfy/config.json`)
180
- 4. profile default
183
+ 4. profile default (`personal=agent_wallet`, `builder=hybrid`, `network=thirdfy`)
181
184
 
182
185
  Profile commands:
183
186
 
@@ -189,6 +192,16 @@ thirdfy-agent whoami --json
189
192
 
190
193
  `profile use --profile <name>` resets run mode to that profile default unless `--run-mode` is explicitly provided.
191
194
 
195
+ ## Framework Guidance
196
+
197
+ Use the same execution identities across frameworks, but choose the rail by who signs and who the agent acts for:
198
+
199
+ - **Hermes agents:** provision the Thirdfy profile and env before the Hermes dashboard/runtime starts, run `thirdfy-agent doctor auth` and `doctor self` during startup checks, prefer `agent_wallet` for the agent’s own managed wallet, and keep `thirdfy` for publisher/fanout or delegated external-wallet execution.
200
+ - **OpenClaw agents:** store Thirdfy credentials as runtime secrets, call `thirdfy-agent actions --provider <id>` before planning, use `run --run-mode agent_wallet` for own-wallet actions, use `self` only when OWS/local signing is configured, and switch to `hybrid`/`thirdfy` only after delegation readiness is confirmed.
201
+ - **Claude Managed Agents:** prefer MCP `agentRun` / `walletExecute` for solo managed execution, `buildTx` / `walletSign` for BYOW local signing, and `executeIntent` only for subscriber fanout or explicit validation-only mirror previews. The CLI remains useful for smoke checks and local operator recovery.
202
+
203
+ For all frameworks, treat `agentApiKey` as a hidden execution credential in secret storage, keep owner-session tokens short lived, and verify mode requirements with `thirdfy-agent help onboarding --json`.
204
+
192
205
  ### One-command self execution (BYOW)
193
206
 
194
207
  Use `--broadcast` with `run --run-mode self` to keep one deterministic command for build/sign/send:
@@ -400,7 +413,7 @@ Managed-self execution performs strict wallet preflight and returns deterministi
400
413
  ## More docs
401
414
 
402
415
  - OpenClaw CLI onboarding flow:
403
- [docs.thirdfy.com/api/thirdfy-agent-cli#create-an-openclaw-agent-with-the-cli](https://docs.thirdfy.com/api/thirdfy-agent-cli#create-an-openclaw-agent-with-the-cli)
416
+ [docs.thirdfy.com/documentation/api/thirdfy-agent-cli#create-an-openclaw-agent-with-the-cli](https://docs.thirdfy.com/documentation/api/thirdfy-agent-cli#create-an-openclaw-agent-with-the-cli)
404
417
  - Creator platform (agent registration and keys):
405
418
  [thirdfy.com/creator](https://thirdfy.com/creator)
406
419
 
@@ -416,7 +429,7 @@ npm run e2e:managed:delegation:parity
416
429
 
417
430
  ## Release
418
431
 
419
- Version history and user-facing notes: [CHANGELOG.md](./CHANGELOG.md) (for example [v0.1.38](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.38) — npm README + lockfile metadata alignment; [v0.1.37](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.37) — email OTP login, onboarding help, auth doctor, wallet list, masked `whoami`). **Before every version bump or npm publish:** update this **README** (release notes paragraph, quick start, and command groups) so the npm package page matches what ships; keep `CHANGELOG.md`, [command reference](./docs/command-reference.md), and MCP summaries aligned when discovery or onboarding surfaces change.
432
+ Version history and user-facing notes: [CHANGELOG.md](./CHANGELOG.md) (for example [v0.1.39](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.39) — agent-wallet solo default, framework guidance, and delegation UX; [v0.1.38](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.38) — npm README + lockfile metadata alignment; [v0.1.37](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.37) — email OTP login, onboarding help, auth doctor, wallet list, masked `whoami`). **Before every version bump or npm publish:** update this **README** (release notes paragraph, quick start, and command groups) so the npm package page matches what ships; keep `CHANGELOG.md`, [command reference](./docs/command-reference.md), and MCP summaries aligned when discovery or onboarding surfaces change.
420
433
 
421
434
  ```bash
422
435
  npm version patch
@@ -43,7 +43,7 @@ const CUSTODY_MODES = ['managed', 'external'];
43
43
  const EFFECT_CHECK_MODES = ['strict', 'relaxed', 'off'];
44
44
  let negotiatedCapabilitiesCache = null;
45
45
  const PROFILE_DEFAULTS = {
46
- personal: 'self',
46
+ personal: 'agent_wallet',
47
47
  builder: 'hybrid',
48
48
  network: 'thirdfy',
49
49
  };
@@ -113,6 +113,43 @@ function buildTopLevelOnboardingHint(payload) {
113
113
  return null;
114
114
  }
115
115
 
116
+ function extractAgentApiKey(value) {
117
+ if (!value || typeof value !== 'object') return '';
118
+ const candidates = [
119
+ value.agentApiKey,
120
+ value.apiKey,
121
+ value.data?.agentApiKey,
122
+ value.data?.apiKey,
123
+ value.bootstrap?.agentApiKey,
124
+ value.bootstrap?.apiKey,
125
+ value.registration?.agentApiKey,
126
+ value.registration?.apiKey,
127
+ value.registration?.registration?.agentApiKey,
128
+ value.registration?.registration?.apiKey,
129
+ value.data?.registration?.agentApiKey,
130
+ value.data?.registration?.apiKey,
131
+ value.data?.registration?.registration?.agentApiKey,
132
+ value.data?.registration?.registration?.apiKey,
133
+ ];
134
+ return String(candidates.find((candidate) => String(candidate || '').trim()) || '').trim();
135
+ }
136
+
137
+ function extractAgentKey(value) {
138
+ if (!value || typeof value !== 'object') return '';
139
+ const candidates = [
140
+ value.agentKey,
141
+ value.data?.agentKey,
142
+ value.bootstrap?.agentKey,
143
+ value.registration?.agentKey,
144
+ value.registration?.registration?.agentKey,
145
+ value.data?.registration?.agentKey,
146
+ value.data?.registration?.registration?.agentKey,
147
+ value.owner?.creatorWallet,
148
+ value.data?.owner?.creatorWallet,
149
+ ];
150
+ return String(candidates.find((candidate) => String(candidate || '').trim()) || '').trim();
151
+ }
152
+
116
153
  async function main() {
117
154
  const profileState = resolveProfileState(globalFlags);
118
155
  context.profile = profileState.profile;
@@ -224,6 +261,7 @@ async function main() {
224
261
  await commandTrackAction(context, subFlags, capabilities);
225
262
  return;
226
263
  case 'delegation create':
264
+ case 'delegation grant':
227
265
  await commandDelegationCreate(context, subFlags, capabilities);
228
266
  return;
229
267
  case 'delegation init-custodial':
@@ -1432,7 +1470,17 @@ async function commandDelegationCreate(ctx, flags, capabilities) {
1432
1470
  success,
1433
1471
  code: success ? 'DELEGATION_CREATED' : 'DELEGATION_CREATE_FAILED',
1434
1472
  message: response?.message || (success ? 'Delegation payload created' : 'Delegation create failed'),
1435
- data: response,
1473
+ data: {
1474
+ ...response,
1475
+ delegationModel: 'gator_erc7710',
1476
+ nextSteps: success
1477
+ ? [
1478
+ 'Sign data.delegation with the external wallet or OWS account that owns --owner-address.',
1479
+ 'Run `thirdfy-agent delegation activate --agent-key <key> --wallet-address <owner> --session-account-address <delegate> --delegation-manager <manager> --delegation <json> --signature <hex>`.',
1480
+ 'Verify with `thirdfy-agent delegation inspect --agent-key <key> --verify`, then use `delegation redeem` or run with --run-mode hybrid|thirdfy for delegated execution.',
1481
+ ]
1482
+ : [],
1483
+ },
1436
1484
  meta: {
1437
1485
  apiBase: ctx.apiBase,
1438
1486
  capabilitiesVersion: capabilities?.contractVersion || null,
@@ -1533,7 +1581,16 @@ async function commandDelegationActivate(ctx, flags, capabilities) {
1533
1581
  success,
1534
1582
  code: success ? 'DELEGATION_ACTIVATED' : 'DELEGATION_ACTIVATE_FAILED',
1535
1583
  message: response?.message || (success ? 'Delegation activated' : 'Delegation activate failed'),
1536
- data: response,
1584
+ data: {
1585
+ ...response,
1586
+ delegationModel: 'gator_erc7710',
1587
+ nextSteps: success
1588
+ ? [
1589
+ 'Run `thirdfy-agent delegation inspect --agent-key <key> --verify` to confirm period allowance and revocation state.',
1590
+ 'Use `thirdfy-agent delegation redeem --run-mode hybrid|thirdfy ...` when Thirdfy/session executor should act under this external-wallet delegation.',
1591
+ ]
1592
+ : [],
1593
+ },
1537
1594
  meta: {
1538
1595
  apiBase: ctx.apiBase,
1539
1596
  capabilitiesVersion: capabilities?.contractVersion || null,
@@ -1854,6 +1911,8 @@ async function commandDeveloperBootstrap(ctx, flags, capabilities) {
1854
1911
  { ...registerFlags, __suppressOutput: true },
1855
1912
  capabilities
1856
1913
  );
1914
+ const agentApiKey = extractAgentApiKey(registerResponse || {});
1915
+ const responseAgentKey = extractAgentKey(registerResponse || {}) || agentKey;
1857
1916
 
1858
1917
  const config = loadProfileConfig();
1859
1918
  const next = {
@@ -1870,6 +1929,13 @@ async function commandDeveloperBootstrap(ctx, flags, capabilities) {
1870
1929
  bootstrapCompletedAt: new Date().toISOString(),
1871
1930
  },
1872
1931
  };
1932
+ if (agentApiKey || responseAgentKey) {
1933
+ next.agent = {
1934
+ ...(config.agent && typeof config.agent === 'object' ? config.agent : {}),
1935
+ ...(agentApiKey ? { apiKey: agentApiKey } : {}),
1936
+ ...(responseAgentKey ? { agentKey: responseAgentKey } : {}),
1937
+ };
1938
+ }
1873
1939
  persistProfileConfig(next);
1874
1940
  if (!flags.__suppressOutput) {
1875
1941
  printEnvelope({
@@ -2134,6 +2200,19 @@ async function commandBootstrapComplete(ctx, flags, capabilities) {
2134
2200
  capabilities
2135
2201
  );
2136
2202
  }
2203
+ const registrationAgentApiKey = extractAgentApiKey(registration || {});
2204
+ const registrationAgentKey = extractAgentKey(registration || {}) || agentKey;
2205
+ if (registrationAgentApiKey || registrationAgentKey) {
2206
+ const latest = loadProfileConfig();
2207
+ persistProfileConfig({
2208
+ ...latest,
2209
+ agent: {
2210
+ ...(latest.agent && typeof latest.agent === 'object' ? latest.agent : {}),
2211
+ ...(registrationAgentApiKey ? { apiKey: registrationAgentApiKey } : {}),
2212
+ ...(registrationAgentKey ? { agentKey: registrationAgentKey } : {}),
2213
+ },
2214
+ });
2215
+ }
2137
2216
 
2138
2217
  printEnvelope({
2139
2218
  success: true,
@@ -2434,8 +2513,8 @@ async function commandProfileShow(ctx, _flags) {
2434
2513
  message: 'Profile configuration loaded',
2435
2514
  data: {
2436
2515
  profile: ctx.profile || config.profile || 'personal',
2437
- runMode: ctx.runMode || config.runMode || 'thirdfy',
2438
- custodyMode: ctx.custodyMode || config.custodyMode || defaultCustodyModeForRunMode(ctx.runMode || config.runMode || 'thirdfy'),
2516
+ runMode: ctx.runMode || config.runMode || 'agent_wallet',
2517
+ custodyMode: ctx.custodyMode || config.custodyMode || defaultCustodyModeForRunMode(ctx.runMode || config.runMode || 'agent_wallet'),
2439
2518
  profileDefaults: PROFILE_DEFAULTS,
2440
2519
  configPath: getProfileConfigPath(),
2441
2520
  config,
@@ -2455,7 +2534,7 @@ function maskSecret(value) {
2455
2534
  function buildOnboardingHelp(ctx) {
2456
2535
  return {
2457
2536
  title: 'Thirdfy Agent CLI onboarding',
2458
- summary: 'Use email OTP, wallet-sign, or existing credentials to create owner auth, wallets, and agent execution credentials.',
2537
+ summary: 'Use email OTP, wallet-sign, or existing credentials to create owner auth, wallets, and hidden agent execution credentials. Fresh solo profiles default to agent_wallet.',
2459
2538
  paths: [
2460
2539
  {
2461
2540
  id: 'email_otp',
@@ -2466,6 +2545,7 @@ function buildOnboardingHelp(ctx) {
2466
2545
  'thirdfy-agent login email user@example.com --code <otp> --accept-terms --key-name "My Agent"',
2467
2546
  'thirdfy-agent whoami',
2468
2547
  'thirdfy-agent managed wallet init --chain-id 8453',
2548
+ 'thirdfy-agent preflight --run-mode agent_wallet --action <action> --params <json> --json',
2469
2549
  ],
2470
2550
  },
2471
2551
  {
@@ -2499,6 +2579,21 @@ function buildOnboardingHelp(ctx) {
2499
2579
  'thirdfy-agent login email user@example.com --code 123456 --accept-terms --ni (place --ni after the subcommand so it is not parsed as a flag value)',
2500
2580
  rule: 'Commands must fail fast instead of waiting for prompts when required input is missing.',
2501
2581
  },
2582
+ executionModes: {
2583
+ agent_wallet: 'Solo managed wallet execution through /execution-wallet + /execute; no subscriber binding when owner userDid matches.',
2584
+ self: 'BYOW/OWS local signing through build-tx, wallet sign, and wallet submit.',
2585
+ hybrid: 'Primary self or agent_wallet execution with optional Thirdfy mirror validation.',
2586
+ thirdfy: 'Publisher/fanout execute-intent; requires active subscriber/delegation bindings for writes.',
2587
+ externalDelegation: 'Use delegation create/grant -> sign -> activate -> inspect/balance -> redeem for Gator/ERC-7710 external-wallet authority.',
2588
+ },
2589
+ frameworkGuidance: {
2590
+ hermes:
2591
+ 'Hermes agents should receive a pre-provisioned Thirdfy profile/env, run doctor auth/self at startup, use agent_wallet for managed solo writes, and keep strategy logic separate from CLI secrets.',
2592
+ openclaw:
2593
+ 'OpenClaw agents should keep Thirdfy credentials in runtime secrets, use actions discovery before planning, prefer run --run-mode agent_wallet for own-wallet execution, and use thirdfy only for publisher/fanout.',
2594
+ claudeManagedAgents:
2595
+ 'Claude Managed Agents should use MCP agentRun/walletExecute for solo managed execution, walletSign/buildTx for BYOW, and executeIntent only for fanout or mirror previews.',
2596
+ },
2502
2597
  apiBase: ctx.apiBase,
2503
2598
  };
2504
2599
  }
@@ -2518,14 +2613,15 @@ async function commandWhoami(ctx, _flags) {
2518
2613
  const auth = config.auth && typeof config.auth === 'object' ? config.auth : {};
2519
2614
  const agent = config.agent && typeof config.agent === 'object' ? config.agent : {};
2520
2615
  const wallets = config.wallets && typeof config.wallets === 'object' ? config.wallets : {};
2616
+ const runMode = ctx.runMode || config.runMode || 'agent_wallet';
2521
2617
  printEnvelope({
2522
2618
  success: true,
2523
2619
  code: 'WHOAMI_OK',
2524
2620
  message: 'Thirdfy CLI identity loaded',
2525
2621
  data: {
2526
2622
  profile: ctx.profile || config.profile || 'personal',
2527
- runMode: ctx.runMode || config.runMode || 'thirdfy',
2528
- custodyMode: ctx.custodyMode || config.custodyMode || defaultCustodyModeForRunMode(ctx.runMode || config.runMode || 'thirdfy'),
2623
+ runMode,
2624
+ custodyMode: ctx.custodyMode || config.custodyMode || defaultCustodyModeForRunMode(runMode),
2529
2625
  auth: {
2530
2626
  source: auth.source || null,
2531
2627
  hasAuthToken: Boolean(auth.authToken),
@@ -2539,6 +2635,7 @@ async function commandWhoami(ctx, _flags) {
2539
2635
  agentKey: agent.agentKey || null,
2540
2636
  },
2541
2637
  wallets: {
2638
+ userDid: wallets.userDid || config.identity?.userDid || null,
2542
2639
  primaryEvmWallet: wallets.primaryEvmWallet || null,
2543
2640
  evm: Array.isArray(wallets.evm) ? wallets.evm : [],
2544
2641
  solana: Array.isArray(wallets.solana) ? wallets.solana : [],
@@ -2571,6 +2668,8 @@ async function commandDoctorAuth(ctx, _flags) {
2571
2668
  const config = loadProfileConfig();
2572
2669
  const auth = config.auth && typeof config.auth === 'object' ? config.auth : {};
2573
2670
  const agent = config.agent && typeof config.agent === 'object' ? config.agent : {};
2671
+ const runMode = normalizeRunMode(ctx.runMode || config.runMode || 'agent_wallet');
2672
+ const userDid = resolveEffectiveUserDid({});
2574
2673
  const ownerSessionTokenFromEnv = String(process.env.THIRDFY_OWNER_SESSION_TOKEN || '').trim();
2575
2674
  const authTokenFromEnv = String(process.env.THIRDFY_AUTH_TOKEN || '').trim();
2576
2675
  const agentApiKeyFromEnv = String(process.env.THIRDFY_AGENT_API_KEY || '').trim();
@@ -2598,6 +2697,14 @@ async function commandDoctorAuth(ctx, _flags) {
2598
2697
  ? 'agent API key from THIRDFY_AGENT_API_KEY'
2599
2698
  : 'not stored yet (optional until execution); complete onboarding or bootstrap to add one',
2600
2699
  },
2700
+ {
2701
+ name: 'user-did',
2702
+ optional: runMode !== 'agent_wallet',
2703
+ ok: Boolean(userDid),
2704
+ detail: userDid
2705
+ ? `user DID available (${userDid})`
2706
+ : 'missing user DID; run `thirdfy-agent login email <email>` or set THIRDFY_USER_DID',
2707
+ },
2601
2708
  {
2602
2709
  name: 'wallet-profile',
2603
2710
  ok: Boolean(config.wallets?.primaryEvmWallet || (Array.isArray(config.wallets?.evm) && config.wallets.evm.length)),
@@ -2660,7 +2767,7 @@ async function commandLogin(ctx, flags) {
2660
2767
  const current = loadProfileConfig();
2661
2768
  const authToken = String(flags.authToken || process.env.THIRDFY_AUTH_TOKEN || '').trim();
2662
2769
  let ownerSessionToken = String(flags.ownerSessionToken || process.env.THIRDFY_OWNER_SESSION_TOKEN || '').trim();
2663
- const loginRunMode = normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'thirdfy');
2770
+ const loginRunMode = normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'agent_wallet');
2664
2771
  const custodyMode = normalizeCustodyMode(
2665
2772
  flags.custodyMode || current.custodyMode || process.env.THIRDFY_CUSTODY_MODE,
2666
2773
  loginRunMode
@@ -2842,10 +2949,10 @@ async function commandLoginEmail(ctx, flags) {
2842
2949
  acceptTerms: true,
2843
2950
  keyName,
2844
2951
  agentKey: String(flags.agentKey || '').trim() || undefined,
2845
- runMode: normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'thirdfy'),
2952
+ runMode: normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'agent_wallet'),
2846
2953
  custodyMode: normalizeCustodyMode(
2847
2954
  flags.custodyMode || current.custodyMode || process.env.THIRDFY_CUSTODY_MODE,
2848
- normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'thirdfy')
2955
+ normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'agent_wallet')
2849
2956
  ),
2850
2957
  bootstrapAgent: !parseBooleanFlag(flags.noBootstrapAgent, false),
2851
2958
  rotateAgentKey: parseBooleanFlag(flags.rotateAgentKey, false),
@@ -2853,15 +2960,17 @@ async function commandLoginEmail(ctx, flags) {
2853
2960
  const data = response?.data || response || {};
2854
2961
  const ownerSessionToken = String(data.ownerSessionToken || '').trim();
2855
2962
  const bootstrap = data.bootstrap && typeof data.bootstrap === 'object' ? data.bootstrap : {};
2856
- const agentApiKey = String(bootstrap.agentApiKey || '').trim();
2857
- const agentKey = String(bootstrap.agentKey || data.owner?.creatorWallet || '').trim();
2963
+ const agentApiKey = extractAgentApiKey(data);
2964
+ const agentKey = extractAgentKey(data);
2858
2965
  const wallets = data.wallets && typeof data.wallets === 'object' ? data.wallets : {};
2966
+ const userDid = String(data.owner?.creatorDid || wallets.userDid || '').trim();
2859
2967
  const primaryEvmWallet = String(wallets.primaryEvmWallet || data.owner?.creatorWallet || '').trim();
2860
2968
  const persistedWallets = {
2861
2969
  ...wallets,
2970
+ ...(userDid ? { userDid } : {}),
2862
2971
  ...(primaryEvmWallet ? { primaryEvmWallet } : {}),
2863
2972
  };
2864
- const runMode = normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'thirdfy');
2973
+ const runMode = normalizeRunMode(flags.runMode || current.runMode || process.env.THIRDFY_RUN_MODE || 'agent_wallet');
2865
2974
  const custodyMode = normalizeCustodyMode(flags.custodyMode || current.custodyMode || process.env.THIRDFY_CUSTODY_MODE, runMode);
2866
2975
  if (!ownerSessionToken) {
2867
2976
  throw createCliError('LOGIN_EMAIL_OWNER_SESSION_MISSING', 'Email onboarding completed without an owner session token.');
@@ -3590,6 +3699,15 @@ function buildBuildTxPayload(flags, resolvedAction) {
3590
3699
  return payload;
3591
3700
  }
3592
3701
 
3702
+ function resolveEffectiveUserDid(flags) {
3703
+ const explicit = String(flags.userDid || '').trim();
3704
+ if (explicit) return explicit;
3705
+ const envUserDid = String(process.env.THIRDFY_USER_DID || '').trim();
3706
+ if (envUserDid) return envUserDid;
3707
+ const config = loadProfileConfig();
3708
+ return String(config?.wallets?.userDid || config?.identity?.userDid || '').trim();
3709
+ }
3710
+
3593
3711
  function buildManagedExecutePayload(flags, options) {
3594
3712
  const runMode = String(options.runMode || flags.runMode || 'agent_wallet').trim().toLowerCase();
3595
3713
  const params = getPreparedParams(flags);
@@ -3620,7 +3738,7 @@ function buildManagedExecutePayload(flags, options) {
3620
3738
  const payload = {
3621
3739
  agentApiKey: resolveAgentApiKey(flags, runMode),
3622
3740
  action: String(options.resolvedAction || requireFlag(flags, 'action', 'Missing --action')).trim(),
3623
- userDid: String(flags.userDid || process.env.THIRDFY_USER_DID || '').trim(),
3741
+ userDid: resolveEffectiveUserDid(flags),
3624
3742
  params: managedParams,
3625
3743
  chainId: Number(flags.chainId || 8453),
3626
3744
  executionStrategy: {
@@ -3631,7 +3749,7 @@ function buildManagedExecutePayload(flags, options) {
3631
3749
  if (!payload.userDid) {
3632
3750
  throw createCliError(
3633
3751
  'MISSING_USER_DID',
3634
- 'Managed wallet execution requires --user-did (or THIRDFY_USER_DID).'
3752
+ 'Managed wallet execution requires --user-did, THIRDFY_USER_DID, or a saved userDid from `thirdfy-agent login email`.'
3635
3753
  );
3636
3754
  }
3637
3755
  if (flags.estimatedAmountUsd) payload.estimatedAmountUsd = Number(flags.estimatedAmountUsd);
@@ -3655,13 +3773,13 @@ async function resolveManagedExecutionPreflight(ctx, flags, resolved, options =
3655
3773
  const chainId = Number(flags.chainId || 8453);
3656
3774
  const runMode = String(options.runMode || 'agent_wallet').trim().toLowerCase();
3657
3775
  const agentApiKey = resolveAgentApiKey(flags, runMode);
3658
- const userDid = String(flags.userDid || process.env.THIRDFY_USER_DID || '').trim();
3776
+ const userDid = resolveEffectiveUserDid(flags);
3659
3777
  if (!userDid) {
3660
3778
  return {
3661
3779
  success: false,
3662
3780
  blockedReason: 'MISSING_USER_DID',
3663
3781
  blockedStage: 'routing',
3664
- error: 'Managed wallet execution requires --user-did (or THIRDFY_USER_DID).',
3782
+ error: 'Managed wallet execution requires --user-did, THIRDFY_USER_DID, or a saved userDid from `thirdfy-agent login email`.',
3665
3783
  signerMethod: 'managed_wallet_server',
3666
3784
  };
3667
3785
  }
@@ -3742,8 +3860,16 @@ function buildIntentPayload(flags, options) {
3742
3860
  if (flags.catalog) payload.catalog = String(flags.catalog).trim();
3743
3861
  if (flags.chainId) payload.chainId = Number(flags.chainId);
3744
3862
  if (flags.estimatedAmountUsd) payload.estimatedAmountUsd = Number(flags.estimatedAmountUsd);
3745
- if (flags.userDid) payload.userDid = String(flags.userDid);
3863
+ const userDid = resolveEffectiveUserDid(flags);
3864
+ if (flags.userDid || (options.validationOnly && (runMode === 'agent_wallet' || (runMode === 'hybrid' && options.mirrorOnly)))) {
3865
+ if (userDid) payload.userDid = userDid;
3866
+ }
3746
3867
  if (options.validationOnly) payload.executionLane = 'validation_only';
3868
+ if (flags.executionScope) {
3869
+ payload.executionScope = String(flags.executionScope).trim();
3870
+ } else if (options.validationOnly && (runMode === 'agent_wallet' || (runMode === 'hybrid' && options.mirrorOnly))) {
3871
+ payload.executionScope = 'solo_owner_mirror';
3872
+ }
3747
3873
  if (options.runMode) {
3748
3874
  payload.executionStrategy = {
3749
3875
  runMode: String(options.runMode),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.1.38",
3
+ "version": "0.1.40",
4
4
  "description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
5
5
  "type": "module",
6
6
  "bin": {