docks-kit 0.1.0

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 (49) hide show
  1. package/AGENTS.md +99 -0
  2. package/LICENSE +21 -0
  3. package/README.md +124 -0
  4. package/SoT/.agents/skills.txt +14 -0
  5. package/SoT/.claude/CLAUDE.md +146 -0
  6. package/SoT/.claude/fetch-usage.sh +66 -0
  7. package/SoT/.claude/hooks/notify.sh +14 -0
  8. package/SoT/.claude/mcp-servers.json +10 -0
  9. package/SoT/.claude/settings.json +258 -0
  10. package/SoT/.claude/statusline.sh +175 -0
  11. package/SoT/.codex/AGENTS.md +75 -0
  12. package/SoT/.codex/agents/.gitkeep +1 -0
  13. package/SoT/.codex/config.toml +45 -0
  14. package/SoT/.codex/plugins/marketplace.json +50 -0
  15. package/SoT/.codex/rules/docks.rules +116 -0
  16. package/SoT/models.json +28 -0
  17. package/SoT/toolchain.json +26 -0
  18. package/cli/docs/flags.md +48 -0
  19. package/cli/docs/install.md +56 -0
  20. package/cli/docs/models.md +42 -0
  21. package/cli/docs/modifiers.md +33 -0
  22. package/cli/docs/overview.md +37 -0
  23. package/cli/docs/platforms.md +31 -0
  24. package/cli/docs/plugins.md +44 -0
  25. package/cli/docs/sync-layers.md +43 -0
  26. package/cli/docs/toolchain.md +54 -0
  27. package/cli/src/commands/docs.ts +65 -0
  28. package/cli/src/commands/model.ts +60 -0
  29. package/cli/src/commands/models.ts +46 -0
  30. package/cli/src/commands/plugins.ts +34 -0
  31. package/cli/src/commands/skills.ts +37 -0
  32. package/cli/src/commands/status.ts +79 -0
  33. package/cli/src/commands/sync.ts +134 -0
  34. package/cli/src/commands/toolchain.ts +42 -0
  35. package/cli/src/engine.ts +36 -0
  36. package/cli/src/kitHome.ts +31 -0
  37. package/cli/src/main.ts +60 -0
  38. package/cli/src/manifests.ts +105 -0
  39. package/cli/src/md.d.ts +4 -0
  40. package/cli/tsconfig.json +14 -0
  41. package/docks-kit +61 -0
  42. package/lib/claude.sh +846 -0
  43. package/lib/codex.sh +518 -0
  44. package/lib/common.sh +229 -0
  45. package/lib/engine.sh +153 -0
  46. package/lib/skills.sh +373 -0
  47. package/lib/toolchain.sh +222 -0
  48. package/notification.mp3 +0 -0
  49. package/package.json +39 -0
@@ -0,0 +1,116 @@
1
+ prefix_rule(pattern=["pwd"], decision="allow")
2
+ prefix_rule(pattern=["ls"], decision="allow")
3
+ prefix_rule(pattern=["cat"], decision="allow")
4
+ prefix_rule(pattern=["head"], decision="allow")
5
+ prefix_rule(pattern=["tail"], decision="allow")
6
+ prefix_rule(pattern=["wc"], decision="allow")
7
+ prefix_rule(pattern=["nl"], decision="allow")
8
+ prefix_rule(pattern=["grep"], decision="allow")
9
+ prefix_rule(pattern=["sort"], decision="allow")
10
+ prefix_rule(pattern=["uniq"], decision="allow")
11
+ prefix_rule(pattern=["diff"], decision="allow")
12
+ prefix_rule(pattern=["which"], decision="allow")
13
+ prefix_rule(pattern=["date"], decision="allow")
14
+ prefix_rule(pattern=["basename"], decision="allow")
15
+ prefix_rule(pattern=["dirname"], decision="allow")
16
+ prefix_rule(pattern=["realpath"], decision="allow")
17
+ prefix_rule(pattern=["readlink"], decision="allow")
18
+ prefix_rule(pattern=["jq"], decision="allow")
19
+ prefix_rule(pattern=["tree"], decision="allow")
20
+ prefix_rule(pattern=["cut"], decision="allow")
21
+ prefix_rule(pattern=["tr"], decision="allow")
22
+ prefix_rule(pattern=["echo"], decision="allow")
23
+ prefix_rule(pattern=["printf"], decision="allow")
24
+ prefix_rule(pattern=["printenv"], decision="allow")
25
+ prefix_rule(pattern=["uname"], decision="allow")
26
+ prefix_rule(pattern=["file"], decision="allow")
27
+ prefix_rule(pattern=["stat"], decision="allow")
28
+ prefix_rule(pattern=["du"], decision="allow")
29
+ prefix_rule(pattern=["id"], decision="allow")
30
+ prefix_rule(pattern=["whoami"], decision="allow")
31
+
32
+ prefix_rule(pattern=["git", "status"], decision="allow")
33
+ prefix_rule(pattern=["git", "diff"], decision="allow")
34
+ prefix_rule(pattern=["git", "log"], decision="allow")
35
+ prefix_rule(pattern=["git", "show"], decision="allow")
36
+ prefix_rule(pattern=["git", "blame"], decision="allow")
37
+ prefix_rule(pattern=["git", "rev-parse"], decision="allow")
38
+ prefix_rule(pattern=["git", "ls-files"], decision="allow")
39
+ prefix_rule(pattern=["git", "grep"], decision="allow")
40
+ prefix_rule(pattern=["git", "ls-tree"], decision="allow")
41
+ prefix_rule(pattern=["git", "branch", "--show-current"], decision="allow")
42
+ prefix_rule(pattern=["git", "branch", "-vv"], decision="allow")
43
+ prefix_rule(pattern=["git", "mv"], decision="allow")
44
+
45
+ prefix_rule(pattern=["gh", "pr", "view"], decision="allow")
46
+ prefix_rule(pattern=["gh", "pr", "list"], decision="allow")
47
+ prefix_rule(pattern=["gh", "pr", "diff"], decision="allow")
48
+ prefix_rule(pattern=["gh", "pr", "status"], decision="allow")
49
+ prefix_rule(pattern=["gh", "pr", "checks"], decision="allow")
50
+
51
+ prefix_rule(pattern=["docker", "ps"], decision="allow")
52
+
53
+ prefix_rule(pattern=["git", "push"], decision="prompt")
54
+ prefix_rule(pattern=["git", "reset"], decision="prompt")
55
+ prefix_rule(pattern=["git", "clean"], decision="prompt")
56
+ prefix_rule(pattern=["git", "merge"], decision="prompt")
57
+ prefix_rule(pattern=["git", "rebase"], decision="prompt")
58
+ prefix_rule(pattern=["git", "checkout"], decision="prompt")
59
+
60
+ prefix_rule(pattern=["rm"], decision="prompt")
61
+ prefix_rule(pattern=["mv"], decision="prompt")
62
+ prefix_rule(pattern=["chmod"], decision="prompt")
63
+ prefix_rule(pattern=["chown"], decision="prompt")
64
+ prefix_rule(pattern=["kill"], decision="prompt")
65
+ prefix_rule(pattern=["pkill"], decision="prompt")
66
+
67
+ prefix_rule(pattern=["npm", "install"], decision="prompt")
68
+ prefix_rule(pattern=["npm", "uninstall"], decision="prompt")
69
+ prefix_rule(pattern=["pnpm", "add"], decision="prompt")
70
+ prefix_rule(pattern=["pnpm", "remove"], decision="prompt")
71
+ prefix_rule(pattern=["yarn", "add"], decision="prompt")
72
+ prefix_rule(pattern=["yarn", "remove"], decision="prompt")
73
+ prefix_rule(pattern=["pip", "install"], decision="prompt")
74
+ prefix_rule(pattern=["pip", "uninstall"], decision="prompt")
75
+ prefix_rule(pattern=["pip3", "install"], decision="prompt")
76
+ prefix_rule(pattern=["pip3", "uninstall"], decision="prompt")
77
+
78
+ prefix_rule(pattern=["docker", "run"], decision="prompt")
79
+ prefix_rule(pattern=["docker", "rm"], decision="prompt")
80
+ prefix_rule(pattern=["docker", "stop"], decision="prompt")
81
+ prefix_rule(pattern=["docker", "volume"], decision="prompt")
82
+ prefix_rule(pattern=["docker", "system"], decision="prompt")
83
+ prefix_rule(pattern=["docker", "compose", "up"], decision="prompt")
84
+ prefix_rule(pattern=["docker", "compose", "down"], decision="prompt")
85
+ prefix_rule(pattern=["docker", "compose", "rm"], decision="prompt")
86
+ prefix_rule(pattern=["docker", "compose", "stop"], decision="prompt")
87
+ prefix_rule(pattern=["docker-compose", "up"], decision="prompt")
88
+ prefix_rule(pattern=["docker-compose", "down"], decision="prompt")
89
+ prefix_rule(pattern=["docker-compose", "rm"], decision="prompt")
90
+ prefix_rule(pattern=["docker-compose", "stop"], decision="prompt")
91
+
92
+ # `tail -f`/`--follow` never returns and hangs the agent (bare `tail` stays allowed above).
93
+ prefix_rule(pattern=["tail", "-f"], decision="prompt")
94
+ prefix_rule(pattern=["tail", "--follow"], decision="prompt")
95
+ # rg and `sed -n` are prompt, NOT allow: argv-prefix matching cannot gate their
96
+ # code-exec forms (rg --pre=CMD or a reordered --pre; sed -n 'e CMD' / -ni) while a
97
+ # shorter allow prefix would auto-approve the whole command.
98
+ prefix_rule(pattern=["rg"], decision="prompt")
99
+ prefix_rule(pattern=["sed", "-n"], decision="prompt")
100
+ prefix_rule(pattern=["find"], decision="prompt")
101
+ prefix_rule(pattern=["sed", "-i"], decision="prompt")
102
+ prefix_rule(pattern=["sed", "--in-place"], decision="prompt")
103
+ prefix_rule(pattern=["awk"], decision="prompt")
104
+ prefix_rule(pattern=["xargs"], decision="prompt")
105
+ prefix_rule(pattern=["tee"], decision="prompt")
106
+ prefix_rule(pattern=["curl"], decision="prompt")
107
+ prefix_rule(pattern=["env"], decision="prompt")
108
+
109
+ prefix_rule(pattern=["sudo"], decision="forbidden")
110
+ prefix_rule(pattern=["eval"], decision="forbidden")
111
+ prefix_rule(pattern=["mkfs"], decision="forbidden")
112
+ prefix_rule(pattern=["dd"], decision="forbidden")
113
+ prefix_rule(pattern=["git", "push", "--force", "origin", "main"], decision="forbidden")
114
+ prefix_rule(pattern=["git", "push", "--force", "origin", "master"], decision="forbidden")
115
+ prefix_rule(pattern=["git", "push", "-f", "origin", "main"], decision="forbidden")
116
+ prefix_rule(pattern=["git", "push", "-f", "origin", "master"], decision="forbidden")
@@ -0,0 +1,28 @@
1
+ {
2
+ "$comment": "Kit-verified model catalog — single source for the engine validators (lib/common.sh), the docks-kit CLI (models/model commands, pickers, bare-flag help), and docs. Entries are research-proofed: update an entry and its tool-level `verified` date when a model ships or retires. The catalog informs, it doesn't imprison: well-formed IDs outside it (claude-* / codex charset) apply with a warning.",
3
+ "claude": {
4
+ "verified": "2026-07-08",
5
+ "models": [
6
+ { "id": "best", "kind": "alias", "note": "Fable 5 where the org has access, latest Opus otherwise (Claude Code >=2.1.170)" },
7
+ { "id": "opus", "kind": "alias", "note": "latest Opus (currently Opus 4.8) — the kit SoT default, paired with the fable advisor" },
8
+ { "id": "fable", "kind": "alias", "note": "Fable 5 — needs org access + Claude Code >=2.1.170" },
9
+ { "id": "sonnet", "kind": "alias", "note": "latest Sonnet (currently Sonnet 5)" },
10
+ { "id": "haiku", "kind": "alias", "note": "latest Haiku (currently Haiku 4.5)" },
11
+ { "id": "default", "kind": "alias", "note": "engine pseudo-value: deletes the deployed model key so the account default applies" },
12
+ { "id": "claude-fable-5", "kind": "id", "note": "Fable 5" },
13
+ { "id": "claude-opus-4-8", "kind": "id", "note": "Opus 4.8" },
14
+ { "id": "claude-sonnet-5", "kind": "id", "note": "Sonnet 5" },
15
+ { "id": "claude-haiku-4-5-20251001", "kind": "id", "note": "Haiku 4.5" }
16
+ ]
17
+ },
18
+ "codex": {
19
+ "verified": "2026-07-08",
20
+ "models": [
21
+ { "id": "gpt-5.5", "kind": "id", "note": "Codex default — the kit SoT pin" },
22
+ { "id": "gpt-5.5-codex", "kind": "id", "note": "codex-tuned gpt-5.5" },
23
+ { "id": "gpt-5.1", "kind": "id", "note": "previous generation" },
24
+ { "id": "gpt-5", "kind": "id", "note": "previous generation" },
25
+ { "id": "gpt-5-codex", "kind": "id", "note": "codex-tuned gpt-5" }
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "$comment": "Kit toolchain manifest — DATA only (versions, floors, policy); the check/install logic lives in lib/toolchain.sh and the per-tool install callbacks in each lib. kind: required (preflight hard dep) | check (doctor visibility only) | managed (kit installs/upgrades it) | pin (no binary probe — a version pin for a tool the kit invokes via npx). policy (managed only): track (upgrade toward latest, gated by `verified`) | present (install when missing, never upgrade). `verified` = last kit-tested version — anything above it prompts before install (--yes auto-accepts; non-TTY declines and falls back to the pinned `verified` when pinnable). Supply-chain stance: every kit-driven install is pinned to `verified` or gated by it — never floating @latest (npm-worm/Shai-Hulud surface). Update `verified` after testing a new release.",
3
+ "tools": {
4
+ "jq": { "kind": "required", "note": "settings merges + manifest reads" },
5
+ "curl": { "kind": "required", "note": "installers + usage fetch" },
6
+ "node": { "kind": "check", "note": "hosts npm globals (agent-browser, LSP servers)" },
7
+ "npm": { "kind": "check", "note": "npm-global installer" },
8
+ "claude": { "kind": "check", "floor": "2.1.170", "note": "kit floor — `best` alias + Fable 5 need >=2.1.170 (mirrors settings minimumVersion)" },
9
+ "codex": { "kind": "check", "note": "upstream-owned; standalone installer prints when missing" },
10
+ "ffplay": { "kind": "check", "note": "Notification hook sound (previously unchecked)" },
11
+ "bwrap": { "kind": "check", "os": "linux", "note": "Codex Linux sandbox runtime" },
12
+ "intelephense": { "kind": "check", "verified": "1.18.5", "note": "php-lsp server binary; `verified` pins claude::sync_lsp_servers' npm install" },
13
+ "typescript-language-server": { "kind": "check", "verified": "5.3.0", "note": "typescript-lsp server binary; `verified` pins claude::sync_lsp_servers' npm install" },
14
+ "tsc": { "kind": "check", "verified": "6.0.3", "note": "typescript-lsp dependency (npm package `typescript`); `verified` pins claude::sync_lsp_servers' npm install" },
15
+ "rtk": { "kind": "managed", "policy": "track", "floor": "0.43.0", "verified": "0.43.0", "pinnable": true,
16
+ "note": "PreToolUse hook — supply-chain review before unverified upgrades; installer honors RTK_VERSION=vX.Y.Z pin" },
17
+ "bun": { "kind": "managed", "policy": "present", "verified": "1.3.14", "pinnable": true,
18
+ "note": "runtime for effect-solutions + the docks-kit CLI; bootstrap installs the verified release (installer takes bun-vX.Y.Z); self-updates via `bun upgrade` when wanted" },
19
+ "effect-solutions": { "kind": "managed", "policy": "track", "verified": "0.5.3", "pinnable": true,
20
+ "note": "Effect docs CLI (bun global) — track keeps it self-upgrading, gated by the verified pin" },
21
+ "agent-browser": { "kind": "managed", "policy": "track", "verified": "0.31.1", "pinnable": true,
22
+ "note": "browser-automation CLI (npm global), gated by the verified pin; first install also downloads Chrome for Testing" },
23
+ "skills-cli": { "kind": "pin", "verified": "1.5.15",
24
+ "note": "the `skills` npm package the kit runs via `npx skills@<verified>` on every agents sync (universal-skill install/remove) — pinned, never @latest" }
25
+ }
26
+ }
@@ -0,0 +1,48 @@
1
+ # Flag reference
2
+
3
+ Convention: global flags are unprefixed; anything touching one tool's
4
+ deployed config is `--<tool>-<setting>`.
5
+
6
+ ## Targets (positional)
7
+
8
+ ```
9
+ docks-kit sync # all three
10
+ docks-kit sync claude # one
11
+ docks-kit sync claude agents # two
12
+ ```
13
+
14
+ ## Global flags
15
+
16
+ | Flag | Effect |
17
+ |------|--------|
18
+ | `--dry-run` | Preview without applying |
19
+ | `--reconcile` | Settings layer reconciled toward SoT (SoT keys win; user-only keys preserved; permissions arrays replaced) |
20
+ | `--prune` | Uninstall kit-managed installs not in SoT: plugins, marketplaces, universal skills |
21
+ | `--skip-rtk` | Skip optional tool bootstrap (RTK, bubblewrap) |
22
+ | `--yes` | Auto-accept toolchain above-verified prompts (containers/CI) |
23
+
24
+ ## Per-tool flags
25
+
26
+ | Flag | Effect |
27
+ |------|--------|
28
+ | `--claude-model=<m>` | Deploy-time modifier: deployed model (aliases or full claude-* IDs; `default` unsets) |
29
+ | `--claude-compact-window=<n>` | Deploy-time modifier: autocompact window in tokens (`680000` or `680k`) |
30
+ | `--claude-permissive` | Deploy-time modifier: empty permissions.ask/deny (sandboxes) |
31
+ | `--claude-plugin=<name>` | Sticky opt-in plugin (known: supabase, n8n); comma-separate for several |
32
+ | `--codex-model=<m>` | Deploy-time modifier: deployed Codex model |
33
+
34
+ Bare `--claude-model` / `--codex-model` (no value) prints the model catalog.
35
+
36
+ ## Renamed legacy flags (pre-CLI sync.sh)
37
+
38
+ Old flags exit with a rename hint — there is no compat behavior.
39
+
40
+ | Old | New |
41
+ |-----|-----|
42
+ | `--claude` / `--codex` / `--agents` | positional `claude` / `codex` / `agents` |
43
+ | `--force` | `--reconcile` |
44
+ | `--remove-plugins` | `--prune` |
45
+ | `--680k` | `--claude-compact-window=680k` |
46
+ | `--permissive` | `--claude-permissive` |
47
+ | `--supabase` / `--n8n` | `--claude-plugin=supabase` / `--claude-plugin=n8n` |
48
+ | `--no-rtk` | `--skip-rtk` |
@@ -0,0 +1,56 @@
1
+ # Installing docks-kit
2
+
3
+ ## 1. Repo checkout (development / current users)
4
+
5
+ ```
6
+ git clone https://github.com/DocksDocks/public.git ~/projects/public
7
+ cd ~/projects/public
8
+ ./docks-kit sync
9
+ ```
10
+
11
+ The `./docks-kit` launcher prefers a compiled binary in `cli/dist/`, then
12
+ falls back to Bun-from-source (auto-installing Bun via download-then-run and
13
+ `bun install --frozen-lockfile` when needed).
14
+
15
+ ## 2. Global via Bun (effect-solutions-style)
16
+
17
+ ```
18
+ bun add -g docks-kit@latest
19
+ docks-kit sync
20
+ # or one-shot, no install:
21
+ bunx docks-kit status
22
+ ```
23
+
24
+ The npm package bundles the engine (`lib/*.sh`) and the SoT — releases are
25
+ versioned config snapshots. Kit-home resolution: `DOCKS_KIT_HOME` env →
26
+ nearest ancestor directory containing `SoT/` (a checkout wins over the
27
+ bundled copy) → the package's own bundled SoT.
28
+
29
+ ## 3. curl installer
30
+
31
+ ```
32
+ curl -fsSL https://raw.githubusercontent.com/DocksDocks/public/main/install.sh -o /tmp/docks-kit-install.sh
33
+ bash /tmp/docks-kit-install.sh && rm /tmp/docks-kit-install.sh
34
+ ```
35
+
36
+ Download-then-run, never `curl | bash` — stream truncation has bitten this
37
+ kit before. The installer bootstraps Bun when absent, runs
38
+ `bun add -g docks-kit`, and links the binary into `~/.local/bin`.
39
+
40
+ ## Zero-dependency escape hatch
41
+
42
+ No Bun, no binary, constrained sandbox:
43
+
44
+ ```
45
+ bash lib/engine.sh sync [targets] [flags]
46
+ bash lib/engine.sh model claude opus
47
+ bash lib/engine.sh toolchain check
48
+ ```
49
+
50
+ Requires only bash + jq (+ curl for installers).
51
+
52
+ ## Prerequisites
53
+
54
+ - bash, jq, curl (hard requirements — preflight checks them)
55
+ - Node/npm for npm-global tools (agent-browser, LSP servers)
56
+ - See `docks-kit toolchain check` for the full picture on this machine
@@ -0,0 +1,42 @@
1
+ # Models
2
+
3
+ `SoT/models.json` is the kit-verified model catalog — the single source for
4
+ the engine validators, `docks-kit models`, the interactive picker, and the
5
+ bare-flag helper output. Each tool section carries a `verified` date; update
6
+ the entry and date when a model ships or retires.
7
+
8
+ ## Validation rules
9
+
10
+ - **Claude**: catalog aliases (`best`, `opus`, `fable`, `sonnet`, `haiku`,
11
+ `default`) and full IDs validate silently; any other `claude-*` ID is
12
+ accepted with a warning (new models outrun the catalog); everything else
13
+ exits 2 with the catalog printed.
14
+ - **Codex**: hard charset gate `^[A-Za-z0-9._-]+$` (also blocks TOML-quote
15
+ injection — the value lands inside a quoted config.toml string); catalog
16
+ misses warn but apply.
17
+
18
+ ## The `best` alias and `default` pseudo-value
19
+
20
+ - `best` resolves to Fable 5 where the org has access, latest Opus otherwise.
21
+ Needs Claude Code >= 2.1.170. (The kit SoT default is `opus`, paired with
22
+ the `fable` advisor — see the advisor note below.)
23
+ - `default` is an engine pseudo-value: it DELETES the deployed `model` key so
24
+ the account default applies. It never reaches the settings file as a value.
25
+
26
+ ## Commands
27
+
28
+ ```
29
+ docks-kit models # both catalogs
30
+ docks-kit models claude --json # machine-readable
31
+ docks-kit model claude # current deployed + SoT + picker (TTY)
32
+ docks-kit model claude fable # set deployed model
33
+ docks-kit sync claude --claude-model=opus # same, as part of a sync
34
+ ```
35
+
36
+ ## Advisor pairing note (Claude)
37
+
38
+ The advisor model must be at least as capable as the main model; Fable
39
+ outranks Opus, so an Opus main + Fable advisor works while Fable main +
40
+ Opus advisor is rejected. The SoT ships `model: opus` + `advisorModel:
41
+ fable` as the deployed-everywhere default; use settings.local.json only
42
+ for a deliberate per-machine deviation.
@@ -0,0 +1,33 @@
1
+ # Deploy-time modifiers
2
+
3
+ Modifiers change the **deployed** config for a specific machine profile —
4
+ the SoT is never touched. They all share one contract:
5
+
6
+ > A later flag-less sync reverts the modifier: the settings merge (Claude)
7
+ > and the config.toml merge (Codex) re-assert SoT values for kit-owned keys.
8
+ > Re-pass the flag on machines that should keep the override, or make it
9
+ > persistent in `~/.claude/settings.local.json` (which sync never touches).
10
+
11
+ | Modifier | Deployed change | Typical use |
12
+ |----------|-----------------|-------------|
13
+ | `--claude-model=<m>` | `.model` in ~/.claude/settings.json (`default` deletes the key) | Drop one machine to opus while the SoT stays on `best` |
14
+ | `--claude-compact-window=<n>` | `env.CLAUDE_CODE_AUTO_COMPACT_WINDOW` | Disposable containers running long autonomous work (e.g. `680k`) — not host machines |
15
+ | `--claude-permissive` | `permissions.ask = []`, `permissions.deny = []` | Sandboxes/containers where prompts stall unattended work. Never on a host — the deny list is the safety floor |
16
+ | `--codex-model=<m>` | top-level `model = "…"` in ~/.codex/config.toml | Same as claude-model, for Codex |
17
+
18
+ ## Standalone get/set (no full sync)
19
+
20
+ ```
21
+ docks-kit model claude # show deployed + SoT + catalog (+ TTY picker)
22
+ docks-kit model claude opus # set deployed model
23
+ docks-kit model claude default # delete the key (account default applies)
24
+ docks-kit model codex gpt-5.5 # codex flavor
25
+ ```
26
+
27
+ The set path calls the same engine functions as the sync flags —
28
+ one implementation, two entry points.
29
+
30
+ ## Sticky opt-ins are NOT modifiers
31
+
32
+ `--claude-plugin=<name>` installs+enables an optional plugin and it STAYS
33
+ (the SoT has no key to revert against). Only `--prune` removes it.
@@ -0,0 +1,37 @@
1
+ # docks-kit overview
2
+
3
+ docks-kit is a portable configuration kit for AI coding agents. Per-tool
4
+ Single Source of Truth (SoT) directories are deployed to each tool's
5
+ user-config location — clone once, sync everywhere, get a consistent
6
+ AI-assisted dev environment on every machine.
7
+
8
+ ## Pieces
9
+
10
+ | Piece | Role |
11
+ |-------|------|
12
+ | `SoT/.claude/` | Claude Code config (settings, hooks, status line, CLAUDE.md) |
13
+ | `SoT/.codex/` | Codex config (config.toml, rules, AGENTS.md, marketplace) |
14
+ | `SoT/.agents/` | Universal agent skills manifest (agentskills.io standard) |
15
+ | `SoT/models.json` | Kit-verified model catalog (see `docks-kit docs models`) |
16
+ | `SoT/toolchain.json` | Verified-version floors for external tools (see `docks-kit docs toolchain`) |
17
+ | `lib/*.sh` | The bash engine — all mutation logic; battle-tested, idempotent |
18
+ | `lib/engine.sh` | Engine entry: `sync`, `model`, `toolchain` — the zero-dependency escape hatch |
19
+ | `cli/` | This CLI (Effect-TS on Bun) — typed front-end over the engine |
20
+ | `docks-kit` | Launcher: compiled binary → bun-from-source, with Bun auto-install |
21
+
22
+ ## Design rules
23
+
24
+ - **Idempotent**: every sync step is safe to re-run; no-change syncs are no-ops.
25
+ - **Additive by default**: user-only keys/plugins/skills survive a plain sync.
26
+ Reconciliation toward the SoT is explicit: `--reconcile` (settings) and
27
+ `--prune` (plugins/marketplaces/skills).
28
+ - **Deploy-time modifiers** mutate deployed config only — the SoT never
29
+ changes, and a later flag-less sync reverts them (`docks-kit docs modifiers`).
30
+ - **Engine/CLI split**: the CLI adds UX (typed flags, pickers, docs, JSON);
31
+ the engine owns mutation. `bash lib/engine.sh <same args>` always works.
32
+
33
+ ## Where to go next
34
+
35
+ - `docks-kit docs sync-layers` — what a sync actually touches
36
+ - `docks-kit docs flags` — full flag reference + old→new renames
37
+ - `docks-kit status` — live doctor view of this machine
@@ -0,0 +1,31 @@
1
+ # Platform support
2
+
3
+ | Platform | CLI (docks-kit) | Sync engine | Notes |
4
+ |----------|-----------------|-------------|-------|
5
+ | Linux | native | native | Primary target |
6
+ | macOS | native (x64 + arm64) | native | bash 3.2-compatible engine |
7
+ | Windows | native (binary/Bun) | **experimental via Git Bash**; full hooks under WSL | See below |
8
+
9
+ ## Windows detail
10
+
11
+ The managed tools all run natively on Windows: Claude Code (requires Git
12
+ Bash for its Bash tool — so Git Bash is present on any Windows machine
13
+ running Claude Code), Codex CLI (native PowerShell + Windows sandbox),
14
+ RTK (native binaries via GitHub releases/winget — but its PreToolUse hook
15
+ mechanism is Unix-only; Windows falls back to RTK's `--claude-md` mode).
16
+
17
+ The kit's engine is bash+jq, so on Windows it runs under Git Bash. Status:
18
+ **experimental and not yet verified on a real Windows machine** — expect
19
+ rough edges around:
20
+
21
+ - shell-rc env exports (needs `setx` translation)
22
+ - the notification hook (ffplay)
23
+ - bubblewrap (Linux-only; skipped)
24
+
25
+ For full fidelity (RTK hooks included), run the kit inside WSL.
26
+
27
+ ## Roadmap
28
+
29
+ A native TypeScript engine (module-by-module port inside the CLI, swappable
30
+ behind the same seam) would remove the Git Bash requirement entirely. Tracked
31
+ as a follow-up plan — not part of the current CLI.
@@ -0,0 +1,44 @@
1
+ # Plugins: the enabledPlugins tri-state
2
+
3
+ `SoT/.claude/settings.json` → `enabledPlugins` values carry three meanings:
4
+
5
+ | Value | Meaning | `--prune` |
6
+ |-------|---------|-----------|
7
+ | `true` | Installed + enabled in every project | keeps installed |
8
+ | `false` | Installed + globally disabled; a project's `.claude/settings.json` can flip it to `true` per-repo | keeps installed |
9
+ | key absent | Not installed | uninstalls if present |
10
+
11
+ The user-scope key MUST stay present (as `false`) for per-project
12
+ re-enablement to work — Claude Code ignores project-level entries whose key
13
+ is absent from user settings.
14
+
15
+ ## Sync passes (idempotent, via the `claude plugin` CLI)
16
+
17
+ 1. Add SoT marketplaces not yet known
18
+ 2. Install SoT-declared plugins missing at user scope
19
+ 3. Refresh marketplace manifests; update installed plugins
20
+ 4. (`--prune` only) uninstall plugins / remove marketplaces not in SoT
21
+ 5. Re-assert SoT enabled-state (undoes install's enable side effect on
22
+ false-keyed plugins)
23
+
24
+ ## Optional opt-ins
25
+
26
+ Situational plugins are kept OUT of the SoT and opted in per machine:
27
+
28
+ ```
29
+ docks-kit sync claude --claude-plugin=supabase
30
+ docks-kit sync claude --claude-plugin=supabase,n8n
31
+ ```
32
+
33
+ Opt-ins are STICKY: with no SoT key to revert against, a later flag-less
34
+ sync leaves them alone; only `--prune` uninstalls them.
35
+
36
+ Caveat (supabase): its bundled MCP server's OAuth is account-global — the
37
+ opt-in only fits while every repo on the machine shares one Supabase account;
38
+ otherwise pin a per-repo .mcp.json instead.
39
+
40
+ ## Inspect
41
+
42
+ ```
43
+ docks-kit plugins list [--json]
44
+ ```
@@ -0,0 +1,43 @@
1
+ # Sync layers
2
+
3
+ `docks-kit sync [claude] [codex] [agents]` — targets are positional words;
4
+ no target means all three.
5
+
6
+ ## claude (→ ~/.claude, ~/.claude.json, shell rc)
7
+
8
+ Order matters — toolchain first, config after:
9
+
10
+ 1. **RTK** (toolchain-gated): install/upgrade, then `rtk init --global` on
11
+ first install. Runs FIRST because rtk init rewrites settings.json — the
12
+ later settings merge normalizes whatever it wrote.
13
+ 2. Scripts (statusline, fetch-usage, notification.mp3), hooks, CLAUDE.md.
14
+ 3. **settings.json merge** — additive: SoT keys win, permissions arrays are
15
+ unioned, user-only keys survive. `--reconcile` replaces permissions arrays
16
+ wholesale instead.
17
+ 4. **Deploy-time modifiers** (`--claude-compact-window`, `--claude-permissive`,
18
+ `--claude-model`) — deployed file only.
19
+ 5. ~/.claude.json (showTurnDuration, user-scoped MCP servers), connector env
20
+ export, removed-artifact pruning.
21
+ 6. **Plugins** — seven idempotent passes via the `claude plugin` CLI
22
+ (marketplaces → install → update → [--prune: uninstall/remove] → re-assert
23
+ SoT enabled-state). Optional opt-ins via `--claude-plugin=<name>`.
24
+ 7. LSP server binaries (npm globals).
25
+
26
+ ## codex (→ ~/.codex, ~/.agents/plugins)
27
+
28
+ bubblewrap check (Linux), config.toml merge (top-level keys replaced
29
+ per-key, [table] blocks replaced wholesale, user-only keys/tables preserved),
30
+ `--codex-model` modifier, rules, AGENTS.md, personal marketplace file,
31
+ `codex plugin add` refresh.
32
+
33
+ ## agents (→ ~/.agents/skills, ~/.claude/skills symlinks)
34
+
35
+ `npx skills add` per missing manifest slug, Claude symlink healing,
36
+ CLI binaries (agent-browser, effect-solutions — toolchain-gated), and the
37
+ kit-managed snapshot that `--prune` reconciles against.
38
+
39
+ ## Reconcile flags
40
+
41
+ - `--reconcile` — settings layer: SoT-declared keys win; user-only preserved.
42
+ - `--prune` — plugins + marketplaces + kit-managed skills not in SoT are removed.
43
+ - Combine for a full reset to the SoT's kit-managed scope.
@@ -0,0 +1,54 @@
1
+ # Toolchain: verified-version floors
2
+
3
+ `SoT/toolchain.json` declares every external tool the kit touches, with:
4
+
5
+ | Field | Meaning |
6
+ |-------|---------|
7
+ | `kind` | `required` (preflight hard dep) / `check` (doctor visibility) / `managed` (kit installs + upgrades) / `pin` (no binary — a version pin for npx-invoked tools, e.g. `skills-cli`) |
8
+ | `policy` | `track` (upgrade toward latest, gated by `verified`) / `present` (install when missing, never upgrade) |
9
+ | `floor` | Minimum acceptable version (below → upgrade automatically) |
10
+ | `verified` | Last kit-tested version — the gate line |
11
+ | `pinnable` | Whether an exact version can be installed (rtk: `RTK_VERSION=vX.Y.Z`) |
12
+
13
+ ## The gate
14
+
15
+ When an install/upgrade candidate is **above `verified`**:
16
+
17
+ - **TTY**: prompt — "X <latest> is not kit-verified (verified: <v>). Install anyway? [y/N]"
18
+ - **`--yes`**: proceed with a warning (containers/CI)
19
+ - **non-TTY, declined**:
20
+ - install mode (tool missing) + pinnable → install the pinned `verified` version
21
+ - upgrade mode → stay on the installed version, warn
22
+
23
+ At or below `verified`, installs/upgrades run silently. After testing a new
24
+ release, bump `verified` in SoT/toolchain.json — that is the "this version is
25
+ now kit-approved" act.
26
+
27
+ ## Managed tools
28
+
29
+ - **rtk** — PreToolUse hook (supply-chain sensitive: review releases before
30
+ bumping `verified`). Runs FIRST in the claude sync so `rtk init`'s
31
+ settings rewrite is normalized by the merge that follows. Pinned installs
32
+ fetch the installer script from the version tag, not mutable master.
33
+ - **bun** — policy `present`: bootstrap only (pinned to `verified` via the
34
+ installer's `bun-vX.Y.Z` release-tag argument), never auto-upgraded.
35
+ - **effect-solutions**, **agent-browser** — policy `track`: self-upgrade
36
+ toward npm latest, gated by their `verified` pins.
37
+
38
+ ## Supply-chain stance
39
+
40
+ Every kit-driven install is pinned to a `verified` version or gated by one —
41
+ never floating `@latest` (the npm-worm / Shai-Hulud attack surface). That
42
+ includes the `npx skills@<verified>` invocations on every agents sync, the
43
+ `chrome-devtools-mcp` MCP server pin in SoT/.claude/mcp-servers.json, and the
44
+ release workflow (actions pinned to commit SHAs, exact bun/npm versions).
45
+ Callbacks receive the exact gate-approved version; an offline "latest unknown"
46
+ probe falls back to the pinned `verified`, never to an ungated latest.
47
+
48
+ ## Commands
49
+
50
+ ```
51
+ docks-kit toolchain check # doctor table (also inside docks-kit status)
52
+ docks-kit toolchain ensure rtk # install/upgrade one tool per policy
53
+ docks-kit sync --yes # unattended: auto-accept gates
54
+ ```
@@ -0,0 +1,65 @@
1
+ import { Args, Command, Options } from "@effect/cli"
2
+ import { Console, Effect, Option } from "effect"
3
+ import { bail } from "../engine"
4
+ import overview from "../../docs/overview.md" with { type: "text" }
5
+ import flags from "../../docs/flags.md" with { type: "text" }
6
+ import modifiers from "../../docs/modifiers.md" with { type: "text" }
7
+ import models from "../../docs/models.md" with { type: "text" }
8
+ import toolchain from "../../docs/toolchain.md" with { type: "text" }
9
+ import plugins from "../../docs/plugins.md" with { type: "text" }
10
+ import syncLayers from "../../docs/sync-layers.md" with { type: "text" }
11
+ import install from "../../docs/install.md" with { type: "text" }
12
+ import platforms from "../../docs/platforms.md" with { type: "text" }
13
+
14
+ const TOPICS: Record<string, { summary: string; body: string }> = {
15
+ "overview": { summary: "What docks-kit is and how the pieces fit", body: overview },
16
+ "sync-layers": { summary: "The three sync layers and additive-by-default semantics", body: syncLayers },
17
+ "flags": { summary: "Full flag reference incl. the old→new rename table", body: flags },
18
+ "modifiers": { summary: "Deploy-time modifiers and the flag-less-sync-reverts contract", body: modifiers },
19
+ "models": { summary: "Model catalog, validation rules, model get/set", body: models },
20
+ "toolchain": { summary: "Verified-version floors, gate policy, --yes semantics", body: toolchain },
21
+ "plugins": { summary: "enabledPlugins tri-state + optional plugin opt-ins", body: plugins },
22
+ "install": { summary: "Install paths: repo checkout, bun add -g, curl installer", body: install },
23
+ "platforms": { summary: "Platform support: Linux/macOS native, Windows via Git Bash/WSL", body: platforms }
24
+ }
25
+
26
+ const topic = Args.text({ name: "topic" }).pipe(
27
+ Args.withDescription(`One of: ${Object.keys(TOPICS).join(", ")}`),
28
+ Args.optional
29
+ )
30
+ const json = Options.boolean("json").pipe(
31
+ Options.withDescription("List topics as JSON")
32
+ )
33
+
34
+ export const docsCommand = Command.make("docs", { topic, json }, (config) =>
35
+ Effect.gen(function* () {
36
+ const requested = Option.getOrUndefined(config.topic)
37
+
38
+ if (requested === undefined) {
39
+ if (config.json) {
40
+ return yield* Console.log(
41
+ JSON.stringify(
42
+ Object.entries(TOPICS).map(([name, t]) => ({ name, summary: t.summary })),
43
+ null,
44
+ 2
45
+ )
46
+ )
47
+ }
48
+ yield* Console.log("docks-kit documentation topics (docks-kit docs <topic>):\n")
49
+ for (const [name, t] of Object.entries(TOPICS)) {
50
+ yield* Console.log(` ${name.padEnd(14)} ${t.summary}`)
51
+ }
52
+ return
53
+ }
54
+
55
+ const entry = TOPICS[requested]
56
+ if (entry === undefined) {
57
+ return yield* bail(`Unknown topic '${requested}'. Valid: ${Object.keys(TOPICS).join(", ")}`)
58
+ }
59
+ yield* Console.log(entry.body)
60
+ })
61
+ ).pipe(
62
+ Command.withDescription(
63
+ "Self-documentation: the kit's concepts as readable topics, bundled with the CLI — a fresh agent can learn the kit from here alone."
64
+ )
65
+ )