pub struct LoopCtx {Show 48 fields
pub config: Config,
pub model_name: String,
pub agent: AgentClient,
pub runtime_factory: AgentRuntimeFactory,
pub bg_manager: BgRuntimeManager,
pub foreground_runtime_id: RuntimeId,
pub runtime_event_tx: UnboundedSender<RuntimeEvent>,
pub runtime_event_rx: UnboundedReceiver<RuntimeEvent>,
pub working_dir: PathBuf,
pub previous_dir: Option<PathBuf>,
pub recent_dirs: Vec<PathBuf>,
pub history: History,
pub input_rx: UnboundedReceiver<InputEvent>,
pub commands: CommandRegistry,
pub session_manager: SessionManager,
pub current_session: Session,
pub update_hint: Arc<Mutex<Option<String>>>,
pub monitor_warning: Arc<Mutex<Option<CodingPlanWarning>>>,
pub monitor_last_check_at: Option<Instant>,
pub usage_slot: Arc<Mutex<Option<UsageInfo>>>,
pub usage_last_check_at: Option<Instant>,
pub monitor_last_sync_seen: Option<SystemTime>,
pub wake_rx: Receiver<()>,
pub wake_tx: Sender<()>,
pub oauth_event_rx: UnboundedReceiver<OauthEvent>,
pub oauth_event_tx: UnboundedSender<OauthEvent>,
pub reader: Option<ReaderHandle>,
pub upgrade_tx: UnboundedSender<UpgradeEvent>,
pub upgrade_rx: UnboundedReceiver<UpgradeEvent>,
pub plugin_job_tx: UnboundedSender<PluginJobEvent>,
pub plugin_job_rx: UnboundedReceiver<PluginJobEvent>,
pub pending_new_issue: Option<NewIssueDraft>,
pub pending_run_codingplan: bool,
pub pending_open_provider_wizard: bool,
pub mcp_registry: Option<Arc<McpRegistry>>,
pub mcp_connect_rx: Option<UnboundedReceiver<McpConnectEvent>>,
pub mcp_reload: Option<McpReloadProgress>,
pub lsp_connect_rx: Option<UnboundedReceiver<LspConnectEvent>>,
pub telemetry: Arc<Telemetry>,
pub worktree_original_dir: Option<PathBuf>,
pub custom_commands: CustomCommandRegistry,
pub skill_registry: Arc<RwLock<SkillRegistry>>,
pub caps: TerminalCaps,
pub replay_on_start: Option<Session>,
pub file_index: FileIndex,
pub current_session_id: Option<SessionId>,
pub clipboard_check: Arc<Mutex<ClipboardCheckState>>,
pub is_plain_renderer: bool,
}Expand description
Bag of handles passed into the loop.
Fields§
§config: Config§model_name: String§agent: AgentClient§runtime_factory: AgentRuntimeFactory§bg_manager: BgRuntimeManager§foreground_runtime_id: RuntimeId§runtime_event_tx: UnboundedSender<RuntimeEvent>§runtime_event_rx: UnboundedReceiver<RuntimeEvent>§working_dir: PathBuf§previous_dir: Option<PathBuf>§recent_dirs: Vec<PathBuf>Recently visited project directories, most recent first (max 5).
Persisted to ~/.atomcode/recent_dirs.txt. Drives the /cd
picker when invoked with no argument and is updated whenever
the working directory changes (via slash command or agent tool).
history: History§input_rx: UnboundedReceiver<InputEvent>§commands: CommandRegistry§session_manager: SessionManager§current_session: SessionSession actively being accumulated. Updated on TurnComplete /
TurnCancelled (both carry the latest messages slice), saved to
disk via session_manager on the same events so /resume after
a quit sees the conversation. Replaced wholesale when the user
resumes another session via /resume + SessionPicker.
update_hint: Arc<Mutex<Option<String>>>Shared “new version available” hint. Populated by the detached
version-check task spawned from run(); read by build_status
on each redraw. None = no hint (either check still pending,
network failed silently, or already up to date).
monitor_warning: Arc<Mutex<Option<CodingPlanWarning>>>Shared CodingPlan drift-monitor warning slot. Written by the
detached check task (see monitor::spawn_check); read by
build_status on each redraw. Takes precedence over update_hint
so a drift warning isn’t buried by an upgrade banner. Cleared
when /codingplan persists a fresh config (re-sync resets the
hint state).
monitor_last_check_at: Option<Instant>Last time a monitor check was fired this session. Pre-turn
triggers respect monitor::CHECK_COOLDOWN (15 min) against this
timestamp; startup + /model switch bypass the cooldown.
None = no check has run yet this session.
usage_slot: Arc<Mutex<Option<UsageInfo>>>CodingPlan token-usage snapshot. Populated by
usage_monitor::spawn_check at startup and after each
TurnComplete (30s cooldown). Read on every redraw to construct
the right-aligned usage hint when usage_percent ≥ 80% and the
current model is on a CodingPlan provider.
usage_last_check_at: Option<Instant>Last time usage_monitor::spawn_check was invoked. Used to
enforce usage_monitor::USAGE_COOLDOWN on TurnComplete-triggered
refreshes. None = no check has run yet this session.
monitor_last_sync_seen: Option<SystemTime>Last-observed timestamp from the shared CodingPlan sync marker
(~/.atomcode/codingplan_sync.json). On every user input we
re-read it; a change means ANOTHER atomcode process (e.g. a
second terminal) just ran /codingplan and the server is now
in sync with the on-disk config. We then hot-reload config
from disk + clear the stale drift warning. Without this,
Terminal A’s “CodingPlan 模型列表更新” hint would stick forever
after Terminal B ran the fix.
wake_rx: Receiver<()>Wake signal from background tasks (version check + CodingPlan
drift monitor). One () sent when any task needs the event loop
to repaint so a freshly-computed hint/warning appears without
waiting for the user’s next keystroke. Bounded at 1 — overlapping
wakes coalesce since the redraw is idempotent.
wake_tx: Sender<()>Sender side of wake_rx. Cloned into every spawned check task
so /model switches, pre-turn triggers, and the like can wake
the event loop after updating monitor_warning.
oauth_event_rx: UnboundedReceiver<OauthEvent>Receiver for OauthEvents emitted by the QR-fast-path onboarding
poll thread (see event_loop::oauth_poll). One event arrives
per spawned poll task (Authorized or Failed). The tokio::select!
arm that reads this channel closes the wizard modal + flips
pending_run_codingplan on Authorized, or surfaces the failure
reason in scrollback on Failed.
oauth_event_tx: UnboundedSender<OauthEvent>Sender cloned into each spawned poll task.
reader: Option<ReaderHandle>Control handle for the crossterm reader thread — Some in raw-mode
TTY sessions, None in pipe mode. Used by child-process handoffs
(OAuth login, future /shell) to pause+resume event consumption
so our reader doesn’t race the child for stdin bytes.
upgrade_tx: UnboundedSender<UpgradeEvent>Sender used by /upgrade to report streaming progress/failure
events from the detached upgrade task. Cloned into the task at
spawn time; kept here so the receiver in the loop outlives any
number of upgrades (no reconstructing on each invocation).
upgrade_rx: UnboundedReceiver<UpgradeEvent>Consumed in the main select! so upgrade progress is rendered
alongside agent events.
plugin_job_tx: UnboundedSender<PluginJobEvent>Long-lived channel for /plugin marketplace add|update and /plugin
install. Each invocation spawns a blocking task that does the git
clone/pull and pushes a PluginJobEvent here when done. Mirrors the
upgrade_tx/rx layout so the event loop only has to add a single
select! arm. Unbounded — events are tiny terminal results.
plugin_job_rx: UnboundedReceiver<PluginJobEvent>§pending_new_issue: Option<NewIssueDraft>Signal channel from the /issue wizard modal back to the event
loop. The wizard’s Enter handler can’t touch App directly
(modals only see LoopCtx), so it stores the collected title +
body here, returns Close, and the event loop’s post-close
branch POSTs the issue to AtomGit and echoes the URL of the
newly-created issue back into the conversation.
pending_run_codingplan: boolSet by OnboardingWizard (step 3, Setup) when the user picks
option 0 (Set up CodingPlan). The event loop drains this on
modal close and runs the full CodingPlan setup flow (login if
needed → claim → fetch models → register providers). Needs
raw-mode suspend/resume, something modals can’t drive
themselves. Same pattern as pending_new_issue.
pending_open_provider_wizard: boolSet by OnboardingWizard (step 3, Setup) when the user picks
option 1 (Configure manually). The event loop drains this on
modal close and swaps in ProviderWizard::MainMenu — a
Modal-to-Modal transition that needs mutable active_modal
access only the event loop has.
mcp_registry: Option<Arc<McpRegistry>>MCP server registry for /mcp status display. None when no MCP
servers are configured or all failed to connect.
mcp_connect_rx: Option<UnboundedReceiver<McpConnectEvent>>Channel for receiving MCP connection status events (Connected/Failed). Events are rendered into scrollback as they arrive during startup.
mcp_reload: Option<McpReloadProgress>When /mcp reload is invoked, we track progress until every configured
server reports Connected/Failed, then emit a one-line summary.
lsp_connect_rx: Option<UnboundedReceiver<LspConnectEvent>>Channel for receiving LSP connection status events (Started / Failed
/ Warning). Same plumbing as mcp_connect_rx — wired in TUI mode
so the manager’s start failures land in scrollback as ✗ LSP server 'rust-analyzer' for .rs failed: ... instead of leaking to stderr
and printing inside the input box.
telemetry: Arc<Telemetry>Telemetry handle — used to emit UseCommand at each slash dispatch.
worktree_original_dir: Option<PathBuf>Original working dir before /worktree create, for /worktree done.
custom_commands: CustomCommandRegistryUser-defined custom commands loaded from ~/.atomcode/commands/ and
<project>/.atomcode/commands/. Queried by the slash-command
dispatcher as a fallback when the entered name doesn’t match a
built-in command.
skill_registry: Arc<RwLock<SkillRegistry>>Loaded skills (.claude/skills/*/SKILL.md, etc.). Same Arc
the agent loop holds, so reload(...) there is visible here
without extra plumbing. Used by the slash-command palette to
surface user-invocable skills, and by the dispatcher to expand
/skill_name [args] into a SendMessage.
caps: TerminalCapsSnapshot of the terminal’s rendering capabilities. Probed once at
startup in lib.rs; threaded into App::new so UiState knows
whether to use Unicode or ASCII fallbacks for the spinner glyph
and ellipsis. Same value as RetainedRenderer was constructed
with — single source of truth.
replay_on_start: Option<Session>Session loaded by the CLI auto-continue path (atomcode -c /
--continue). Replayed into scrollback AND restored into the
agent’s model context via AgentCommand::SetMessages on first
run_loop entry, then dropped — matching /resume behaviour.
file_index: FileIndexLazy file/dir index for @-mention popup. Built on first @
keystroke via FileIndex::filter; session-life cache.
current_session_id: Option<SessionId>Active session id once /resume has loaded one. Required by the
/rename slash command to know which session file to update.
clipboard_check: Arc<Mutex<ClipboardCheckState>>Cached “clipboard currently holds an image” flag, with a short TTL
so the right-aligned Image in clipboard · ctrl+v to paste hint
stays current without thrashing the system clipboard on every
redraw. Refreshed lazily inside build_status.
is_plain_renderer: booltrue when the TUI was launched with PlainRenderer (CI / pipe
/ non-TTY). The onboarding wizard checks this — plain mode can’t
run interactive multi-step flows, so first-run falls through to
the existing “no provider configured” status hint.
Auto Trait Implementations§
impl !Freeze for LoopCtx
impl !RefUnwindSafe for LoopCtx
impl Send for LoopCtx
impl !Sync for LoopCtx
impl Unpin for LoopCtx
impl UnsafeUnpin for LoopCtx
impl !UnwindSafe for LoopCtx
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more