ccdesk 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +84 -67
  3. package/dist/server/agent-edit.js +77 -0
  4. package/dist/server/backups.js +129 -52
  5. package/dist/server/cli.js +21 -8
  6. package/dist/server/mcp-edit.js +263 -0
  7. package/dist/server/mutations.js +8 -3
  8. package/dist/server/scan/compare.js +34 -0
  9. package/dist/server/scan/context.js +6 -5
  10. package/dist/server/scan/env.js +8 -3
  11. package/dist/server/scan/files.js +118 -30
  12. package/dist/server/scan/index.js +29 -15
  13. package/dist/server/scan/instructions.js +11 -7
  14. package/dist/server/scan/inventory.js +134 -42
  15. package/dist/server/scan/mcp.js +88 -30
  16. package/dist/server/scan/memory.js +8 -9
  17. package/dist/server/scan/path-test.js +32 -10
  18. package/dist/server/scan/permissions.js +22 -6
  19. package/dist/server/scan/plugins.js +18 -11
  20. package/dist/server/scan/projects.js +7 -6
  21. package/dist/server/scan/sandbox.js +161 -0
  22. package/dist/server/scan/settings.js +33 -20
  23. package/dist/server/scan/tools.js +7 -3
  24. package/dist/server/scan/usage.js +119 -46
  25. package/dist/server/schema.js +15 -0
  26. package/dist/server/secrets.js +63 -0
  27. package/dist/server/server.js +222 -128
  28. package/dist/server/settings-edit.js +90 -21
  29. package/dist/server/watch.js +52 -10
  30. package/dist/server/write.js +58 -20
  31. package/dist/shared/compare.js +1 -0
  32. package/dist/shared/hook-events.json +35 -0
  33. package/dist/shared/mcp-server.schema.json +25 -0
  34. package/dist/shared/memory.js +4 -0
  35. package/dist/shared/scopes.js +3 -1
  36. package/dist/shared/types.js +1 -1
  37. package/dist/ui/assets/hanken-grotesk-cyrillic-ext-wght-normal-D_UHSL_T.woff2 +0 -0
  38. package/dist/ui/assets/index-D5XqP5c_.css +1 -0
  39. package/dist/ui/assets/index-XqJwI3k9.js +60 -0
  40. package/dist/ui/assets/jetbrains-mono-cyrillic-ext-wght-normal-EocZY2iu.woff2 +0 -0
  41. package/dist/ui/index.html +2 -2
  42. package/package.json +10 -4
  43. package/dist/ui/assets/index-BM4K7hSO.css +0 -1
  44. package/dist/ui/assets/index-CN3vkVjv.js +0 -45
package/CHANGELOG.md CHANGED
@@ -1,5 +1,91 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.1](https://github.com/ayagmar/ccdesk/compare/v0.2.0...v0.2.1) (2026-10-12)
4
+
5
+ ### Features
6
+
7
+ * **ui:** add a text size control and raise the default sizes ([1a9fe82](https://github.com/ayagmar/ccdesk/commit/1a9fe82b35cc4743936b7bf3c7a6d4244c86779a)), references [#root](https://github.com/ayagmar/ccdesk/issues/root)
8
+ * **ui:** open the docs from the ccdesk logo ([834986a](https://github.com/ayagmar/ccdesk/commit/834986a40df7801e6b4cf12588fd69f65411458a))
9
+
10
+ ### Bug Fixes
11
+
12
+ * **ui:** keep the section links on one row with the larger text ([f349f19](https://github.com/ayagmar/ccdesk/commit/f349f19c5e81ba3c498ff9f0751f4e3d5d99ade1))
13
+
14
+ ## [0.2.0](https://github.com/ayagmar/ccdesk/compare/v0.1.0...v0.2.0) (2026-10-12)
15
+
16
+ ### Features
17
+
18
+ * **agents:** create, change and delete subagent files ([1d8d011](https://github.com/ayagmar/ccdesk/commit/1d8d011c93c08dc8435ad304f5061378e8c4c1b7)), references [sub-agents#supported-frontmatter-fields](https://github.com/sub-agents/issues/supported-frontmatter-fields)
19
+ * **cli:** add --config-dir to read another Claude folder ([777712a](https://github.com/ayagmar/ccdesk/commit/777712aeb91da62f3f323292c8050b600ff59f5a))
20
+ * compare the settings of two directories ([9ec5e56](https://github.com/ayagmar/ccdesk/commit/9ec5e56b0d4f1cfc85b48accaea00ac59cf592c2))
21
+ * describe a claude -p or SDK session as well as an interactive one ([45c0ad1](https://github.com/ayagmar/ccdesk/commit/45c0ad180c1a26074d151375f99b80ddb20dd99e)), references [permissions#what-runs-before-you-trust-a-folder](https://github.com/permissions/issues/what-runs-before-you-trust-a-folder) [#when-your-local-settings-file-needs-trust](https://github.com/ayagmar/ccdesk/issues/when-your-local-settings-file-needs-trust) [hooks#workspace-trust](https://github.com/hooks/issues/workspace-trust)
22
+ * **hooks:** add, change and remove hooks in settings files ([7307b6b](https://github.com/ayagmar/ccdesk/commit/7307b6b1f3b7baa1ced8db4be6695e8456c87ef8))
23
+ * list claude mcp edits in Recent changes ([bfc153c](https://github.com/ayagmar/ccdesk/commit/bfc153c5f3489143d73c2cfcc75a5fc2c1175e93))
24
+ * **mcp:** add, change and remove MCP servers ([40f88a6](https://github.com/ayagmar/ccdesk/commit/40f88a6cce41f4c04d3816dfbd540cb2435482e9))
25
+ * **mcp:** check server entries against a schema of the documented fields ([3bfac6c](https://github.com/ayagmar/ccdesk/commit/3bfac6c884c07c03430fd896fe5ec2ba558cbc43))
26
+ * **mcp:** say what approved, rejected or holds a .mcp.json server ([1a42288](https://github.com/ayagmar/ccdesk/commit/1a4228880a81a24468caebab84aa27e85fdbde62))
27
+ * **site:** add the documentation site with llms.txt ([25148e4](https://github.com/ayagmar/ccdesk/commit/25148e43f4f5190c000f0e3f4aaeb98872c9ef53))
28
+ * **site:** capture frames for a video with screenshots --video ([e754f1f](https://github.com/ayagmar/ccdesk/commit/e754f1fd910834044158ca3c2125d706e3ca5d1c))
29
+ * **site:** light up each scope's rows in the hero screenshot ([af20413](https://github.com/ayagmar/ccdesk/commit/af204130ea0e1eee8cd428ba7a67df10bb0a6ffa))
30
+ * **site:** open each landing page question to the rows that answer it ([29d6815](https://github.com/ayagmar/ccdesk/commit/29d6815b628e68751d9de91d10c07a5805d27bc1))
31
+ * **site:** open screenshots in place, add motion and load faster ([340ee81](https://github.com/ayagmar/ccdesk/commit/340ee817449d06910fbc3ae3f6f2003c804014d9))
32
+ * **ui:** say that the page describes an interactive session ([c618a77](https://github.com/ayagmar/ccdesk/commit/c618a776a1313d44f8b88c05c9a660e64e55bb38))
33
+ * undo a change that created its file by removing the file ([e6297e3](https://github.com/ayagmar/ccdesk/commit/e6297e35296b0c2a9f4fd222bfff71f78216211e))
34
+
35
+ ### Bug Fixes
36
+
37
+ * **agents:** save a new agent typed as reviewer.md as reviewer.md, not reviewer.md.md ([2d07508](https://github.com/ayagmar/ccdesk/commit/2d07508eeb50dd9fff98e9816e58c1eaa25abc21))
38
+ * **backups:** record restored memories and restore halfway deletes ([3bfcbcf](https://github.com/ayagmar/ccdesk/commit/3bfcbcfd487956dd9eddd9f7252c9093887f95d9))
39
+ * hide keys in MCP server args ([922475c](https://github.com/ayagmar/ccdesk/commit/922475c067b313f75aee2332f01066bc4739ab55))
40
+ * **hooks:** hide the user name, password and query of an http hook's URL ([8b40d25](https://github.com/ayagmar/ccdesk/commit/8b40d25867ca6cbf76164a27584a15309803bb44))
41
+ * **instructions:** head your user CLAUDE.md as ~/.claude/CLAUDE.md, not .claude/CLAUDE.md ([683b1c8](https://github.com/ayagmar/ccdesk/commit/683b1c88bd244f1b033b3f546f7944599a0327de))
42
+ * **instructions:** say why a linked rule with paths does not load ([922788d](https://github.com/ayagmar/ccdesk/commit/922788d34fdc9333679d8792eb1865aa70acd831))
43
+ * match what Claude Code loads and keep hidden values out of edits ([9997c26](https://github.com/ayagmar/ccdesk/commit/9997c2652be271f1c6b3326f84218cfbe27f031d))
44
+ * **mcp:** count a "use all servers" answer to the .mcp.json prompt ([3008f9c](https://github.com/ayagmar/ccdesk/commit/3008f9c9792174d2334ce641555167962b7f67e3))
45
+ * **mcp:** hide a server's secrets in claude's own error message ([2b7882b](https://github.com/ayagmar/ccdesk/commit/2b7882b5e1df3d3540c06a5c8d7c559ec6ce4328))
46
+ * **mcp:** pass names safely to claude mcp and keep servers when it fails ([69b9353](https://github.com/ayagmar/ccdesk/commit/69b9353be3ecd96de2c29ed91183bfce0dfc6274))
47
+ * **mcp:** read and add local servers under the repository root only ([c536737](https://github.com/ayagmar/ccdesk/commit/c536737a8e8d05946d43b0bbe74364a890141cd8))
48
+ * **memory:** remove a [[name]] index line when its memory is deleted ([a08fbdf](https://github.com/ayagmar/ccdesk/commit/a08fbdf899c17e958c0ac98678d44e4b9b259dd5))
49
+ * **memory:** stop flagging a 200-line MEMORY.md that ends in a newline as cut off ([07a670b](https://github.com/ayagmar/ccdesk/commit/07a670b209593d315e7850e6145e8443b5c01554))
50
+ * **permissions:** say that ccdesk reads commands and addresses to match rules ([ca60592](https://github.com/ayagmar/ccdesk/commit/ca605920235512d041b03b0fbea57c4967f1ac70))
51
+ * **readme:** link each screenshot to its full-size image ([18837fc](https://github.com/ayagmar/ccdesk/commit/18837fc055aede576926f15d90b031c3b6a19fa9))
52
+ * **scan:** hold back settings-file hooks until the folder is trusted ([ab9ea97](https://github.com/ayagmar/ccdesk/commit/ab9ea973e153b343530ae5c945b8f71a28dd7895)), references [hooks#workspace-trust](https://github.com/hooks/issues/workspace-trust)
53
+ * **scan:** name plugin skills and commands with their plugin ([43d178a](https://github.com/ayagmar/ccdesk/commit/43d178a0f14c9479b576c6260eea1541f5fb6d53)), references [skills#how-a-skill-gets-its-command-name](https://github.com/skills/issues/how-a-skill-gets-its-command-name) [plugins-reference#name](https://github.com/plugins-reference/issues/name)
54
+ * **server:** put a file back when ccdesk cannot read it while removing it ([bfa4931](https://github.com/ayagmar/ccdesk/commit/bfa49318dc4df99605cc570e004cf6ed0b41543e))
55
+ * **server:** refuse a hard link to the credentials file ([8689378](https://github.com/ayagmar/ccdesk/commit/86893788ee20e1c0fc53464306167a5329968d6e))
56
+ * **server:** refuse a restore that would change hidden keys in args ([5ab6b40](https://github.com/ayagmar/ccdesk/commit/5ab6b409db633d82ac2cea37833639eff1d88c8d))
57
+ * **server:** refuse to save a file that has other hard links ([4fe7445](https://github.com/ayagmar/ccdesk/commit/4fe7445daba710babba8e5bc3826060389857f24))
58
+ * **server:** stop on SIGTERM and answer a malformed URL with 400 ([a519fcb](https://github.com/ayagmar/ccdesk/commit/a519fcb7b0f34c21ac35b81b606ec0bc350119d6))
59
+ * **server:** watch what a scan read even when the watch starts after it ([554a3d5](https://github.com/ayagmar/ccdesk/commit/554a3d58e9361c209313d258f665b54a09792757))
60
+ * **settings:** leave out sandbox fields Claude Code ignores from a file ([97bf3a9](https://github.com/ayagmar/ccdesk/commit/97bf3a95407a21682b0579482bd558071698f40a))
61
+ * **settings:** say why a value that may only tighten a key is ignored ([6e01ce8](https://github.com/ayagmar/ccdesk/commit/6e01ce882f08d3a34d1a2725f5371852e6c5b9ce))
62
+ * **settings:** show a value set only in the older local file in the details ([57cbc45](https://github.com/ayagmar/ccdesk/commit/57cbc453449eb1b3562062817091f8baa449ccef))
63
+ * **site:** draw the GitHub icon in the text colour ([f8dce1c](https://github.com/ayagmar/ccdesk/commit/f8dce1c184b98ed168e3f516f040ce22269a4dd3))
64
+ * **site:** line the header search up with the landing page's wider column ([95a1762](https://github.com/ayagmar/ccdesk/commit/95a176252a28e8f98253bd816212af0f8f54111e))
65
+ * **site:** name the app section each landing page question is answered in ([977a65c](https://github.com/ayagmar/ccdesk/commit/977a65c41b43fe03320a9181cbb02e1011c3be64))
66
+ * **tools:** list a whole-Bash rule under Monitor, whose commands it covers ([52e09b5](https://github.com/ayagmar/ccdesk/commit/52e09b5ead6570c620d0ef9ba9ba5cb8a880ac28))
67
+ * **tools:** show a failed count as unknown instead of counting forever ([b7b628d](https://github.com/ayagmar/ccdesk/commit/b7b628d2d6d672a245d9940d51edcfbc42f29f3a))
68
+ * **ui:** give the session switch its own line so the directory name keeps its room ([c43db64](https://github.com/ayagmar/ccdesk/commit/c43db642f6d980f8efea19387d09f11d3082272c))
69
+ * **ui:** give the tables the room until a row is picked and keep the directory name whole ([8059bea](https://github.com/ayagmar/ccdesk/commit/8059bea410755683637338814413fcc7f1b7844a))
70
+ * **ui:** keep an edited draft when the file changes underneath it ([5f72626](https://github.com/ayagmar/ccdesk/commit/5f726268c96160ba703fcec684fd420b0c7a9d3d))
71
+ * **ui:** keep the save toast above sticky table headers ([711c670](https://github.com/ayagmar/ccdesk/commit/711c6706fa276511ebe4968f05d105f7244722cf))
72
+ * **ui:** line up the columns on Recent changes ([112e732](https://github.com/ayagmar/ccdesk/commit/112e732a3eb776ce121e479538521c2f078551cc))
73
+ * **ui:** offer no undo for a change that created its file ([8103ddc](https://github.com/ayagmar/ccdesk/commit/8103ddc8c78ac323039a778be83c3d89f830851a))
74
+ * **ui:** offer only settings files that exist here when adding a rule or hook ([34bc591](https://github.com/ayagmar/ccdesk/commit/34bc5914cd23d87da8b2574bf7e4a5402a1571f8))
75
+ * **ui:** say that claude mcp edits pass values on claude's command line ([06d971e](https://github.com/ayagmar/ccdesk/commit/06d971e3ff9c7af693bbf9b1d9226b82dcf16100))
76
+ * **ui:** ship the small font files instead of inlining them past the CSP ([166ad6a](https://github.com/ayagmar/ccdesk/commit/166ad6a29df96b5df8c6b043e6ed23654226e978))
77
+ * **usage:** answer a stopped count even while one of its reads hangs ([9495017](https://github.com/ayagmar/ccdesk/commit/9495017641d050f15ba33d19e13db0b2fc9c0ed9))
78
+ * **usage:** stop tool-call counts nobody waits for or that run too long ([cc89847](https://github.com/ayagmar/ccdesk/commit/cc898474b3588c5a64c38fca1635e9bed20f1a27))
79
+
80
+ ### Performance Improvements
81
+
82
+ * **server:** cap the usage cache and keep only what matching reads ([6e5eeea](https://github.com/ayagmar/ccdesk/commit/6e5eeea66ce209c9598a417540ae0eb3415986b9))
83
+ * **server:** reuse a current scan for the path tester ([cb48481](https://github.com/ayagmar/ccdesk/commit/cb484810daa5a5469cef5688d740ba7a418a3756))
84
+
85
+ ### Reverts
86
+
87
+ * **site:** drop screenshots --video ([0009af4](https://github.com/ayagmar/ccdesk/commit/0009af451f02da3a2d41847e1ce21fbda2d6e892))
88
+
3
89
  ## 0.1.0 (2026-10-11)
4
90
 
5
91
  ### Features
package/README.md CHANGED
@@ -7,108 +7,125 @@
7
7
 
8
8
  [![npm](https://img.shields.io/npm/v/ccdesk?style=flat-square&color=141414)](https://www.npmjs.com/package/ccdesk)
9
9
  [![CI](https://img.shields.io/github/actions/workflow/status/ayagmar/ccdesk/ci.yml?branch=master&style=flat-square&label=ci)](https://github.com/ayagmar/ccdesk/actions/workflows/ci.yml)
10
- [![node](https://img.shields.io/node/v/ccdesk?style=flat-square&color=141414)](package.json)
11
- [![license](https://img.shields.io/github/license/ayagmar/ccdesk?style=flat-square&color=141414)](LICENSE)
10
+ [![node](https://img.shields.io/node/v/ccdesk?style=flat-square&color=141414)](https://github.com/ayagmar/ccdesk/blob/master/package.json)
11
+ [![license](https://img.shields.io/github/license/ayagmar/ccdesk?style=flat-square&color=141414)](https://github.com/ayagmar/ccdesk/blob/master/LICENSE)
12
12
 
13
- See and change everything that shapes Claude Code on your machine: instruction files, settings, hooks, MCP servers, subagents, skills, plugins and auto memory.
13
+ See and change everything Claude Code loads on your machine: instruction files, settings, permissions, hooks, MCP servers, subagents, skills, plugins and auto memory.
14
14
 
15
15
  ```sh
16
16
  npx ccdesk
17
17
  ```
18
18
 
19
- ccdesk opens in your browser on the directory you ran it from and answers one question: **what is Claude told here, and where does each piece come from?**
20
-
21
- It is not a session viewer or a usage dashboard. It reads your config, shows it in the order Claude Code loads it, and lets you fix it.
22
-
23
- ## What you see
24
-
25
- For any directory Claude Code has been used in:
26
-
27
- - **Instructions.** Every `CLAUDE.md`, `CLAUDE.local.md`, `AGENTS.md` and `.claude/rules/*.md` that applies, in load order. Each file shows whether it is loaded, skipped (and why), or loaded only for matching paths. It also lists the `@imports` it pulls in, whether it is tracked in git, untracked, git-ignored or personal, and whether it is a link into `~/.agents` that other coding agents read too.
28
- - **Settings.** Every key with the value Claude Code ends up using and the file it comes from: managed (including `managed-settings.d/`), user, project or local. Local settings are read from the repository root, as Claude Code does. Values overridden by a higher file are struck through, lists that merge across files are marked as merged, and a key set in a file Claude Code does not read it from is marked ignored.
29
- - **Permissions.** Every `allow`, `ask` and `deny` rule from every settings file, plus `defaultMode` and extra folders. Claude Code checks deny, then ask, then allow across all files, so an allow rule that the same rule in deny or ask overrides is flagged. Rules that wait for you to trust the folder, or that managed settings switch off, are marked as not in effect. An allow rule that covered no call in those sessions is marked, and calls Claude Code asked you about and you allowed show up as **suggested** allow rules, such as `Bash(pnpm test *)` or `WebFetch(domain:nodejs.org)`, with how many times you allowed them. A rule is not suggested when it would also cover a call you refused, or when your rules already decide those calls. Bash rules are suggested only for read-only commands such as `ls` or `jq`, for subcommands such as `git status` or `gh pr view` whose flags cannot run another command or write a file you did not name, and for script runners such as `pnpm test` or `git commit`, the same rule Claude Code's own prompt offers. A script runner runs your project's scripts or hooks, and npm and pnpm flags such as `--node-options` can make it run other code. A rule for `sed`, `make`, `go test`, `gh repo`, `git stash` or an install could allow far more than you approved.
30
- - **Built-in tools.** Every tool Claude Code ships with, what it does, and what happens when Claude reaches for it here: removed by a deny rule, asks first, or runs without asking. Rules that cover only some uses, such as `Bash(git push *)` or an `Edit` path, and `PreToolUse` hooks that match the tool are listed with it. Outcomes are as in Manual mode; the header says which mode sessions here start in. **Used** counts how often Claude called each tool in the sessions started here, or anywhere in the repository and its worktrees, since rules at a repository's root apply there too.
31
- - **Memory.** Auto memory for the directory, with filters by type (user, feedback, project, reference). Checks flag memories missing from `MEMORY.md`, broken `[[links]]`, a `MEMORY.md` too long to load in full, and memories saved in more than one directory. `autoMemoryEnabled`, `autoMemoryDirectory` and `CLAUDE_CODE_DISABLE_AUTO_MEMORY` are taken into account.
32
- - **Hooks, MCP servers, subagents, skills, commands, output styles and plugins**, each marked with the scope it comes from. Hooks turned off by `disableAllHooks` or `allowManagedHooksOnly`, MCP servers that wait for approval, are turned off, rejected or overridden by a closer definition, and plugins that are off are marked. Project skills come from the start directory and every parent up to the repository root. Subagents, skills and plugins can be filtered by kind.
33
- - **All settings.** Every key in the settings reference, set or not, grouped by area: what it does, which files Claude Code reads it from, its documented values and default, and the value it has here. Pick one to set it in the file you choose.
34
- - **Health checks.** Instruction files longer than the 200 lines the docs suggest, paragraphs repeated across files, and imports of files that do not exist.
35
-
36
- The header says when you have not yet accepted Claude Code's trust dialog for the folder, which is read from `~/.claude.json`. Settings files and `.mcp.json` files that are not valid JSON are listed at the top.
37
-
38
- If the directory is in a git repository, a strip under the line shows which of these files are tracked in git (everyone who clones gets them), not tracked yet, or git-ignored.
39
-
40
- **What Claude sees** switches to what your config puts in context when a session starts here, in load order: a custom output style, instruction files and their imports (without frontmatter and HTML comments, which Claude Code strips), the part of `MEMORY.md` that loads, the skill listing and your subagents' descriptions. Each shows its size and an estimated token count. Claude Code's system prompt and the tool names of MCP servers are listed but not counted. ccdesk does not show the text of an import outside the project and your Claude folders, and imports that wait for your approval are not counted.
41
-
42
- Below it, **When Claude touches a file** takes a path and lists what joins the session once Claude reads or edits it: path rules, skills with matching `paths`, and the `CLAUDE.md` files of the folders on the way.
43
-
44
- The line across the top is the load order: **M**anaged, **U**ser, **P**roject, **L**ocal, **A**uto memory and plugins (**X**). Click a stop to show only that scope.
45
-
46
- Every table can be filtered with `/`, narrowed with the chips above it, and sorted by clicking a column. Long tables show 50 rows at a time. Filters and sorting are kept in the URL, so a reload or a shared link opens the same view.
47
-
48
- **All directories** lists every directory Claude Code has sessions or memory for, and memories that exist in more than one of them.
49
-
50
- ## What you can change
51
-
52
- - **Settings.** Pick a key from the schema, which comes with autocomplete and descriptions, or open an existing one. Choose which file to write: user, project or local; files Claude Code does not read the key from are not offered. Each value gets the control that fits its type: a checkbox, a choice list, a number field, a text field with the documented values one click away, one entry per line, or JSON. Before anything is written you see the exact diff, and Save writes exactly that diff: if the file changed in the meantime, ccdesk asks you to review again. Values are checked against Claude Code's settings schema, other keys are left as they are, and the old file is backed up first. A file that is a symlink, such as one in a dotfiles repository, is written through and stays a link. Undo is one click.
53
- - **Permission rules.** Move a rule to another list, remove it, or add a new one to the file you choose, with the same diff review and backup. A suggested rule goes into local settings by default, as Claude Code's "don't ask again" does.
54
- - **Built-in tools.** Turn a tool off for Claude with a deny rule in the file you choose, and turn it back on by removing the rules that remove it. A rule from managed settings cannot be removed, so the tool stays off.
55
- - **Memory.** Delete a memory you no longer want. ccdesk also removes its line from `MEMORY.md`, warns you if other memories link to it, keeps a backup, and offers undo. A memory missing from `MEMORY.md` can be added to it, and lines pointing at deleted files can be removed. Each of these shows the exact change to `MEMORY.md` first and is refused if the memory or the index changed after you reviewed it.
56
- - **Open in your editor.** Every file path has an open button. ccdesk uses `$CCDESK_EDITOR`, then `$VISUAL` or `$EDITOR` when they name a graphical editor, and otherwise your system's default app.
57
-
58
- Backups go to `~/.claude/backups/ccdesk/`. **Recent changes** lists every change ccdesk made. Each one can be restored after you review the diff, and the current file is backed up before it is replaced.
59
-
60
- ccdesk never deletes sessions and never writes `~/.claude.json`.
19
+ Each piece lives in its own file, at one of six scopes: managed, user, project, local, auto memory or a plugin. ccdesk opens in your browser on the directory you ran it from, lists everything that applies there in the order Claude Code loads it, and names the file behind each piece. When something is wrong, change it on the same page: you review the diff first, and every edit has a backup and an undo. It is not a session viewer or a usage dashboard.
20
+
21
+ **Docs:** [ayagmar.github.io/ccdesk](https://ayagmar.github.io/ccdesk/)
22
+
23
+ <a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/directory-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/directory-dark.webp" /><img alt="ccdesk on a made-up project: the load order across the top, then instruction files and settings, each marked with the scope it comes from" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/directory-light.webp" /></picture></a>
24
+
25
+ ## Questions it answers
26
+
27
+ - Why does Claude ask me before every `git push` here? ([Permissions](https://ayagmar.github.io/ccdesk/permissions/))
28
+ - Which model does this repository use, and which file set it? ([Settings](https://ayagmar.github.io/ccdesk/settings/))
29
+ - Is my `AGENTS.md` loaded at all? ([Instructions](https://ayagmar.github.io/ccdesk/instructions/))
30
+ - How much context does my config take before I type anything? ([What Claude sees](https://ayagmar.github.io/ccdesk/what-claude-sees/))
31
+ - What do I keep approving by hand, and which allow rules have I stopped needing? ([Permissions](https://ayagmar.github.io/ccdesk/permissions/#suggested-rules))
32
+ - Which project MCP servers still wait for approval? ([MCP servers](https://ayagmar.github.io/ccdesk/mcp-servers/))
33
+
34
+ ## What it covers
35
+
36
+ | | What you see | What you can change | Docs |
37
+ | --- | --- | --- | --- |
38
+ | **Instructions** | Every `CLAUDE.md`, `AGENTS.md` and `.claude/rules/*.md` that applies, in load order, with why a file is skipped and who else sees it | Open it in your editor | [Instructions](https://ayagmar.github.io/ccdesk/instructions/) |
39
+ | **Settings** | The value Claude Code ends up using for each key, the file it comes from, and the values it overrides | Set or remove any documented key in user, project or local settings, picked from the schema | [Settings](https://ayagmar.github.io/ccdesk/settings/) |
40
+ | **Permissions** | Every allow, ask and deny rule, which ones never take effect, and allow rules that covered no call | Add, move or remove rules; accept allow rules suggested from the calls you approved | [Permissions](https://ayagmar.github.io/ccdesk/permissions/) |
41
+ | **Built-in tools** | What happens when Claude reaches for each tool here, and how often it did | Turn a tool off with a deny rule, or back on | [Tool usage](https://ayagmar.github.io/ccdesk/tool-usage/) |
42
+ | **Hooks** | Every hook with its scope, and the ones that are turned off | Add, change or remove hooks in user, project or local settings | [Hooks](https://ayagmar.github.io/ccdesk/hooks/) |
43
+ | **MCP servers** | Every server, and the ones waiting for approval, off, rejected or overridden | Add, change or remove servers in `.mcp.json`, or through `claude mcp` for user and local ones | [MCP servers](https://ayagmar.github.io/ccdesk/mcp-servers/) |
44
+ | **Subagents** | Every agent from managed, project, user and plugin folders, and which definition wins | Create, change or delete agent files | [Subagents](https://ayagmar.github.io/ccdesk/subagents/) |
45
+ | **Skills and plugins** | Skills, commands, output styles and plugins, by scope | Open them in your editor | [Skills and plugins](https://ayagmar.github.io/ccdesk/skills-and-plugins/) |
46
+ | **Memory** | Auto memory for the directory, with memories missing from `MEMORY.md`, broken links and duplicates flagged | Delete a memory and its index line, fix the index | [Memory](https://ayagmar.github.io/ccdesk/memory/) |
47
+ | **What Claude sees** | What your config puts in context when a session starts, with sizes and estimated tokens | | [What Claude sees](https://ayagmar.github.io/ccdesk/what-claude-sees/) |
48
+
49
+ <table>
50
+ <tr>
51
+ <td width="50%"><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/permissions-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/permissions-dark.webp" /><img alt="The permissions table with rules from user, project and local settings, and three suggested allow rules" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/permissions-light.webp" /></picture></a></td>
52
+ <td width="50%"><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/context-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/context-dark.webp" /><img alt="What Claude sees: instruction files, memory and skill listing in load order, with sizes and token estimates" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/context-light.webp" /></picture></a></td>
53
+ </tr>
54
+ <tr>
55
+ <td>Permissions, with allow rules suggested from the calls you approved</td>
56
+ <td>What Claude sees when a session starts here</td>
57
+ </tr>
58
+ <tr>
59
+ <td><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/memory-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/memory-dark.webp" /><img alt="Auto memory for a directory, with checks on the MEMORY.md index" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/memory-light.webp" /></picture></a></td>
60
+ <td><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/changes-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/changes-dark.webp" /><img alt="Recent changes: every edit ccdesk made, each one restorable" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/changes-light.webp" /></picture></a></td>
61
+ </tr>
62
+ <tr>
63
+ <td>Auto memory and its index</td>
64
+ <td>Every change ccdesk made, ready to restore</td>
65
+ </tr>
66
+ </table>
67
+
68
+ ## How changes are made
69
+
70
+ <a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/review-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/review-dark.webp" /><img align="right" width="300" alt="Changing the model setting: the files that set it, the value Claude Code uses, and the diff to project settings before saving" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/review-light.webp" /></picture></a>
71
+
72
+ - You see the exact diff before anything is written, and Save writes exactly that diff. If the file changed in the meantime, ccdesk asks you to review again.
73
+ - Settings and hooks are checked against Claude Code's settings schema. Other keys in the file stay as they are.
74
+ - The old file is backed up to `~/.claude/backups/ccdesk/` first. Undo is one click, and **Recent changes** can restore any earlier edit.
75
+ - A settings file that is a symlink, such as one in a dotfiles repository, is written through and stays a link.
76
+ - A file with other hard links is not saved: replacing it would split it from its other names. Edit it in your editor.
77
+ - ccdesk never writes `~/.claude.json`. User and local MCP server changes go through Claude Code's own `claude mcp` command, so they need `claude` on your PATH.
78
+
79
+ Details: [Recent changes, backups and undo](https://ayagmar.github.io/ccdesk/recent-changes/)
80
+
81
+ <br clear="right" />
61
82
 
62
83
  ## Keyboard
63
84
 
64
85
  | Key | Action |
65
86
  | --- | --- |
66
87
  | `j` / `k` | Next / previous row |
67
- | `1`–`9` | Jump to a section |
88
+ | `1` to `9` | Jump to a section |
68
89
  | `/` | Filter rows |
69
- | `Ctrl K` / `⌘ K` | Jump to any directory, file, setting or rule, or a memory saved for any directory |
90
+ | `Ctrl K` / `⌘ K` | Jump to any directory, file, setting, rule or memory |
70
91
  | `Esc` | Close details |
71
92
 
93
+ More in [Reading the interface](https://ayagmar.github.io/ccdesk/interface/).
94
+
72
95
  ## Options
73
96
 
74
97
  ```
75
98
  npx ccdesk [options]
76
99
 
77
- --port <n> Port to listen on (default: a free port)
78
- --no-open Print the URL instead of opening a browser
79
- -h, --help Show this help
100
+ --port <n> Port to listen on (default: a free port)
101
+ --no-open Print the URL instead of opening a browser
102
+ --config-dir <path> Claude folder to read, as CLAUDE_CONFIG_DIR sets it for Claude Code
103
+ (wins over $CLAUDE_CONFIG_DIR)
104
+ -h, --help Show this help
80
105
  ```
81
106
 
82
- ccdesk reads `~/.claude`, or `$CLAUDE_CONFIG_DIR` when it is set. It watches the config files for the open directory, so edits made in another editor or by Claude show up within a second. `~/.claude.json` is not watched, because Claude Code rewrites it during every session; changes to it show up when you return to ccdesk's tab. Requires Node.js 22.19 or newer.
107
+ ccdesk reads `~/.claude` and `~/.claude.json`, or `$CLAUDE_CONFIG_DIR` when it is set, as Claude Code does. To look at another profile without exporting the variable, pass `--config-dir <path>`. Edits made in another editor or by Claude show up within a second. Requires Node.js 22.19 or newer. See [Platform notes](https://ayagmar.github.io/ccdesk/platforms/) for Windows, macOS and WSL.
83
108
 
84
109
  ## Privacy and safety
85
110
 
86
- - The server listens on `127.0.0.1` only. Every API call needs a token generated for that run, which the browser receives in the URL fragment. Requests from other hosts or origins are refused.
87
- - Nothing leaves your machine.
88
- - Values under `env` and `headers` (in settings and MCP servers) are hidden in the UI, including in diffs and in a settings file reached through an import or a link. ccdesk never changes them: an edit that touches them is refused, and so is a restore that would put back older values. The user name, password and query string of a `url` (such as an MCP server's) are hidden too, wherever ccdesk shows it, and errors about a broken JSON file give only the line and column.
89
- - ccdesk never reads `~/.claude/.credentials.json`, even through a link or an import, and never writes `~/.claude.json`, even through a settings file that links to it. A `MEMORY.md` that links outside its memory folder is left alone.
90
- - To count tool calls and your answers to permission prompts, ccdesk reads the open directory's transcripts in `~/.claude/projects/`. Only counts and rule patterns (a command's program and subcommand, a fetch's domain) reach the page, never commands, file contents or anything else from a session. Your answers come from a transcript field Claude Code does not document, so older transcripts may not have them.
91
- - Backups can hold settings with secrets, so their folders and files are readable only by you.
92
- - Markdown is rendered without raw HTML, so an `AGENTS.md` from a cloned repo cannot run script in the page.
93
-
94
- ## Settings schema
111
+ - The server listens on `127.0.0.1` only, and every API call needs a token generated for that run. Nothing leaves your machine.
112
+ - Values under `env` and `headers`, and keys in an MCP server's `args` (after flags such as `--token` or `--api-key`, or starting like `sk-` or `ghp_`), are hidden everywhere in the UI, diffs included, and ccdesk refuses any edit that would change them.
113
+ - ccdesk never reads `~/.claude/.credentials.json`.
114
+ - From your transcripts, only counts and rule patterns (a command's program and subcommand, a fetch's domain) reach the page, never commands or file contents.
115
+ - Backups are readable only by you on Linux and macOS.
95
116
 
96
- The settings schema is generated from the `Settings` type in [`@anthropic-ai/claude-agent-sdk`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk), which is published with each Claude Code release. Which files each key is read from comes from the Scope column of the [settings reference](https://code.claude.com/docs/en/settings-reference). The built-in tools come from the [tools reference](https://code.claude.com/docs/en/tools-reference). The settings catalog comes from the same reference. A daily workflow regenerates all of them and opens a pull request when any of them changed. Some of Claude Code's behaviour, such as how rules match commands, is only described in the docs, so ccdesk follows it by hand and cites the docs section in the code; the workflow also fingerprints every cited section and lists the ones that changed in the pull request.
117
+ The full list is in [Safety and privacy](https://ayagmar.github.io/ccdesk/safety-and-privacy/).
97
118
 
98
119
  ## Development
99
120
 
100
121
  ```sh
101
122
  pnpm install
102
123
  pnpm dev # API on 127.0.0.1:4319
103
- pnpm dev:ui # UI with hot reload on 127.0.0.1:4320
124
+ pnpm dev:ui # UI with hot reload on localhost:4320
104
125
  pnpm check # typecheck, lint, format, tests, build
105
- pnpm schema # regenerate src/shared/settings.schema.json
106
- pnpm scopes # regenerate src/shared/settings-scopes.json from the settings reference
107
- pnpm tools # regenerate src/shared/builtin-tools.json from the tools reference
108
- pnpm docs:fingerprints # fingerprint the docs sections the code cites; prints the ones that changed
109
126
  ```
110
127
 
111
- Tests never touch your real `~/.claude`. Each one builds a throwaway home directory.
128
+ Tests never touch your real `~/.claude`; each one builds a throwaway home directory. The settings schema, scopes and built-in tools are generated from [`@anthropic-ai/claude-agent-sdk`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) and Claude Code's docs, and a daily workflow opens a pull request when they change. [Contributing](https://ayagmar.github.io/ccdesk/contributing/) covers the generators, the docs site and releases.
112
129
 
113
130
  ## License
114
131
 
@@ -0,0 +1,77 @@
1
+ import { join, resolve } from "node:path";
2
+ import {} from "../shared/types.js";
3
+ import {} from "./scan/env.js";
4
+ import { gitRoot, revisionOf, shownText } from "./scan/files.js";
5
+ import { scanDirectory } from "./scan/index.js";
6
+ import { agentProblems } from "./scan/inventory.js";
7
+ import { RefusedError, readIfExists, recordChange, removeExactly, serially, StaleError, writeAtomic, } from "./write.js";
8
+ /** The file an edit changes: an agent the scan shows here, or a new one in your or the project's folder. */
9
+ async function targetOf(env, edit) {
10
+ const dir = resolve(edit.dir);
11
+ if (edit.path !== undefined) {
12
+ const agent = (await scanDirectory(env, dir)).inventory.agents.find((a) => a.path === edit.path);
13
+ if (!agent)
14
+ throw new RefusedError("That agent is no longer here; review it again.");
15
+ if (agent.scope !== "user" && agent.scope !== "project")
16
+ throw new RefusedError(agent.scope === "plugin"
17
+ ? "This agent comes with its plugin; change it in the plugin."
18
+ : "Managed agents are set by your organisation.");
19
+ return agent.path;
20
+ }
21
+ if (!edit.create)
22
+ throw new RefusedError("An agent edit needs the agent or where a new one goes.");
23
+ const { scope } = edit.create;
24
+ // The folder gives the .md; a name typed with it would otherwise end in .md.md.
25
+ const file = edit.create.file.replace(/\.md$/i, "");
26
+ if (!/^[\w][\w.-]*$/.test(file))
27
+ throw new RefusedError("A file name has letters, digits, '.', '-' or '_', and no folders.");
28
+ const folder = scope === "user"
29
+ ? join(env.claudeDir, "agents")
30
+ : join((await gitRoot(dir)) ?? dir, ".claude", "agents");
31
+ return join(folder, `${file}.md`);
32
+ }
33
+ async function plan(env, edit) {
34
+ const path = await targetOf(env, edit);
35
+ const raw = await readIfExists(env, path);
36
+ if (!edit.path && raw !== null)
37
+ throw new RefusedError(`${path} already exists; open that agent to change it.`);
38
+ const before = shownText(raw);
39
+ // The page shows the file with env, header and URL values hidden, so a changed file written back
40
+ // from it would lose them; it can still be deleted, as a whole.
41
+ if (edit.text !== null && before !== raw)
42
+ throw new RefusedError(`${path} has env, header or URL values ccdesk does not show; edit it in your editor instead.`);
43
+ const errors = edit.text === null ? [] : agentProblems(edit.text);
44
+ return {
45
+ path,
46
+ raw,
47
+ preview: {
48
+ path,
49
+ before,
50
+ after: errors.length > 0 ? (before ?? "") : (shownText(edit.text) ?? ""),
51
+ revision: revisionOf(raw),
52
+ reformats: false,
53
+ errors,
54
+ },
55
+ };
56
+ }
57
+ export async function previewAgentEdit(env, edit) {
58
+ return (await plan(env, edit)).preview;
59
+ }
60
+ /** Writes or deletes an agent file, backed up first, only while it is as reviewed. */
61
+ export function saveAgentEdit(env, edit, expectedRevision) {
62
+ return serially(async () => {
63
+ const { path, raw, preview } = await plan(env, edit);
64
+ if (preview.errors.length > 0)
65
+ throw new RefusedError(preview.errors.join(" "));
66
+ if (preview.revision !== expectedRevision)
67
+ throw new RefusedError("The agent changed since you reviewed this; review it again.");
68
+ const { text } = edit;
69
+ return recordChange(env, { kind: "agent", target: path, before: raw }, async () => {
70
+ if (text !== null)
71
+ await writeAtomic(env, path, text, expectedRevision);
72
+ else if (!(await removeExactly(path, expectedRevision)))
73
+ throw new StaleError(`${path} changed while ccdesk deleted it; nothing was deleted.`);
74
+ return { target: path, revision: revisionOf(text) };
75
+ });
76
+ });
77
+ }