Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ knobs.cc is a **Tauri 2 desktop app** (pre-release; no signed installer yet) tha
The repo holds three coordinated surfaces:

1. **`spec/`** — design, scope, and roadmap. `inventory.md` catalogs every Claude Code config surface; `settings-display.md` and `inspector-ui.md` describe the app's backend and UI in phases; `catalog-sync.md` describes the harness that keeps catalog files in sync with upstream docs; `design-notes.md` carries open questions; `roadmap.md` is the single source of truth for what's shipped and what's pending.
2. **The Tauri 2 app** (`src/`, `src-tauri/`) — implementation. The Rust backend exposes three commands: `read_settings_layers` (reads the five real layers — managed / env / project_local / project / user — with per-leaf provenance and array-merge for permissions-style fields; `cli` and `default` are synthesized at the UI), `read_catalog` (the upstream-derived reference data), and `read_shell_env_vars` (filters the user's process env down to catalog-listed names for the EnvVarsPanel). Plus a `notify`-based file watcher that emits `settings-changed` so the UI refreshes live (see "Tauri 2 boundaries" — we use `notify` directly, not `tauri-plugin-fs-watch`, to keep the capability surface minimal). The React/Vite frontend is a three-pane DevTools-style Inspector (precedence rail, settings list, key drawer) plus a sibling **EnvVarsPanel** modal — a topbar-pill takeover that's the SSOT for env vars (catalog × shell × settings.json `env` block). Inspector rows skip the `env` subtree by design; the panel owns that surface.
3. **The catalog harness** (`scripts/sync-*.js`, `catalog/*.json`) — pulls upstream JSON Schema and docs into `catalog/{settings,env-vars,hooks,sub-agents,mcp,permissions,keybindings,cli-reference}.json`, which the app reads through `read_catalog`. `catalog/env-settings-map.json` maps env vars to their settings-key equivalents for the env layer. `.github/workflows/catalog-drift.yml` re-runs the sync scripts weekly (and on `workflow_dispatch`), normalises the always-changing `fetchedAt` field out of the comparison, and opens a single rolling `chore/catalog-drift` PR when real content drifts. Don't run the sync scripts and commit by hand unless you have a specific reason — let the workflow drive.
2. **The Tauri 2 app** (`src/`, `src-tauri/`) — implementation. The Rust backend exposes four commands: `read_settings_layers` (reads the six real precedence layers — managed / cli / env / project_local / project / user — with per-leaf provenance and array-merge for permissions-style fields; `default` is synthesized at the UI; accepts `attached_pid` / `project_root_override` args to ground the snapshot in a chosen session), `read_runtime_layer` (enumerates same-UID claude processes via `sysinfo` and returns each one's cwd / argv / environ — see [`spec/attach-mode.md`](spec/attach-mode.md)), `read_catalog` (the upstream-derived reference data), and `read_shell_env_vars` (filters knobs.cc's own process env down to catalog-listed names; complementary to the attached-env column when a claude is attached). Plus a `notify`-based file watcher that emits `settings-changed` so the UI refreshes live (see "Tauri 2 boundaries" — we use `notify` directly, not `tauri-plugin-fs-watch`, to keep the capability surface minimal). The React/Vite frontend is a three-pane DevTools-style Inspector (precedence rail, settings list, key drawer) plus a sibling **EnvVarsPanel** modal — a topbar-pill takeover that's the SSOT for env vars (catalog × attached-environ × shell × settings.json `env` block, with a Δ-diff chip when attached vs shell disagree). Inspector rows skip the `env` subtree by design; the panel owns that surface. A **SessionPill** in the topbar drives the attach mechanism: 0 / 1 / 2+ claude processes get distinct UI states, with a path-picker fallback when none are running.
3. **The catalog harness** (`scripts/sync-*.js`, `catalog/*.json`) — pulls upstream JSON Schema and docs into `catalog/{settings,env-vars,hooks,sub-agents,mcp,permissions,keybindings,cli-reference}.json`, which the app reads through `read_catalog`. `catalog/env-settings-map.json` maps env vars to their settings-key equivalents for the env layer; `catalog/cli-settings-map.json` does the same for argv flags feeding the cli layer (both hand-maintained — upstream JSON Schema doesn't expose these as structured metadata). `.github/workflows/catalog-drift.yml` re-runs the sync scripts weekly (and on `workflow_dispatch`), normalises the always-changing `fetchedAt` field out of the comparison, and opens a single rolling `chore/catalog-drift` PR when real content drifts. Don't run the sync scripts and commit by hand unless you have a specific reason — let the workflow drive.

**Outstanding work is tracked in [`spec/roadmap.md`](spec/roadmap.md)**, the single source of truth. When you ship something or discover new work, update there rather than scattering status across the individual specs.

Expand All @@ -28,7 +28,7 @@ Entries tagged `> [!verify]` haven't been cross-checked against live docs. Clear

v1 is locked to read-only inspection. The capability surface is deliberately tiny:

- `src-tauri/capabilities/default.json` grants `core:default`, `opener:default`, and a scoped `opener:allow-open-path` (whitelist covering the user/project `.claude/` dirs — needed for the rail's path-note click-through). Platform-specific managed-tier paths live in sibling files gated with `platforms`: `default-macos.json` (`/Library/...`), `default-linux.json` (`/etc/claude-code/**`), `default-windows.json` (`C:\Program Files\ClaudeCode\**`). Splitting them is load-bearing — Tauri compiles every scope glob on every target, and the Windows backslash pattern fails to compile on macOS/Linux unless gated. **Do not add `fs`, `shell`, `process`, `dialog`, or `updater` plugin permissions.** Adding a path to the `opener:allow-open-path` allowlist is an expansion of the trust surface — keep new entries as tight as the file you actually need to open, not the whole parent dir.
- `src-tauri/capabilities/default.json` grants `core:default`, `opener:default`, a scoped `opener:allow-open-path` (whitelist covering the user/project `.claude/` dirs — needed for the rail's path-note click-through), and `dialog:allow-open` (used for the project-directory picker when no claude is attached; returns a path string but doesn't read files). Platform-specific managed-tier paths live in sibling files gated with `platforms`: `default-macos.json` (`/Library/...`), `default-linux.json` (`/etc/claude-code/**`), `default-windows.json` (`C:\Program Files\ClaudeCode\**`). Splitting them is load-bearing — Tauri compiles every scope glob on every target, and the Windows backslash pattern fails to compile on macOS/Linux unless gated. **Do not add `fs`, `shell`, `process`, or `updater` plugin permissions.** Adding a path to the `opener:allow-open-path` allowlist is an expansion of the trust surface — keep new entries as tight as the file you actually need to open, not the whole parent dir.
- File reads happen through explicit `#[tauri::command]` Rust functions registered via `tauri::generate_handler![...]`, **not** by granting the frontend filesystem-plugin permissions.
- File **watching** uses the `notify` crate from Rust and pushes `settings-changed` events to the frontend. Don't swap to `tauri-plugin-fs-watch` — that would require granting fs-watch capabilities to JS.
- Frontend calls commands via `invoke()` from `@tauri-apps/api/core`. No open-ended plugin APIs from JS.
Expand Down
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# Contributing

knobs.cc is in early development. The Tauri 2 app shell has been scaffolded (React + TypeScript + Vite frontend, Rust backend), but no custom Tauri commands or UI have been implemented yet. The project is still in concept phase — see `spec/` for the working inventory of Claude Code's configuration surface and the catalog-sync harness design.
knobs.cc is in pre-release. The Tauri 2 desktop inspector runs end-to-end via `npm run tauri dev` — settings-precedence rendering, a session picker that grounds the inspector against a running `claude` process (or a picked project directory), per-leaf provenance, per-element waterfall for array-merged paths, and a sibling EnvVarsPanel with attached/shell diff. No signed installer yet.

## What's useful right now

- **Corrections to the inventory.** Entries tagged `> [!verify]` are places we're least confident. If you've tested a knob and can confirm the behaviour, file an issue or PR against `spec/inventory.md`.
- **Missing knobs.** If you know of a Claude Code configuration surface — env var, setting, hook event, IDE quirk — that's absent from the inventory, file an issue.
- **Design input.** Opinions on app stack, hero flow, how to represent hook graphs, etc. belong in issues tagged `design`.
- **Inspector bugs / UX feedback.** Run `npm run tauri dev`, attach to a session, file what feels off.
- **Design input.** Opinions on hero flow, how to represent hook graphs, goals view, landing page, etc. belong in issues tagged `design`.

## What's not useful yet

Code PRs. The prototype milestone hasn't been reached — the Tauri 2 scaffold is in place but no app-specific functionality has been built. If you're excited to contribute, watch the repo for the prototype milestone.
Substantial code PRs without an issue first — let's discuss the shape before you write it. The roadmap in `spec/roadmap.md` is the source of truth for what's slated and what's deferred.

## Ground rules

Expand Down
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,6 @@ A local desktop inspector for every knob Claude Code gives you — where it live
**Pre-release.** The read-only inspector runs end-to-end via
`npm run tauri dev`. No signed installer or auto-update yet.

Two known gaps in the precedence rail are tracked openly: the `cli`
slot stays empty because knobs.cc can't read another process's flags
([#11](https://github.com/AlteredCraft/knobs-cc/issues/11)), and the
`project` / `project_local` rows resolve relative to knobs.cc's own
working directory rather than a chosen claude session, so they're
greyed out in the rail
([#12](https://github.com/AlteredCraft/knobs-cc/issues/12)). The
managed / env / user / default layers are unaffected.

## Premise

Claude Code has a sprawling configuration surface: settings files
Expand All @@ -32,10 +23,16 @@ hard.
knobs.cc lays it all out in one place:

- What Claude Code **can** be configured with
- What **is** configured in the current environment
- What **is** configured for a specific session
- **Where** each value is coming from (user / project / local /
managed / env var / CLI flag / default)

The inspector grounds against a running `claude` process you pick
from the topbar: it reads that session's cwd, argv, and environ to
resolve the project, cli, and env layers honestly. If no claude is
running, point the inspector at a project directory and the file
layers resolve against it.

Live updates are wired in: when a watched settings file changes on
disk the snapshot refreshes automatically.

Expand All @@ -59,13 +56,16 @@ disk the snapshot refreshes automatically.
Three coordinated surfaces:

- **The Tauri 2 app.** `src/` (React/Vite/TypeScript Inspector UI) and
`src-tauri/` (Rust backend with the read-only `read_settings_layers`
and `read_catalog` Tauri commands). Five settings layers (managed /
env / project_local / project / user), per-leaf provenance, and
`src-tauri/` (Rust backend with the read-only `read_settings_layers`,
`read_catalog`, `read_shell_env_vars`, and `read_runtime_layer`
Tauri commands). Seven settings layers (managed / cli / env /
project_local / project / user / default), per-leaf provenance,
per-element waterfall for array-merged fields like
`permissions.allow`. The managed tier reads the macOS
`com.anthropic.claudecode` MDM plist when present and falls back to
the file-based source otherwise.
`permissions.allow`, and a session picker that reads a running
claude process's cwd, argv, and environ so the cli + env + project
layers resolve against the same session. The managed tier reads the
macOS `com.anthropic.claudecode` MDM plist when present and falls
back to the file-based source otherwise.
- **The specs.** [`spec/roadmap.md`](spec/roadmap.md) is the single
source of truth for what's shipped vs pending. Other live specs:
[`spec/inventory.md`](spec/inventory.md) (every Claude Code knob),
Expand Down
32 changes: 32 additions & 0 deletions catalog/cli-settings-map.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"source": "Hand-curated from catalog/cli-reference.json — each flag's documented 'Overrides … setting' wording. See spec/attach-mode.md PR 2 'cli row + EnvVarsPanel attached-env column'. Mirrors the env-settings-map.json pattern.",
"fetchedAt": "2026-05-13",
"count": 5,
"mappings": [
{
"flag": "--model",
"settings": "model",
"kind": "string"
},
{
"flag": "--permission-mode",
"settings": "permissions.defaultMode",
"kind": "string"
},
{
"flag": "--effort",
"settings": "effortLevel",
"kind": "string"
},
{
"flag": "--agent",
"settings": "agent",
"kind": "string"
},
{
"flag": "--add-dir",
"settings": "permissions.additionalDirectories",
"kind": "stringArrayMulti"
}
]
}
8 changes: 7 additions & 1 deletion mocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@ open mocks/03-goals.html
```

All three render the same realistic snapshot:
- 5 of 7 layers active (managed and cli are absent / not inspectable)
- 5 of 7 layers active (managed and cli are absent in this fixture —
no MDM policy, no attached claude with mapped flags)
- 12 set keys, 2 env vars, 3 shadowed values, 4 array-merged fields
- The same `model` shadowing example: project (`opus-4-7`) wins over user (`sonnet-4-6`)
- The same `permissions.allow` array-merge across user + project + project_local

These are concept-phase mocks; the shipped Inspector resolves the cli +
env + project layers against a session picked via the topbar (see
[`../spec/attach-mode.md`](../spec/attach-mode.md)). The mocks predate
that surface and don't render it.

No build step. No JS framework. Tailwind via CDN. Fonts from Google.

---
Expand Down
16 changes: 13 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
},
"dependencies": {
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "^2.7.1",
"@tauri-apps/plugin-opener": "^2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down
Loading
Loading