atctl is a Rust CLI/TUI for sending and managing AT commands for USB
cellular modems from macOS on Apple Silicon.
Validated environment:
- Mac: Apple Silicon Mac
- USB modem: SORACOM Onyx LTE USB Dongle (Quectel EG25-G)
- USB ID:
0x2c7c:0x0125 - Observed firmware:
EG25GGBR07A08M2G(ATI, 2026-06-17)
Real-hardware workflows confirmed in this environment:
- USB device discovery and descriptor inspection with
devicesandinspect, plus directAT/ATIexecution - Preset execution with masked history and session logging
- TUI candidate refresh and related Sequence input behavior
- PTY bridge operation through
screen - SMS send, receive/list, read, and reply, plus Quectel/SORACOM ping and TCP Sequence workflows
Install atctl with Homebrew:
brew install uchimanajet7/atctl/atctlThe Homebrew formula installs the libusb runtime dependency. See the
installation guide
for prerequisites and installation checks.
Confirm that the modem is visible and responds to AT commands:
atctl devices
atctl inspect
atctl send AT
atctl send ATI
atctl tuiUse atctl devices to find the current USB target. If the expected modem is not
shown, run atctl devices --all-usb and follow the
troubleshooting guide.
- Work interactively with
atctl tui. - Send one AT command with
atctl send <COMMAND>. - Run repeatable checks with
atctl preset listandatctl preset run <NAME>. - Run multi-step SMS and data-send checks with
atctl sequence listandatctl sequence run <SEQUENCE>. - Use
atctl bridge --symlink <PATH>for a terminal-style PTY bridge. - Collect raw diagnostic evidence only with an explicit output path and
raw-logacknowledgement.
atctl send, atctl preset run, atctl sequence run, and TUI executions
write masked command history and session logs by default:
~/.local/state/atctl/history.jsonl
~/.local/state/atctl/logs/<timestamp>.session.log
These paths follow the
XDG Base Directory Specification.
Set XDG_STATE_HOME to a non-empty absolute path to use a different state
directory for one invocation. atctl appends its own atctl directory:
env XDG_STATE_HOME="$HOME/Documents" atctl send AT
env XDG_STATE_HOME="$HOME/Documents" atctl logs listThese commands use $HOME/Documents/atctl/. To skip new masked history and
session logs for one command or TUI session, use --no-log:
atctl send AT --no-log
atctl preset run modem-info --no-log
atctl sequence run sms-receive-check --no-log
atctl tui --no-log--no-log does not hide existing logs and does not disable a raw diagnostic
export explicitly requested with --raw-log-file or the TUI raw-export action.
atctl retains normal masked logs in the XDG state directory until the operator
removes them; it does not apply a retention period or automatic rotation. TUI
log actions can reveal the selected log directly. To keep a separate copy of a
current Response, choose Export response... in the TUI and select a destination
folder, or pass --export-response <PATH> to send, preset run, or
sequence run. Response export follows the selected foreground masking mode,
uses a new file, and never replaces normal stdout or the generated masked logs.
When the TUI Response is unmasked, copy requires copy acknowledgement and
export requires export acknowledgement after destination selection.
See
Review and Manage Logs
for CLI and TUI review, Response export, Finder access, and deletion effects.
Command and Sequence rows use one risk label: [safe], [sensitive],
[write], [persistent], [dangerous], or [unknown]. Output masking state
and required confirmation are shown separately.
AT commands can read sensitive identifiers and change modem state. atctl
masks sensitive output by default, requires confirmation for state-changing
actions, and creates raw diagnostic exports only when the user chooses an
output file and acknowledges the risk. Read the
safety guide
before running unfamiliar or state-changing commands.
A preset runs one AT command. A Sequence runs a multi-step workflow such as SMS send, read, or reply. Product-provided presets and standard Sequences are ready to use from the CLI and TUI.
atctl preset list
atctl preset run modem-info
atctl sequence list
atctl sequence run sms-receive-checkRepository-managed examples and project-local definitions are loaded by providing their file or directory for the current command or TUI session:
atctl preset list --preset-dir examples/presets
atctl sequence list --sequence-dir examples/sequences
atctl tui --preset-dir examples/presets --sequence-dir examples/sequencesExternal definitions retain their source identity and use the same risk, confirmation, masking, logging, and raw-export protections as product-provided definitions. Review their source and destination values before execution. See the presets and Sequences reference for inventories, TOML formats, loading options, Sequence parameters, and evidence interpretation.
For usage questions, bug reports, and feature requests, search the existing GitHub Issues and open a new issue if needed.
For suspected security vulnerabilities, use GitHub private vulnerability reporting instead of opening a public issue.
For a bug report, include the atctl version when available, the affected
command or TUI action, reproduction steps, expected result, actual result, and
only reviewed masked output when needed. Do not include raw diagnostic exports,
unmasked output, credentials, subscriber identifiers, phone numbers, or message
contents in a public issue.
Code and documentation contributions are welcome. Read the contribution guide before opening a pull request.
- Development guide
- Packaging and release guide
- Product and technical specification
- Accepted product and architecture decisions
MIT. See LICENSE.
