Repository navigation
feat(agent): select a delegated identity for hook recording - #219
Merged
Merged
Conversation
`atomic agent identity set <name>` makes every hooked agent on this
machine record under a delegated identity's own key instead of the
plus-tag of the default identity. The selection is global — one
identity per machine, deliberately not per repository — written to a
new top-level `agent_identity` in ~/.atomic/config.toml.
Hooks resolve the identity on every invocation:
ATOMIC_AGENT_IDENTITY env var
> global agent_identity setting
> active server profile's agent_identity binding
> plus-tag fallback
The server-profile link closes a promise that was already written down:
`bind_agent_identity` documents the binding as "so hooks use it by
default", but only push auth ever read it — recording never did.
`set` validates eagerly (the identity must resolve and be an
agent/delegated type; human identities are refused; a missing delegation
certificate warns) while the record path degrades softly on a bad name
— recording a turn must never fail over identity selection. `show` and
`agent status` (human + JSON) report the effective identity and its
source. With nothing configured anywhere, recorded turns are
indistinguishable from before, and `atomic record` is untouched.
atomic-agent never reads config: the resolved name crosses as plain
data through TurnRecordOptions into build_agent_author and
active_delegation_urn, so change headers carry the agent's public key
and envelopes name the active delegation certificate.
cargo fmt across the touched crates, and the `key()` doc comment linked to `Self::fmt` — a trait impl method rustdoc cannot resolve — which failed the Documentation job under -Dwarnings.
Every test in database_owner_integration_test spawns real atomic subprocesses that hold the redb lock and burn CPU. On 2-core Windows CI runners, the default test-threads parallelism lets the process-heavy tests (the eight-process session-start hammer, the failpoint owners) starve whichever sibling tests overlap them past their database-wait budgets. The failure signature is exactly that: different tests fail on different runs — concurrent_session_starts…, crashing_second_checkpoint…, owner_death_after_checkpoint_prepare… in this PR's runs; concurrent_stops_publish… on another PR the same day — all in this file, all contention-shaped (one with an explicit 'Database already open. Cannot acquire lock'), while macOS and ubuntu pass the same suite. #[serial] trades a few minutes of wall time for runs that only fail when something is actually broken. Locally the serialized suite passes in 53s (macOS); CI is the only place the starvation reproduced.
graywolf336
approved these changes
Sep 25, 2026
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.
What
atomic agent identity set <name>makes every hooked agent on this machine record turns under a delegated identity's own key instead of the plus-tag of the default identity. One identity per machine — deliberately not per repository — persisted to a new top-levelagent_identityin~/.atomic/config.toml.New command tree under
atomic agent identity:set <name>— validates eagerly: the identity must resolve in the store and be an agent/delegated type (human identities are refused — signing agent work with the human's key is worse than the honest plus-tag), and a missing delegation certificate prints a warning.unset— clears the selection; hooks go back to the plus-tag path.show— the effective identity, its source, email, key, and active delegation URN — the same resolution the hooks run.Resolution order (per hook invocation)
The server-profile link closes a promise already written down:
bind_agent_identitydocuments its binding as "so hooks use it by default", but only push auth ever read it — the recording path never did. Now creating an agent identity makes hooks use it with zero extra steps, and the global setting overrides it.Design invariants
atomic recorduntouched: the human path keeps using the default identity.set, soft fallback lives in the record path.TurnRecordOptions.agent_identityintobuild_agent_authorandactive_delegation_urn, so change headers carry the agent's public key and envelopes name the active delegation certificate.Also
atomic agent statusshows the effective identity in human output and asagent_identity: {name, source}in--json(stable source keys:env,global,server-profile).Testing
cargo test -p atomic-config -p atomic-agent -p atomic-cli— all pass (1,356 / 1,927 / 28), including new unit tests for the resolution order, blank-value skipping, keyed-attribution threading, and never-fail fallback.IdentityNotFound, env var precedence over the global setting, status human + JSON output.