diff --git a/agterm/Info.plist b/agterm/Info.plist
index 27397a45..17d851ce 100644
--- a/agterm/Info.plist
+++ b/agterm/Info.plist
@@ -50,18 +50,28 @@
Command-line tools you run inside agterm (for example, ffmpeg capturing video) request camera access through agterm.
NSContactsUsageDescription
Command-line tools you run inside agterm request access to your contacts through agterm.
+ NSDesktopFolderUsageDescription
+ Command-line tools you run inside agterm request access to your Desktop folder through agterm.
+ NSDocumentsFolderUsageDescription
+ Command-line tools you run inside agterm request access to your Documents folder through agterm.
+ NSDownloadsFolderUsageDescription
+ Command-line tools you run inside agterm request access to your Downloads folder through agterm.
NSLocalNetworkUsageDescription
Command-line tools you run inside agterm (for example, connecting to a .local host) request local network access through agterm.
NSLocationUsageDescription
Command-line tools you run inside agterm request your location through agterm.
NSMicrophoneUsageDescription
Command-line tools you run inside agterm (for example, voice dictation in Claude Code) request microphone access through agterm.
+ NSNetworkVolumesUsageDescription
+ Command-line tools you run inside agterm request access to files on network volumes through agterm.
NSPhotoLibraryUsageDescription
Command-line tools you run inside agterm (for example, osxphotos) request access to your photo library through agterm.
NSRemindersFullAccessUsageDescription
Command-line tools you run inside agterm request access to your reminders through agterm.
NSRemindersUsageDescription
Command-line tools you run inside agterm request access to your reminders through agterm.
+ NSRemovableVolumesUsageDescription
+ Command-line tools you run inside agterm request access to files on removable volumes through agterm.
NSSpeechRecognitionUsageDescription
Command-line tools you run inside agterm request speech recognition through agterm.
NSSystemAdministrationUsageDescription
diff --git a/agtermCore/Sources/agtermCore/AgentHooksInstall.swift b/agtermCore/Sources/agtermCore/AgentHooksInstall.swift
index 3dc8bbf3..97f6a797 100644
--- a/agtermCore/Sources/agtermCore/AgentHooksInstall.swift
+++ b/agtermCore/Sources/agtermCore/AgentHooksInstall.swift
@@ -15,7 +15,7 @@ public enum AgentHooksInstall {
/// The bundled Pi extension's path relative to the agent-status package, and its destination filename.
public static let piExtensionRelativePath = "pi/agterm-status.ts"
- public static let piExtensionName = "agterm-status.ts"
+ static let piExtensionName = "agterm-status.ts"
/// Ownership sentinel in the bundled Pi extension: a reinstall refuses to overwrite an unmarked same-named
/// extension, preserving a user-authored integration.
@@ -23,7 +23,7 @@ public enum AgentHooksInstall {
/// The bundled OpenCode plugin's path relative to the agent-status package, and its destination filename.
public static let opencodePluginRelativePath = "opencode/agterm-status.js"
- public static let opencodePluginName = "agterm-status.js"
+ static let opencodePluginName = "agterm-status.js"
/// Ownership sentinel in the bundled OpenCode plugin, same policy as `piExtensionMarker`. Named `*Plugin*`
/// (not `*Extension*`) because OpenCode's host term is plugin — a deliberate divergence from `piExtension*`.
@@ -36,8 +36,8 @@ public enum AgentHooksInstall {
/// Marker lines bracketing the agterm-managed block in a shell rc file; the opening marker is also the
/// idempotency probe (present → already installed).
- public static let rcMarkerBegin = "# >>> agterm agent-status >>>"
- public static let rcMarkerEnd = "# <<< agterm agent-status <<<"
+ static let rcMarkerBegin = "# >>> agterm agent-status >>>"
+ static let rcMarkerEnd = "# <<< agterm agent-status <<<"
/// The Claude Code hook events the merge installs, paired with the state (plus flags) each maps to.
/// `UserPromptSubmit` and `PostToolUse` both set `active` — the latter after every tool run, so the status
@@ -64,7 +64,7 @@ public enum AgentHooksInstall {
]
/// The destination directory for Pi's auto-discovered global extensions.
- public static func piExtensionDirectory(home: String) -> String {
+ static func piExtensionDirectory(home: String) -> String {
home + "/.pi/agent/extensions"
}
@@ -81,7 +81,7 @@ public enum AgentHooksInstall {
}
/// The destination directory for OpenCode's auto-discovered global plugins.
- public static func opencodePluginDirectory(home: String) -> String {
+ static func opencodePluginDirectory(home: String) -> String {
home + "/.config/opencode/plugins"
}
@@ -286,11 +286,11 @@ public enum AgentHooksInstall {
/// the absolute wrapper-script path the installed hooks invoke (`/agterm-agent-status.sh`); the
/// caller's hook entry appends the state.
- public static func wrapperPath(scriptDir: String) -> String {
+ static func wrapperPath(scriptDir: String) -> String {
scriptDir + "/" + wrapperName
}
- public static func codexWrapperPath(scriptDir: String) -> String {
+ static func codexWrapperPath(scriptDir: String) -> String {
scriptDir + "/" + codexWrapperName
}
@@ -299,7 +299,7 @@ public enum AgentHooksInstall {
/// merge declines, and nothing checks the two against each other.
/// The wrapper's absolute path is baked into each command — shell-quoted (so a path with spaces stays one
/// token) inside a TOML basic string — so the hook fires without the CLI on PATH.
- public static func codexHooksBlock(scriptDir: String) -> String {
+ static func codexHooksBlock(scriptDir: String) -> String {
let wrapper = shellQuote(codexWrapperPath(scriptDir: scriptDir))
return codexHooks.map { hook in
"""
diff --git a/agtermCore/Sources/agtermCore/ConfigPaths.swift b/agtermCore/Sources/agtermCore/ConfigPaths.swift
index 6a8d16c8..9040e125 100644
--- a/agtermCore/Sources/agtermCore/ConfigPaths.swift
+++ b/agtermCore/Sources/agtermCore/ConfigPaths.swift
@@ -74,7 +74,7 @@ public enum ConfigPaths {
# Examples:
#
# command "Open in Zed" cmd+shift+e open -a Zed "$AGT_SESSION_PWD"
- # command "Lazygit" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --socket "$AGT_SOCKET"
+ # command "Lazygit" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --target "$AGT_SESSION_ID" --socket "$AGT_SOCKET"
# command "Deploy" ./deploy.sh
#
# global-hotkey
diff --git a/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift b/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift
index df070b8d..55466bef 100644
--- a/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift
+++ b/agtermCore/Tests/agtermCoreTests/ConfigPathsTests.swift
@@ -37,7 +37,7 @@ struct ConfigPathsTests {
#expect(starter.contains("command \"\" [chord] "))
#expect(starter.contains("single chord OR a leader like `ctrl+a>g`"))
#expect(starter.contains("command \"Open in Zed\" cmd+shift+e open -a Zed \"$AGT_SESSION_PWD\""))
- #expect(starter.contains("command \"Lazygit\" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --socket \"$AGT_SOCKET\""))
+ #expect(starter.contains("command \"Lazygit\" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --target \"$AGT_SESSION_ID\" --socket \"$AGT_SOCKET\""))
#expect(starter.contains("command \"Deploy\" ./deploy.sh"))
#expect(starter.contains("ctrl+shift+p"))
#expect(!starter.contains("super"))
diff --git a/docs/backlog/codex-wrapper-path-is-public-with-no-consumer.md b/docs/backlog/codex-wrapper-path-is-public-with-no-consumer.md
deleted file mode 100644
index 98603c98..00000000
--- a/docs/backlog/codex-wrapper-path-is-public-with-no-consumer.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-worth: later
-where: agtermCore/Sources/agtermCore/AgentHooksInstall.swift:293
-added: 2026-08-19
----
-# codexWrapperPath is public with nothing outside the module calling it
-
-`codexWrapperPath(scriptDir:)` is `public` but its only caller is `codexHooksBlock` at `:303`, in the same
-file. `internal` would serve it. Contrast `codexWrapperName` two lines up, whose `public` is earned by
-`agterm/AgentHooksInstaller.swift:136`.
-
-Against the standing rule that visibility is private by default and exported only when used outside the
-package. Nothing is broken; the cost is that a reader has to grep to learn which of the two neighbouring
-symbols is an app-target contract and which is not.
-
-Worth doing whenever something else touches this file, and worth checking the rest of the enum's public
-surface in the same pass rather than tightening one symbol alone.
-
-Surfaced reviewing PR #461.
diff --git a/docs/backlog/no-folder-usage-strings-in-info-plist.md b/docs/backlog/no-folder-usage-strings-in-info-plist.md
deleted file mode 100644
index 73d8130c..00000000
--- a/docs/backlog/no-folder-usage-strings-in-info-plist.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-worth: later
-where: agterm/Info.plist:37
-added: 2026-08-20
----
-# Info.plist declares no usage string for the protected folders
-
-The sixteen `NSxxxUsageDescription` strings cover the entitlement-gated services and none of the
-Files & Folders family. macOS defines an optional string per protected folder —
-`NSDesktopFolderUsageDescription`, `NSDocumentsFolderUsageDescription`,
-`NSDownloadsFolderUsageDescription`, `NSNetworkVolumesUsageDescription`,
-`NSRemovableVolumesUsageDescription` — and with none present it falls back to its own copy, measured in
-`TCC.framework/Versions/A/Resources/Localizable.loctable` as
-`REQUEST_ACCESS_SERVICE_kTCCServiceSystemPolicyDownloadsFolder` = `“%@” would like to access
-files in your Downloads folder.` So the user is asked why agterm wants his Downloads and told nothing.
-
-Every other family already explains hosted-CLI responsibility in its string, so the same pattern applies:
-"Command-line tools you run inside agterm may request access to your Downloads folder through agterm."
-WezTerm ships two of these written for exactly that case; Ghostty, kitty and iTerm2 ship none.
-
-Deferred because it fixes nothing. The strings are not a gate — agterm can obtain these grants today
-without them — so this repairs no denial and adds no access, and the only change is five pieces of prompt
-copy. It also cannot be proven by CI, which pins the entitlement set and asserts nothing about
-`Info.plist`: confirming the custom text actually renders needs a signed build and a fresh TCC state by
-hand. Surfaced investigating #468, where the missing strings turned out not to be the cause.
diff --git a/docs/backlog/seeded-lazygit-example-omits-target.md b/docs/backlog/seeded-lazygit-example-omits-target.md
deleted file mode 100644
index 286e563e..00000000
--- a/docs/backlog/seeded-lazygit-example-omits-target.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-worth: later
-where: agtermCore/Sources/agtermCore/ConfigPaths.swift:77
-added: 2026-08-20
----
-# the seeded Lazygit example omits --target and can open its overlay elsewhere
-
-The starter `keymap.conf` ships:
-
-```
-command "Lazygit" ctrl+a>g agtermctl session overlay open 'zsh -lc lazygit' --socket "$AGT_SOCKET"
-```
-
-`TargetOptions.target` defaults to `active` (`agtermCore/Sources/agtermctlKit/Commands.swift:69`), and `active`
-is resolved when the request reaches the server, not when the chord built its context. The custom command is
-spawned detached and fire-and-forget (`agterm/Commands/CustomCommandRunner.swift:336`), so a session or window
-switch between the keypress and delivery opens the overlay over whatever is selected by then. The command
-reference already tells automated callers to pin it (`site/commands.html:379`), and a custom command has the
-stable `$AGT_SESSION_ID` for exactly this.
-
-The fix is one flag: `--target "$AGT_SESSION_ID"`. The line is otherwise valid — `overlay open` does not
-require a size flag, so omitting `--size-percent` correctly gives a full-size overlay.
-
-Worth doing because the `#extend` lesson now sends new users to **File ▸ Edit Keymap…**, where they read this
-example next to the docs' pinned one and get two different answers. Kept out of the docs change (#PR) because
-touching `ConfigPaths.swift` pulls in the full Swift gate run for a one-line seed-text improvement, and no
-existing user is blocked by it.
-
-Found by codex while reviewing the paste lines in the `#extend` lesson.