Skip to content

Ground inspection in a chosen claude session (#11, #12)#15

Merged
samkeen merged 2 commits into
mainfrom
feat/attach-mode
May 13, 2026
Merged

Ground inspection in a chosen claude session (#11, #12)#15
samkeen merged 2 commits into
mainfrom
feat/attach-mode

Conversation

@samkeen
Copy link
Copy Markdown
Contributor

@samkeen samkeen commented May 13, 2026

Pivot the inspector from "knobs.cc's own CWD" to a session it picks from the running process table. Closes the longstanding paradox where the project / project_local rail rows showed knobs.cc's launch directory rather than the user's claude session, and the cli row sat permanently empty because flags couldn't be observed without reading another process's argv.

New surface:

  • read_runtime_layer Tauri command enumerates same-UID claude / claude-code processes via the sysinfo crate and returns each one's cwd, argv, and environ.
  • read_settings_layers grows attached_pid / project_root_override args. The new ProjectSource enum routes the three grounding modes (Attached / Picked / CurrentDir-fallback) through one snapshot read.
  • cli_layer.rs parses argv against catalog/cli-settings-map.json (5 starter flags: --model, --permission-mode, --effort, --agent, --add-dir) and emits a real cli LayerRead.
  • env_layer.rs grows read_env_layer_attached(environ), so the env precedence layer reads the attached claude's environ when attached rather than knobs.cc's own.
  • SessionPill in the topbar drives a four-state picker (loading / 0 / 1 / 2+ claudes, plus unsupported on Windows). Single-process case auto-attaches; multi-process opens an inline picker; zero drops to a native folder picker via the dialog plugin.
  • EnvVarsPanel gains an attached column alongside shell, a per-row Δ badge when the two diverge, and attached / Δ diff filter chips that appear only when attached.

Capability surface gains one grant: dialog:allow-open for the project-directory fallback picker. Cross-process reads stay Rust-only (no JS-side process/fs plugin grants). The "no fs, shell, process, updater" rule from design-notes.md still holds.

Other refinements during smoke-testing:

  • MERGED chip on array-merge paths now only fires when 2+ layers actually contributed elements. Single-contributor array paths render as normal set rows with the contributor's badge; the per-element drawer view still renders.
  • #[tauri::command(rename_all = "snake_case")] on read_settings_layers — Tauri 2 defaults to camelCase command args while this project's wire format is snake_case throughout; without the override attached_pid from JS silently deserialized to None.
  • The repo's "Claude Code reads dotenv files at startup" claim (footnote, four spec spots, Read another running claude process's argv + env (the "runtime introspection" layer) #11 body) was wrong. Smoke-tested with claude -p reading a .env-only var: nothing. The claim is removed.

Docs sweep: user-facing copy (README, HelpView, EnvVarsPanel footnote, waterfall empty-state) describes grounded inspection as the product without narrating the pivot. Spec docs (attach-mode.md, inspector-ui, design-notes, settings-display, roadmap) reference the implementation contract in attach-mode.md and the closed issues.

Small code-cleanup items (dedup set_dotted_path between cli + env layer, strip pivot/legacy framing from comments, two missing test cases) parked in issue #14.

Pivot the inspector from "knobs.cc's own CWD" to a session it picks from
the running process table. Closes the longstanding paradox where the
project / project_local rail rows showed knobs.cc's launch directory
rather than the user's claude session, and the cli row sat permanently
empty because flags couldn't be observed without reading another
process's argv.

New surface:

- `read_runtime_layer` Tauri command enumerates same-UID `claude` /
  `claude-code` processes via the `sysinfo` crate and returns each
  one's cwd, argv, and environ.
- `read_settings_layers` grows `attached_pid` / `project_root_override`
  args. The new `ProjectSource` enum routes the three grounding modes
  (Attached / Picked / CurrentDir-fallback) through one snapshot read.
- `cli_layer.rs` parses argv against `catalog/cli-settings-map.json`
  (5 starter flags: --model, --permission-mode, --effort, --agent,
  --add-dir) and emits a real `cli` LayerRead.
- `env_layer.rs` grows `read_env_layer_attached(environ)`, so the env
  precedence layer reads the attached claude's environ when attached
  rather than knobs.cc's own.
- `SessionPill` in the topbar drives a four-state picker (loading /
  0 / 1 / 2+ claudes, plus unsupported on Windows). Single-process
  case auto-attaches; multi-process opens an inline picker; zero
  drops to a native folder picker via the `dialog` plugin.
- EnvVarsPanel gains an `attached` column alongside `shell`, a per-row
  `Δ` badge when the two diverge, and `attached` / `Δ diff` filter
  chips that appear only when attached.

Capability surface gains one grant: `dialog:allow-open` for the
project-directory fallback picker. Cross-process reads stay Rust-only
(no JS-side process/fs plugin grants). The "no `fs`, `shell`,
`process`, `updater`" rule from design-notes.md still holds.

Other refinements during smoke-testing:

- `MERGED` chip on array-merge paths now only fires when 2+ layers
  actually contributed elements. Single-contributor array paths
  render as normal `set` rows with the contributor's badge; the
  per-element drawer view still renders.
- `#[tauri::command(rename_all = "snake_case")]` on
  `read_settings_layers` — Tauri 2 defaults to camelCase command
  args while this project's wire format is snake_case throughout;
  without the override `attached_pid` from JS silently deserialized
  to `None`.
- The repo's "Claude Code reads dotenv files at startup" claim
  (footnote, four spec spots, #11 body) was wrong. Smoke-tested with
  `claude -p` reading a .env-only var: nothing. The claim is removed.

Docs sweep: user-facing copy (README, HelpView, EnvVarsPanel footnote,
waterfall empty-state) describes grounded inspection as the product
without narrating the pivot. Spec docs (attach-mode.md, inspector-ui,
design-notes, settings-display, roadmap) reference the implementation
contract in attach-mode.md and the closed issues.

Small code-cleanup items (dedup `set_dotted_path` between cli + env
layer, strip pivot/legacy framing from comments, two missing test
cases) parked in issue #14.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new settings tests — cli_layer_ok_when_attached_to_live_process
and attached_pid_for_live_process_resolves_project_root — assert that
attaching to a live pid resolves to Some(...). But process_for_pid is
Unix-only in v1 (sysinfo doesn't expose another process's environ on
Windows, so the function early-returns None on that target). Add the
same cfg!(target_os = "windows") early-return guard used by
current_uid_resolves_on_unix.

The Windows code path is still covered by the existing tests that
exercise the None branch (attached_pid_for_unknown_process_emits_diagnostic
runs on every OS).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@samkeen samkeen merged commit 0a5ac27 into main May 13, 2026
3 checks passed
@samkeen samkeen deleted the feat/attach-mode branch May 13, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant