Repository navigation
feat: share one state dir between the terminal agent and the desktop app (ATO-416) - #673
Merged
Merged
Conversation
…sion registry (ATO-416) The desktop app and the terminal agent now share one state dir. The desktop registers its own live-session marker and spawns every atag with ATOMIC_AGENT_SESSION_PARENT_PID; hasOtherLiveSessions treats that parent's marker like the caller's own, so an atag the desktop runs no longer sees the desktop as another app still using the model. A dead parent's marker is reclaimed as before, and a malformed value is ignored. The marker format the desktop mirrors is documented in the module comment.
…set - --expect-sha256 (ATO-416)
The desktop app and the terminal agent now share one state dir, so both
write the same config.json, and a client that writes back a copy it read
earlier silently reverts the other's change.
config get --with-sha256 prints {"sha256", "config"}: the normalised
config and the sha256 of the raw file bytes it came from, from one read
(the empty-string hash when there is no file). config set - --expect-sha256
<hex> writes only while the file still hashes to <hex>; otherwise it
writes nothing, prints "config changed since it was read" to stderr and
exits 3. The hash is checked before the analytics opt-out report and again
right before the write. Without the flag set - is unchanged.
…state dir (ATO-416) The desktop's atag serve and the TUI now share one state dir, each with a scheduler. Claiming kept a task from running twice, but it could run in the process without the Telegram bot, where its report had no channel. Interval ticks now drain only in the leader. When this process wants Telegram (a token and the channel not disabled), the live holder of <stateDir>/telegram.lock leads and also takes scheduler.lock; a process that lost the bot stands by and gives scheduler.lock up. Otherwise, or while nobody holds telegram.lock (a reconnect gap), the holder of <stateDir>/scheduler.lock leads, with the TelegramLockfile take-over: others wait and take over when the holder exits or its pid is dead. Leadership is re-checked every tick and released on stop after the drain. A single process always leads; an explicit tickOnce is not gated; a lock that cannot be created fails open.
The desktop's bundled atag can be older than the TUI sharing its state dir. Once the TUI has migrated config.json, config get reports that newer version and the desktop sends it back unchanged, which config set - refused as newer than this build understands, blocking every desktop save. Refuse a payload version only when it is newer than both this build's schema version and the version currently on disk; the write already keeps the on-disk version.
…oryStore.hasContent Seams for merging another state dir's databases (ATO-416): - SessionStore.insertMissing copies sessions keeping their ids with INSERT OR IGNORE, so a stored row wins. No turn_owner is written and a live status is ended as an interrupted turn. - TaskStore.insertMissing does the same for tasks. No run_owner is written and a running task arrives pending with no started_at, as the boot sweep would put it back. - MemoryStore.hasContent answers exact-content dedup for the whole store, which list() cannot past MEMORY_LIST_MAX_LIMIT rows. Each insert batch is one BEGIN IMMEDIATE transaction so it waits on a concurrent TUI or serve instead of failing on a lock upgrade.
atag import atomic-desktop --source <dir> [--json] merges the desktop app's former state dir into ATOMIC_AGENT_STATE_DIR (ATO-416). The desktop moves the plain files itself; this handles the databases: - sessions and tasks by id, target wins on the same id, live turns and running tasks arrive ended / pending with no owner marks - memory notes through MemoryStore with exact-content dedup, keeping tags, session, working dir, source and timestamp - profile facts through ProfileStore, skipped when the target has any row for the key - lessons, procedures, votes, note links and embeddings are not copied Each source database is read from a private snapshot: a byte copy after a clean close, SQLite's online backup over a read-only connection when a -wal is present. The source is never written. Parts run independently, a re-run imports nothing new, and --json prints one object with per-part imported/skipped counts, warnings and error on failure.
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.
The desktop app is moving onto the terminal agent's own state dir,
~/.atomic-agent, so both share chats, memory, skills, keys and settings (ATO-416). Until now the desktop kept a separate~/.atomic-agent-desktop, and a user who set the agent up in the terminal found an empty desktop. This PR is the agent side: what the core needs so that two processes can safely run on one state dir, and an importer for the desktop's old data.What changes
ATOMIC_AGENT_SESSION_PARENT_PID=<pid>treats that pid's session marker as its own. The desktop registers one marker for itself and itsatagchildren, so quitting the terminal does not stop a local model the desktop is still using, and the other way round.atag config get --with-sha256prints{"sha256": "<hex>", "config": {...}}from a single read.atag config set - --expect-sha256 <hex>writes only whileconfig.jsonstill has that hash. Otherwise it writes nothing, printsconfig changed since it was readand exits 3.<stateDir>/scheduler.lock. Claiming a task stays atomic, as before.config set -now accepts a payload whose version equals the version already on disk, even when it is newer than the build. Before, a desktop with an older bundled agent could not save any setting after the terminal had been updated. Nested keys from a newer schema can still be lost in that case; that is tracked separately (ATO-417).atag import atomic-desktop --source <dir> [--json]merges the desktop's former state dir into the current one:SessionStore.insertMissing,TaskStore.insertMissingandMemoryStore.hasContent.Checks
On the MacBook Pro:
docs:check,imports:checkandtypecheck:testsall clean;~/.atomic-agent-desktopinto~/.atomic-agentthere: 39 chats, 1 task, 8 notes and 5 profile facts were imported, with no duplicates and no warnings.The desktop side is in a separate PR into
rel/xp-build.