Repository navigation
Headless hardening: fixes from the live test run - #9
Merged
Merged
Conversation
…it can't look A Vault-held token belongs to the Vault, so balanceOf(owner) is 0 and the owner lookup returned an empty list. Discovery now also scans transfers out of the wallet and keeps tokens whose Vault records this wallet as the owner. When that scan can't run and nothing was found, it fails with the RPC detail and an ETHAGENT_RPC_URL hint instead of claiming the wallet holds nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
agentURI(uint256) reverts on the Base registry, so the agent URI probe was always unknown and the custody probe never saw a mid-flow switch. The probes now read tokenURI. A differing pointer is this machine's when a pinned snapshot waits to publish and the chain's otherwise, so the manager's "Newer snapshot onchain" banner can finally appear. Mid-flow custody comes from local state (token in the Vault, Advanced not saved here), not from URI drift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
The operator path never pulled the tools' edits and would pin and send a transaction with nothing changed. It now pulls first, skips like save does, and reads the token back after publishing to report verification. The no-changes check, the read-back, and the JSON envelope live in one helper both saves use, and both now print schema: 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
Status and stopDaemon trusted any live pid, so a pid the system had reused read as the sync daemon and could be sent SIGTERM. The daemon now touches its pid file every 30 seconds, and only a pid that is alive and beat within two minutes counts as running or gets signalled; a stale file is cleared. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
The deferred host-stats write was asynchronous, so a command ending with process.exit could cut it off after the temp file was written and before the rename. Every write is now synchronous (the file is small), and the first load sweeps temp files older than a minute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
Only the parent's manager can remove a subname, and when that is the agent's operator key the delete had no headless signer. It may now sign with --operator; the preflight still refuses any key that doesn't manage the parent, and publishing the unlinked agent still takes the owner wallet. When the browser wallet isn't the parent's manager but the operator key is, the hint says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
…ts key With no operator key in the shell, the read view reported operator: null, which read as no operator at all. It now checks the identity's active operator against the name's control and marks keyAvailable: false. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
…or ENS delete Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
baairon
added a commit
that referenced
this pull request
Oct 7, 2026
- The heartbeat from #9 read a watcher that never touches its pid file as gone. That is every watcher started before #9, including 5.3.2's: status deleted its pid file, ensureDaemon started a second watcher beside it, and pause could not stop it. - A pid that is alive but not beating is the daemon when its process is an ethagent watcher by its command line (/proc on Linux, ps on macOS, PowerShell on Windows). Any other live pid is still treated as recycled and is never signalled. - A starting watcher stops such a watcher and takes the pid file only once that process is gone. A beating watcher is left in place. - The heartbeat makes a watcher exit when sync is paused or another live process holds the pid file, and a watcher removes the pid file only while it is still its own. - daemonStatus no longer deletes the pid file, so status is read-only again.
baairon
added a commit
that referenced
this pull request
Oct 7, 2026
* wip: chain suite on local anvil chains Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw * fix: transfer runs in the command's wallet tab The signing step opened a second browser session of its own, the one command that bypassed its wallet tab. It now takes the command's session when given one, as create and the custody steps do; the manager still opens its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw * test: chain suite walks an agent's whole life on local anvil chains npm run test:chain starts a Mainnet and a Base anvil, places stand-in registry and ENS contracts at the real addresses, serves IPFS from the runner, and runs every --yes path in order with a test wallet in place of the browser: create, profile, ENS link, records and delete, Advanced custody with the operator key, an operator save, check, restore on a fresh machine and by owner lookup, Simple custody, and a transfer the receiver restores. Every step is checked against chain state, and nothing can reach a public host. CI runs it as its own job. Along the way: ETHAGENT_ENS_RPC_URL for ENS reads and writes, and saves with ETHAGENT_IPFS_API_URL no longer demand a Pinata JWT they never use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw * fix(test): Base test chain genesis names every fork and a base fee CI's Anvil read the bare genesis as pre-London and refused EIP-1559 transactions, so create failed and every later step had no agent. The genesis now activates every fork through Cancun from block 0 with a base fee, and CI pins Foundry to the version the suite was run with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw * fix: an older or stalled daemon is taken over instead of duplicated - The heartbeat from #9 read a watcher that never touches its pid file as gone. That is every watcher started before #9, including 5.3.2's: status deleted its pid file, ensureDaemon started a second watcher beside it, and pause could not stop it. - A pid that is alive but not beating is the daemon when its process is an ethagent watcher by its command line (/proc on Linux, ps on macOS, PowerShell on Windows). Any other live pid is still treated as recycled and is never signalled. - A starting watcher stops such a watcher and takes the pid file only once that process is gone. A beating watcher is left in place. - The heartbeat makes a watcher exit when sync is paused or another live process holds the pid file, and a watcher removes the pid file only while it is still its own. - daemonStatus no longer deletes the pid file, so status is read-only again. --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes from running the full test plan against the live agent on Base. Most of them are places that said "all fine" without having looked. One commit per fix.
restore --ownerfinds Vault-held agents.balanceOf(owner)is 0 and the lookup returnedagents: [].ETHAGENT_RPC_URLhint, instead of an empty list.checkand the manager readtokenURI.agentURI(uint256)reverts on the registry, so the URI probe was alwaysunknownand mid-flow custody never fired.local-newerwhen a pinned snapshot is waiting,chain-newerotherwise. The manager's "Newer snapshot onchain" banner can appear again.save --operatormatchessave.verification.schema: 1.daemon.pid.hosts.json.*.tmpleftovers. Host-stats writes are synchronous, soprocess.exitcan't cut them off. Stale temp files are swept on load.ens --delete --operator.--operatorwhen that is the parent's manager.enswithout a key in the shell reports whether the active operator could sign (keyAvailable: false), instead ofoperator: null.Docs: README (restore
--owner, save verification, the operator delete rule) andcommands/ethagent.md.Testing
npm run typecheckandnpm test(775 pass) in a clean env.--ownererror and hint;tokenURI,local-newervschain-newer, mid-flow;operator-save: pull, skip, verify, exit 3;ens --delete --operator, and the keyless operator view.restore --ownerin a temp HOME with no reachable RPC exits 1 with the detail and the hint, and leaves no temp files.To re-check after merge:
restore --owner <owner> --network base --jsonlists #45744;check --jsonreports a realchain.agentUri;ens --jsonshows the operator withoutkeychain exec;keychain operator-savewith no edits reports skipped and sends nothing.🤖 Generated with Claude Code
https://claude.ai/code/session_01HG2miyE22qTuug1Quxj7iw
Generated by Claude Code