A local TUI for finding, inspecting, and resuming coding-agent sessions across projects.
Providers:
- Codex CLI sessions stored under
$CODEX_HOME/sessionsor~/.codex/sessions. Titles prefer Codex's native$CODEX_HOME/session_index.jsonlthread names, then fall back tohistory.jsonland rollout user messages. Resume bindsCODEX_HOMEto the selected session's source home before runningcodex. - Claude Code sessions stored under
$CLAUDE_HOME/projectsor~/.claude/projects. Resume runs from the original session cwd withclaude --resume <session-id>. - Kimi Code sessions stored under
$KIMI_CODE_HOME/$KIMI_HOMEor~/.kimi-code. Resume runs from the original session cwd withkimi --session <session-id>. - Kiro CLI sessions stored under
$KIRO_HOME/sessions/clior~/.kiro/sessions/cli. Resume runs from the original session cwd withkiro-cli chat --resume-id <session-id>. - opencode sessions stored in
$OPENCODE_HOME/opencode.dbor~/.local/share/opencode/opencode.db(SQLite, opencode v1.18+), with the legacystorage/session/**.jsonlayout used when the database does not exist. Resume runs from the original session cwd withopencode -s <session-id>. - ZCode sessions stored in a SQLite database under
$ZCODE_HOME/cli/db/db.sqliteor~/.zcode/cli/db/db.sqlite. ZCode is an Electron desktop app without a CLI or documented resume path, so asm treats zcode as discover-only; the reported resume command (zcode --resume <session-id>) is a future-compatible placeholder. - OpenClaw sessions indexed from the per-agent
sessions.jsonunder$OPENCLAW_STATE_DIR,$OPENCLAW_HOME/.openclaw, or~/.openclaw, checked in that order;--openclaw-homeoverrides all of them with an explicit state directory. asm lists OpenClaw sessions for discovery and reports, but resume is unsupported and transcripts are not parsed yet, so its report coverage is markedunavailable.
go run ./cmd/asmUse asm show <session-id> to read a bounded, normalized transcript without
opening a provider. All registered providers implement transcript reading;
providers whose native store keeps only a latest prompt return that available
portion. Tool calls, tool results, and reasoning are omitted from the normalized
user/assistant flow for a stable cross-provider contract.
asm show <session-id> --provider claude
asm show <session-id> --grep "timeout" --before 2 --after 2
asm show <session-id> --grep 'error-[0-9]+' --regex --case-sensitive
asm show <session-id> --full --from-index 50 --format jsonl --fields id,provider,messages--grep is a case-insensitive substring match by default. --regex switches
to regular-expression matching and --exact requires the complete message text
to match; --case-sensitive applies to either mode. --before and --after
require --grep and include neighboring messages while match_offsets reports
byte offsets in the original matching message. Message index values are
zero-based positions in the append-only transcript and are stable for existing
messages; use --from-index as a cursor when walking a growing session.
--offset skips returned rows after filtering and is less stable than
--from-index if a provider inserts history.
The default json format is indented, compact is one JSON envelope without
whitespace, and jsonl emits a metadata row followed by one message row per
line. --fields selects top-level envelope fields. --summary keeps the same
indexes, roles, and timestamps but limits text to --summary-chars (200 by
default). Show failures are written as {"error":{"code":"...","message":"..."}}
to stderr for scripts.
Download a prebuilt binary from the
latest GitHub Release.
Release archives are published for Linux, macOS, and Windows on amd64 and arm64,
with checksums in sha256sums.txt.
Linux and macOS:
version="${ASM_VERSION:-$(curl -fsSL https://api.github.com/repos/hxy91819/agent-session-manager/releases/latest | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')}"
case "$(uname -s)" in
Linux) os="linux" ;;
Darwin) os="darwin" ;;
*) echo "unsupported OS: $(uname -s)" >&2; exit 1 ;;
esac
case "$(uname -m)" in
x86_64|amd64) arch="amd64" ;;
arm64|aarch64) arch="arm64" ;;
*) echo "unsupported architecture: $(uname -m)" >&2; exit 1 ;;
esac
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
curl -fL -o "${tmpdir}/asm.tar.gz" "https://github.com/hxy91819/agent-session-manager/releases/download/${version}/asm_${version}_${os}_${arch}.tar.gz"
tar -C "${tmpdir}" -xzf "${tmpdir}/asm.tar.gz"
sudo install -m 0755 "${tmpdir}/asm_${version}_${os}_${arch}/asm" /usr/local/bin/asmWindows PowerShell:
$Version = (Invoke-RestMethod "https://api.github.com/repos/hxy91819/agent-session-manager/releases/latest").tag_name
$Arch = switch ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture) {
"X64" { "amd64" }
"Arm64" { "arm64" }
default { throw "unsupported architecture: $_" }
}
$Zip = Join-Path $env:TEMP "asm.zip"
$Extract = Join-Path $env:TEMP "asm-release"
$InstallDir = Join-Path $env:LOCALAPPDATA "Programs\asm"
Invoke-WebRequest -Uri "https://github.com/hxy91819/agent-session-manager/releases/download/$Version/asm_${Version}_windows_${Arch}.zip" -OutFile $Zip
Expand-Archive -Path $Zip -DestinationPath $Extract -Force
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
Copy-Item -Force (Join-Path $Extract "asm_${Version}_windows_${Arch}\asm.exe") (Join-Path $InstallDir "asm.exe")
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
if (($UserPath -split ";") -notcontains $InstallDir) {
$NewUserPath = if ([string]::IsNullOrWhiteSpace($UserPath)) { $InstallDir } else { "$UserPath;$InstallDir" }
[Environment]::SetEnvironmentVariable("Path", $NewUserPath, "User")
$env:Path = "$env:Path;$InstallDir"
}Developers with Go installed can also install from source:
go install github.com/hxy91819/agent-session-manager/cmd/asm@latestUseful non-interactive checks:
go run ./cmd/asm --json --query openclaw
go run ./cmd/asm --resume <session-id> --print-exec
go run ./cmd/asm resume --provider codex <session-id>
go run ./cmd/asm --claude-home /tmp/fake-claude --json
go run ./cmd/asm --kimi-home /tmp/fake-kimi --json
go run ./cmd/asm --kiro-home /tmp/fake-kiro --json
go run ./cmd/asm --opencode-home /tmp/fake-opencode --json
go run ./cmd/asm --zcode-home /tmp/fake-zcode --json
go run ./cmd/asm report --period yesterday
go run ./cmd/asm report --period today
go run ./cmd/asm report --period last-week --query openclaw
go run ./cmd/asm skills install agent-work-report
go run ./cmd/asm skills install tencent-meeting-summaryDeveloper checks:
pre-commit install
pre-commit run --all-files
go test ./...
go build ./cmd/asm
go run ./tools/check-provider-performance
go test -run '^$' -bench 'BenchmarkDiscover' -benchmem ./internal/provider/codex ./internal/provider/claude ./internal/provider/kiro ./internal/provider/opencode ./internal/provider/zcode
python3 -m unittest scripts/generate_release_changelog_test.pyThe pre-commit setup expects gitleaks and golangci-lint to be installed.
It runs staged secret scanning, basic file hygiene checks, gofmt, go vet,
go test, and a small Go lint set.
Release preparation:
git switch master
git pull --ff-only
python3 scripts/generate-release-changelog.py \
--version v0.8.0 \
--target HEAD \
--mode prepend \
--output CHANGELOG.md
git add CHANGELOG.md
git commit -m "Prepare v0.8.0 changelog"
git tag v0.8.0
git push origin master v0.8.0Generate and commit the changelog only after every intended feature and fix has
merged into master. The generator reads first-parent history, resolves each
merged PR's original GitHub author, and writes explicit Thanks @author
credit. The tag workflow verifies that committed section before publishing.
Release smoke verification:
tar -xzf asm_v0.9.0_linux_amd64.tar.gz
scripts/verify-release-smoke.sh ./asm_v0.9.0_linux_amd64/asmThe script uses isolated temporary stores and exercises the installed binary
through its public CLI for dsh, Pi, and opencode SQLite discovery, title
fallbacks, report evidence, provider-scoped resume commands, and missing-cwd
safety. It requires jq and python3; it never reads or modifies real agent
stores.
Performance controls:
go run ./cmd/asm --limit 1000 --since-days 30--limit caps how many session files are parsed per provider after newest-first
ordering. Use --codex-home, --claude-home, --kimi-home, --kiro-home,
--opencode-home, or --zcode-home to point at alternate provider stores. By
default only sessions active in the last 30 days are shown.
--since-days 0 disables the modification-time filter.
When --codex-home is omitted, ASM_CODEX_EXTRA_HOMES can contain additional
Codex homes separated by the platform path-list separator (: on Unix and ;
on Windows). ASM records the source home for each discovered Codex session and
uses it automatically for resume. This selects the source home's authentication
and configuration while still launching the standard codex command; shell
wrappers and their extra arguments are not replayed. An explicit
--codex-profile continues to override the selected home's default profile.
Automated and one-shot sessions are hidden when their provider exposes a
reliable non-interactive marker. Pass --include-non-interactive to include
them in JSON output or the TUI.
Discovery is isolated per provider. If one local provider store cannot be read,
JSON and report output keep sessions from healthy providers and add a
provider_errors array with the affected provider and error. The TUI shows the
same diagnostic in its status line. asm resume --provider <name> scans only
the selected provider; unqualified resume refuses to guess while any provider
could not be scanned.
macOS Gatekeeper:
Release binaries are not Apple Developer ID signed or notarized yet. If macOS
shows "Apple could not verify asm is free of malware", remove the quarantine
attribute after you have verified the release checksum:
grep 'asm_v0.5.0_darwin_arm64.tar.gz' sha256sums.txt
shasum -a 256 asm_v0.5.0_darwin_arm64.tar.gz
tar -xzf asm_v0.5.0_darwin_arm64.tar.gz
xattr -dr com.apple.quarantine asm_v0.5.0_darwin_arm64/asmThe long-term fix is to sign and notarize the Darwin release artifacts with an
Apple Developer ID certificate. Until then, building locally with
go install github.com/hxy91819/agent-session-manager/cmd/asm@latest also
avoids the browser-download quarantine path.
Direct resume:
go run ./cmd/asm resume --provider codex <session-id>
go run ./cmd/asm resume --provider claude <session-id> --print-exec
go run ./cmd/asm resume --provider kiro <session-id> --print-execThe provider flag disambiguates session IDs across agent providers. Report JSON
includes a resume_command for each session so agents can surface copyable
commands in follow-up sections.
When asm runs inside a Herdr-managed pane (HERDR_ENV=1), it asks the current
Herdr server for live agents. A session with one exact native session-ID match
is marked H in the TUI, and enter or asm resume focuses its existing pane
instead of starting another copy. --print-exec prints the corresponding
herdr agent focus <pane-id> command.
The live location is also exposed by asm --json as
sessions[].runtime_locations, with workspace_id, tab_id, pane_id, and
agent_status. Herdr lookup failures appear in the top-level
runtime_errors array without hiding provider sessions. Report JSON stays
independent of this transient runtime state.
Exact matching currently works for Codex, Claude Code, Kimi Code, opencode, and Cursor when their official Herdr integrations are installed. asm does not guess from cwd, titles, or workspace labels, so Kiro, CodeBuddy, OpenClaw, and ZCode continue through their normal resume behavior. If Herdr has no matching live session, or its CLI is temporarily unavailable, asm warns when necessary and falls back to the provider resume command.
Provider and new-session commands launched by asm inherit the complete current
process environment. In a Herdr pane this preserves HERDR_ENV,
HERDR_SOCKET_PATH, HERDR_SESSION, and the current workspace, tab, and pane
IDs, so the resumed agent reports back to the pane that actually hosts it.
Skill install:
go run ./cmd/asm skills install agent-work-report
go run ./cmd/asm skills install tencent-meeting-mcp
go run ./cmd/asm skills install tencent-meeting-summary
go run ./cmd/asm skills install --all
go run ./cmd/asm skills install agent-work-report --scope current --target agents
go run ./cmd/asm skills install hxy91819/agent-session-manager --path skills/agent-work-report --scope current --target agents
go run ./cmd/asm skills install hxy91819/agent-session-manager --path skills --all --scope both --target bothBy default, asm skills install downloads the standalone skills bundle from
the latest agent-session-manager GitHub Release. When --scope or --target
is omitted, asm prompts for current directory vs user directory and .agents
vs .claude. Use --yes for defaults (current + .agents) in scripts.
Example workflow:
asm skills install agent-work-report --scope current --target agents --yesAfter installing the bundled agent-work-report skill, ask your coding agent
for "生成上周 Agent 工作周报" or "总结昨天的工作". The skill calls
asm report --period last-week or asm report --period yesterday, classifies
the session previews by project and topic, and returns a Chinese work report
with a project-oriented morning-standup overview, follow-ups, and risks. Every
overview item is labeled [高投入], [中投入], or [低投入] using relative
signals from meeting duration, session timing, and evidence content; the labels
are estimates rather than measured working hours. A project with multiple
independent tasks keeps one numbered overview item and expands those tasks into
an indented child list; single-task items remain on one line.
For meeting-enriched reports, install tencent-meeting-mcp and the lightweight
tencent-meeting-summary skill, then export TENCENT_MEETING_TOKEN. The
summary skill lists ended meetings for the report window and reads available
Tencent Meeting smart minutes without downloading or reprocessing full
transcripts. Missing minutes may contribute only a clearly labeled,
title-inferred broad topic; they are never treated as proof of completed work.
The tracked nightly report entrypoint is:
cp .env.example .env
bash scripts/daily-agent-report.sh --dry-runIt loads the latest bundled skills from this checkout, keeps asm report as
the coding-work evidence source, and adds meeting context when the ignored
root .env provides TENCENT_MEETING_TOKEN. Generated output is validated
before delivery so an overview without effort levels, or one using effort
percentages, is retried instead of being sent.
Generation and delivery are separate executable adapters. The bundled
ollama.sh is the default generator
provider and receives --prompt <path>, sending the prompt to Ollama Cloud's
OpenAI-compatible /v1/chat/completions endpoint. Set
OLLAMA_BASE_URL, OLLAMA_MODEL, OLLAMA_REASONING_EFFORT=max, and
OLLAMA_API_KEY in the ignored .env; the DeepSeek default uses maximum
thinking depth.
The requested provider can be switched explicitly with
--generator-provider ollama or --generator-provider codebuddy; the bundled
codebuddy.sh remains available.
The orchestrator also exports REPORT_MODEL, REPORT_MAX_TURNS, and
REPORT_CODEBUDDY_BIN for providers that need them. The bundled
local-file-and-telegram.sh
is the default delivery provider. It first writes one canonical Markdown file
per report kind and window start under .local/agent-work-reports/, keeping an
existing file as the authoritative local version, then sends the report to
Telegram. If Telegram fails, the local report remains available and the next
run can retry Telegram without overwriting the local file. Either route remains
available alone with --delivery-provider local-file or
--delivery-provider telegram. Delivery adapters receive --report <path>,
REPORT_DELIVERY_CONFIG, and REPORT_TITLE.
Replace either side without changing report collection, validation, or retry behavior:
bash scripts/daily-agent-report.sh \
--generator-script ./scripts/my-report-generator \
--delivery-script ./scripts/my-tencent-doc-deliveryA replacement generator must accept --prompt <path>, write only the Markdown
report to stdout, and use stderr for diagnostics. A replacement delivery
adapter must accept --report <path> and return non-zero when delivery fails.
Copy the bundled providers as starting points for another model or a Tencent
Docs API integration. For a one-off historical resend, pass a half-open custom
window such as --start 2026-07-31 --end 2026-08-01. Keep all service
credentials in the ignored .env,
user-local configuration, or a secret manager; .env.example intentionally
contains no credentials.
Agent report export:
go run ./cmd/asm report --period yesterday
go run ./cmd/asm report --period today
go run ./cmd/asm report --period last-week
go run ./cmd/asm report --start "2026-06-17" --end "2026-06-18"
go run ./cmd/asm report --start "2026-06-17 09:00" --end "2026-06-17 18:30"
go run ./cmd/asm report --period yesterday --preview-messages-per-edge 4 --preview-max-chars 1000
go run ./cmd/asm report --period yesterday --preview-messages-per-edge 2 --preview-edge-offset 2asm report prints JSON for agent consumption. It uses local-time natural
windows and includes bounded user-message previews only for the report path.
Report discovery scans every session file modified since the start of the
requested window before applying --limit, so newer activity after a historical
window cannot displace matching sessions. For reports, --limit caps matching
sessions per provider after in-window evidence selection; 0 includes all.
When this result limit omits matching sessions, the provider's coverage entry
sets truncated: true and reports matched_sessions and included_sessions.
Detected non-interactive generator sessions are excluded by default so report
automation does not count its own work; use --include-non-interactive when
those sessions are intentionally part of the report.
today covers local midnight through the command's current time.
Use --start and --end for custom windows; accepted formats are
YYYY-MM-DD, local YYYY-MM-DD HH:MM[:SS], and RFC3339. Custom report
windows are half-open (start <= item < end), so --end 2026-06-18 excludes
events at local midnight on June 18.
For report writing, sessions[].evidence is the authoritative in-window work
evidence. The main sessions, projects, and their totals contain only sessions
with timestamped user-message evidence inside the requested half-open window.
Session titles are omitted from report output because a long-lived session can
have a title from another day. Session records updated within the window without
a user-authored message whose original timestamp falls in the window are placed
in unverified_sessions. Each item includes a reason_code and
may_hide_user_work. This is primarily a transcript-activity diagnostic, not a
count of missing work: only may_hide_user_work: true means a known provider
limitation could conceal in-window prompts.
Codex subagent threads remain discoverable and resumable, but reports exclude
them because their rollout files inherit the parent thread's history and would
otherwise duplicate the parent's work evidence.
coverage describes known provider limitations. Kimi is currently marked
partial because its state exposes only the latest prompt, and OpenClaw is
marked unavailable until its transcript is parsed. opencode messages without
an original message timestamp are excluded from evidence rather than dated by
filesystem mtime.
sessions[].evidence reuses the bounded preview selection, so
--preview-messages-per-edge caps evidence at twice its value per session.
The default of 2 user messages per edge (up to 4 evidence items per session)
is session.DefaultPreviewMessagesPerEdge in internal/session/preview.go;
long sessions keep only the window's head and tail prompts unless the flag is
raised.
If the default previews are not enough for a reliable summary, increase
--preview-messages-per-edge or --preview-max-chars and rerun the report.
For incremental context loading, keep --preview-messages-per-edge fixed and
increase --preview-edge-offset to fetch the next layer from both ends.
Oversized user records from the transcript-backed Codex, Claude, CodeBuddy, and
Cursor providers are recovered as bounded head/tail previews with their
original timestamp. Oversized known assistant/tool outputs are drained without
reducing user-evidence coverage; an explicit partial-coverage warning remains
only when a record may contain user evidence that cannot be identified safely.
The synthetic new row starts a fresh session with the project's most recently
used launchable agent. Press n from anywhere in the project to choose another
agent; the last-used agent is highlighted as the default.
TUI keys:
enter: resume the selected session, start the selectednewaction, or confirm an agent choicen: choose an agent for a new session in the current projectleft/right: switch projectsup/down: switch sessionspgup/pgdown: switch session pageshome/end: jump to first or last session in the project/: search sessionss: cycle sort modem: load 30 more days of historyesc: close the new-session agent chooserq: quit
Sessions or project counts marked with ! have a missing or unavailable cwd and
cannot be resumed until the path exists again.
Session discovery parses provider stores directly instead of asking provider
CLIs to list sessions. See
docs/session-discovery-design.md for the
provider discovery, parsing, concurrency, and cache model.