shmakk 1.2.4 → 1.2.5

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 (51) hide show
  1. package/.env.example +11 -0
  2. package/README.md +75 -1
  3. package/docs/index.html +154 -16
  4. package/docs/mcp.md +78 -0
  5. package/docs/ssh.md +82 -0
  6. package/docs/vibedit-analysis.md +375 -0
  7. package/docs/vim.md +110 -0
  8. package/docs/voice.md +4 -0
  9. package/package.json +9 -5
  10. package/scripts/test-vibedit.js +45 -0
  11. package/scripts/vibedit-demo.sh +52 -0
  12. package/skills/shmakk-skill-creator.md +269 -0
  13. package/src/_check.js +7 -0
  14. package/src/_check_schema.js +5 -0
  15. package/src/_cleanup.js +18 -0
  16. package/src/_fix.js +9 -0
  17. package/src/_test_import.js +15 -0
  18. package/src/agent.js +11 -4
  19. package/src/browser-daemon.js +209 -0
  20. package/src/browser.js +10 -0
  21. package/src/cli/browserDaemon.js +60 -0
  22. package/src/cli/connectBrowser.js +137 -0
  23. package/src/cli.js +235 -8
  24. package/src/completions.js +8 -0
  25. package/src/control.js +273 -1
  26. package/src/core/browserConnector.js +523 -0
  27. package/src/electron.js +305 -0
  28. package/src/endpoints.js +74 -9
  29. package/src/index.js +24 -1
  30. package/src/llm.js +501 -61
  31. package/src/mobile.js +307 -0
  32. package/src/notify.js +51 -3
  33. package/src/orchestrator.js +35 -1
  34. package/src/pty.js +11 -6
  35. package/src/review.js +45 -11
  36. package/src/self-commands.js +153 -0
  37. package/src/session-convert.js +508 -0
  38. package/src/session-search.js +31 -0
  39. package/src/session.js +384 -46
  40. package/src/skills/browserActions.ts +984 -0
  41. package/src/skills.js +451 -24
  42. package/src/system-prompt.js +31 -25
  43. package/src/tools.js +81 -0
  44. package/src/vibedit/control.js +534 -0
  45. package/src/vibedit/electron.js +108 -0
  46. package/src/vibedit/files.js +171 -0
  47. package/src/vibedit/index.js +298 -0
  48. package/src/vibedit/overlay.js +1482 -0
  49. package/src/vibedit/prompts.js +245 -0
  50. package/src/vibedit/state.js +32 -0
  51. package/src/vim.js +410 -0
package/.env.example CHANGED
@@ -10,6 +10,17 @@ SHMAKK_MODEL=gpt-4o-mini
10
10
  # Optional extra headers (k=v,k=v)
11
11
  # SHMAKK_HEADERS=
12
12
 
13
+ # ── Vibedit: screenshot → vision LLM ──
14
+ # Direct vision endpoint URL (takes precedence over endpoints.json entries).
15
+ # Point this at a vision-capable endpoint (LM Studio, Ollama, OpenAI, etc.)
16
+ # VISION_API_URL=http://127.0.0.1:1234/v1
17
+
18
+ # Vision model name (default: qwen/qwen3.5-9b)
19
+ # VISION_MODEL=qwen/qwen3.5-9b
20
+
21
+ # API key for vision endpoint (falls back to SHMAKK_API_KEY)
22
+ # VISION_API_KEY=
23
+
13
24
  # Voice input (microphone → Whisper API / local faster-whisper transcription)
14
25
 
15
26
  ## Option A — local faster-whisper server (no API key needed)
package/README.md CHANGED
@@ -38,6 +38,7 @@ Or configure multiple native model providers in `~/.config/shmakk/endpoints.json
38
38
  ```json
39
39
  {
40
40
  "main": "gpt5-codex",
41
+ "fast": "flash",
41
42
  "models": {
42
43
  "gpt5-codex": {
43
44
  "provider": "codex",
@@ -53,6 +54,11 @@ Or configure multiple native model providers in `~/.config/shmakk/endpoints.json
53
54
  "provider": "anthropic",
54
55
  "model": "claude-sonnet-4-5-20250929",
55
56
  "api_key": "ANTHROPIC_API_KEY"
57
+ },
58
+ "flash": {
59
+ "provider": "google",
60
+ "model": "gemini-flash",
61
+ "api_key": "GOOGLE_API_KEY"
56
62
  }
57
63
  }
58
64
  }
@@ -75,6 +81,40 @@ You're now in an AI-supervised terminal. Type commands as normal. shmakk will:
75
81
  - **Execute tasks** — ask "set up a new React project" and shmakk handles the steps
76
82
  - **Keep you safe** — confirms risky commands before running them
77
83
 
84
+ ## Vim / vi mode
85
+
86
+ By default, shmakk intercepts `vi` inside a shmakk session. Use `--vim vim` to intercept `vim`, or `--vim disable` to leave both commands untouched.
87
+
88
+ ```bash
89
+ shmakk --vim vi
90
+ shmakk --vim vim
91
+ shmakk --vim disable
92
+ ```
93
+
94
+ The shim launches your real Vim with your normal config, then loads shmakk commands:
95
+
96
+ | Vim command | What it does |
97
+ |-------------|--------------|
98
+ | `:G <prompt>` | Generate code at the cursor |
99
+ | `:Tw <prompt>` | Write prose or documentation |
100
+ | `:Cmd <command>` | Run a shell command in a scratch buffer |
101
+ | `<C-Space>` / `:ShmakkSuggest` | Full-block AI suggestion with preview + Accept/Deny |
102
+ | `:ShmakkAccept` / `:ShmakkPreview` / `:ShmakkDeny` | Handle pending auto-suggestions |
103
+
104
+ Lowercase `:g` remains Vim's native `:global`; use uppercase `:G` for shmakk. Regular Vim commands such as `:%s/foo/bar/g` continue to work.
105
+
106
+ Optional automatic suggestions:
107
+
108
+ ```vim
109
+ let g:shmakk_auto_suggest = 1
110
+ let g:shmakk_auto_suggest_delay_ms = 2000
111
+ let g:shmakk_auto_suggest_min_chars = 20
112
+ ```
113
+
114
+ Suggestions prefer a fast model endpoint. Configure `"fast"` in `endpoints.json`, or set `SHMAKK_FAST_ENDPOINT` / `SHMAKK_VIM_SUGGEST_ENDPOINT`.
115
+
116
+ → Full Vim documentation: [docs/vim.md](docs/vim.md)
117
+
78
118
  ## Voice (optional)
79
119
 
80
120
  speak naturally — shmakk listens, transcribes, responds, and reads its answer aloud. No push-to-talk.
@@ -138,9 +178,14 @@ The coordinator system enables complex, multi-step task execution with plan-firs
138
178
  | `SHMAKK_BASE_URL` | OpenAI-compatible base URL |
139
179
  | `SHMAKK_API_KEY` | API key |
140
180
  | `SHMAKK_MODEL` | Default model |
141
- | `SHMAKK_PROVIDER` | `openai-compatible`, `codex`, or `anthropic` |
181
+ | `SHMAKK_FAST_ENDPOINT` | Named endpoint for low-latency tasks |
182
+ | `SHMAKK_VIM_SUGGEST_ENDPOINT` | Named endpoint for Vim suggestions |
183
+ | `SHMAKK_PROVIDER` | `openai-compatible`, `codex`, `anthropic`, or `google` |
142
184
  | `SHMAKK_HEADERS` | Extra headers (k=v,k=v) |
143
185
  | `SHMAKK_MODEL_RECOMMENDATION` | Set to `1` to let the configured `main` model route each call |
186
+ | `SHMAKK_VIM_SUGGEST_MAX_CHARS` | Max context chars sent for Vim suggestions |
187
+ | `SHMAKK_VIM_SUGGEST_BEFORE_LINES` | Context lines before cursor for Vim suggestions |
188
+ | `SHMAKK_VIM_SUGGEST_AFTER_LINES` | Context lines after cursor for Vim suggestions |
144
189
 
145
190
  ## Useful commands
146
191
 
@@ -163,6 +208,33 @@ The coordinator system enables complex, multi-step task execution with plan-firs
163
208
  | `shmakk --sts` | Speech-to-speech mode |
164
209
  | `shmakk --stt` | Mic input, text responses |
165
210
  | `shmakk --tts` | Text input, spoken responses |
211
+ | `shmakk --vim vi\|vim\|disable` | Select vi/vim interception mode |
212
+ | `shmakk --mcp-status` | Show MCP server/tool status |
213
+
214
+ ## MCP tools
215
+
216
+ shmakk can connect to Model Context Protocol servers over stdio. Configure servers in `.shmakk/mcp.json` for a workspace or `~/.config/shmakk/mcp.json` globally:
217
+
218
+ ```json
219
+ {
220
+ "mcpServers": {
221
+ "example": {
222
+ "command": "node",
223
+ "args": ["server.js"],
224
+ "env": { "TOKEN": "${TOKEN}" },
225
+ "safety": "uncertain",
226
+ "safeTools": ["read_status"],
227
+ "unsafeTools": ["delete_item"],
228
+ "timeout": 30000,
229
+ "disabled": false
230
+ }
231
+ }
232
+ }
233
+ ```
234
+
235
+ Use `shmakk --mcp-status` or the in-session `mcp status` command to inspect discovered servers and tools. MCP tools participate in the same safety confirmation system as built-in tools.
236
+
237
+ → Full MCP documentation: [docs/mcp.md](docs/mcp.md)
166
238
 
167
239
  ## Safety
168
240
 
@@ -210,6 +282,8 @@ Host *
210
282
 
211
283
  Then `mkdir -p ~/.ssh/controlmasters` once.
212
284
 
285
+ → Full SSH documentation: [docs/ssh.md](docs/ssh.md)
286
+
213
287
  ## How it works
214
288
 
215
289
  shmakk wraps your shell in a PTY (pseudo-terminal). Every command that fails is checked against a deterministic correction engine (no LLM, no API call). If a correction matches and the fixed command succeeds, shmakk feeds the agent your **original input** (not the fixed command) so the agent can address your full intent — not just the typo. You can also give task instructions in natural language — shmakk uses tools to read files, write code, list directories, and run commands, all constrained to your workspace.
package/docs/index.html CHANGED
@@ -288,8 +288,14 @@ body {
288
288
 
289
289
  <div class="tabs">
290
290
  <button class="tab active" onclick="go('chat')">chat</button>
291
+ <button class="tab" onclick="go('natural')">natural language</button>
291
292
  <button class="tab" onclick="go('project')">project builder</button>
292
293
  <button class="tab" onclick="go('typo')">typo correction</button>
294
+ <button class="tab" onclick="go('vim')">vim</button>
295
+ <button class="tab" onclick="go('endpoints')">endpoints</button>
296
+ <button class="tab" onclick="go('mcp')">mcp</button>
297
+ <button class="tab" onclick="go('ssh')">ssh</button>
298
+ <button class="tab" onclick="go('self')">self commands</button>
293
299
  <button class="tab" onclick="go('skills')">skills</button>
294
300
  <button class="tab" onclick="go('profiles')">profiles</button>
295
301
  <button class="tab voice-tab" onclick="go('voice')">voice</button>
@@ -325,6 +331,26 @@ body {
325
331
  <div class="ln" data-d="4700"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/D/r/s/demo-deepseek</span><span class="muted">&gt;</span> <span class="cur"></span></div>
326
332
  </div>
327
333
 
334
+ <!-- NATURAL LANGUAGE -->
335
+ <div class="panel" id="panel-natural">
336
+ <div class="ln" data-d="0"><span class="muted"># natural language becomes a tool plan, not blind shell text</span></div>
337
+ <div class="ln" data-d="160">&nbsp;</div>
338
+ <div class="ln" data-d="260"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/Downloads/log-archive</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">delete</span> all files from every tuesday between 11 and 12 from the last 8 weeks</span></div>
339
+ <div class="ln" data-d="650"><span class="task-label">[shmakk task] (Ctrl-C to interrupt)</span></div>
340
+ <div class="ln" data-d="950"><span class="thinking">⊥ planning with safety constraints...</span></div>
341
+ <div class="ln" data-d="1350"><span class="ai-out">I will first list matching files, show the count, then ask before deleting.</span></div>
342
+ <div class="ln" data-d="1650"><span class="tool-arrow">→</span> <span class="tool-name">run(find . -type f -newermt "8 weeks ago" -printf ...)</span></div>
343
+ <div class="ln" data-d="2050"><span class="tool-result"> matched 37 files · Tuesday · modified 11:00:00-11:59:59</span></div>
344
+ <div class="ln" data-d="2300"><span class="tool-result"> ./2026-04-21/app-11-14.log</span></div>
345
+ <div class="ln" data-d="2450"><span class="tool-result"> ./2026-05-05/app-11-48.log</span></div>
346
+ <div class="ln" data-d="2600"><span class="tool-result"> ./2026-05-26/debug-11-31.tmp</span></div>
347
+ <div class="ln" data-d="2800"><span class="muted"> ...34 more</span></div>
348
+ <div class="ln" data-d="3200"><span class="confirm">Delete these 37 files? [y/N] </span><span class="user-input">n</span></div>
349
+ <div class="ln" data-d="3500"><span class="ai-out">Nothing deleted. I can write the exact deletion command to a script if you want to review it.</span></div>
350
+ <div class="ln" data-d="3900">&nbsp;</div>
351
+ <div class="ln" data-d="4000"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/Downloads/log-archive</span><span class="muted">&gt;</span> <span class="cur"></span></div>
352
+ </div>
353
+
328
354
  <!-- PROJECT -->
329
355
  <div class="panel" id="panel-project">
330
356
  <div class="ln" data-d="0"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/D/r/s/demo-deepseek</span><span class="muted"> (main)&gt;</span> <span class="user-input"><span class="cmd-first">set</span> up a react and flask project with a login page using oauth, follow best practice and set it up with docker compose and add redis and mongodb</span></div>
@@ -373,27 +399,119 @@ body {
373
399
  <div class="ln" data-d="4300"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/D/r/s/demo-deepseek</span><span class="muted">&gt;</span> <span class="cur"></span></div>
374
400
  </div>
375
401
 
402
+ <!-- VIM -->
403
+ <div class="panel" id="panel-vim">
404
+ <div class="ln" data-d="0"><span class="muted"># real vi/vim, your config, plus shmakk commands</span></div>
405
+ <div class="ln" data-d="180"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/api</span><span class="muted">&gt;</span> <span class="white">shmakk --vim vi</span></div>
406
+ <div class="ln" data-d="520"><span class="muted">[shmakk] vi shim active. real editor config still loads.</span></div>
407
+ <div class="ln" data-d="850"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/api</span><span class="muted">&gt;</span> <span class="white">vi src/auth.js</span></div>
408
+ <div class="ln" data-d="1250"><span class="muted">:G create a JWT refresh token validator</span></div>
409
+ <div class="ln" data-d="1550"><span class="muted">[shmakk] generating...</span></div>
410
+ <div class="ln" data-d="2150"><span class="code">function validateRefreshToken(token, secret) {</span></div>
411
+ <div class="ln" data-d="2300"><span class="code"> const payload = jwt.verify(token, secret);</span></div>
412
+ <div class="ln" data-d="2450"><span class="code"> if (payload.type !== 'refresh') throw new Error('invalid token type');</span></div>
413
+ <div class="ln" data-d="2600"><span class="code"> return payload;</span></div>
414
+ <div class="ln" data-d="2750"><span class="code">}</span></div>
415
+ <div class="ln" data-d="3100">&nbsp;</div>
416
+ <div class="ln" data-d="3200"><span class="muted">press &lt;C-Space&gt;</span></div>
417
+ <div class="ln" data-d="3500"><span class="muted">[shmakk] suggesting...</span></div>
418
+ <div class="ln" data-d="4050"><span class="ai-out">[shmakk-suggestion] preview opened · Accept / Deny</span></div>
419
+ <div class="ln" data-d="4350"><span class="muted">:Cmd npm test -- auth</span></div>
420
+ <div class="ln" data-d="4650"><span class="tool-result">$ npm test -- auth</span></div>
421
+ <div class="ln" data-d="4800"><span class="tool-result">exit 0 · 12 tests passed</span></div>
422
+ </div>
423
+
424
+ <!-- ENDPOINTS -->
425
+ <div class="panel" id="panel-endpoints">
426
+ <div class="ln" data-d="0"><span class="muted"># one registry, separate main and fast model roles</span></div>
427
+ <div class="ln" data-d="220"><span class="code">~/.config/shmakk/endpoints.json</span></div>
428
+ <div class="ln" data-d="520"><span class="code">{ "main": "pro", "fast": "flash", "models": {</span></div>
429
+ <div class="ln" data-d="760"><span class="code"> "pro": { "provider": "google", "model": "gemini-pro" },</span></div>
430
+ <div class="ln" data-d="1000"><span class="code"> "flash": { "provider": "google", "model": "gemini-flash" }</span></div>
431
+ <div class="ln" data-d="1240"><span class="code">}}</span></div>
432
+ <div class="ln" data-d="1650">&nbsp;</div>
433
+ <div class="ln" data-d="1750"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="white">shmakk --endpoint pro</span></div>
434
+ <div class="ln" data-d="2100"><span class="ai-out">main model: pro · fast model: flash</span></div>
435
+ <div class="ln" data-d="2450"><span class="tool-result">agent planning / edits → pro</span></div>
436
+ <div class="ln" data-d="2700"><span class="tool-result">vim suggestions / low latency → flash</span></div>
437
+ <div class="ln" data-d="3050">&nbsp;</div>
438
+ <div class="ln" data-d="3150"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">use</span> endpoint claude</span></div>
439
+ <div class="ln" data-d="3550"><span class="ai-out">active endpoint switched to claude. fast remains flash.</span></div>
440
+ </div>
441
+
442
+ <!-- MCP -->
443
+ <div class="panel" id="panel-mcp">
444
+ <div class="ln" data-d="0"><span class="muted"># stdio MCP servers become shmakk tools</span></div>
445
+ <div class="ln" data-d="220"><span class="code">.shmakk/mcp.json</span></div>
446
+ <div class="ln" data-d="520"><span class="code">{ "mcpServers": { "github": {</span></div>
447
+ <div class="ln" data-d="760"><span class="code"> "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"],</span></div>
448
+ <div class="ln" data-d="1000"><span class="code"> "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" },</span></div>
449
+ <div class="ln" data-d="1240"><span class="code"> "safety": "uncertain", "safeTools": ["search_issues"]</span></div>
450
+ <div class="ln" data-d="1480"><span class="code">}}}</span></div>
451
+ <div class="ln" data-d="1850"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="white">shmakk --mcp-status</span></div>
452
+ <div class="ln" data-d="2200"><span class="tool-result">github: running · 14 tools discovered</span></div>
453
+ <div class="ln" data-d="2450"><span class="tool-result"> github.search_issues safe</span></div>
454
+ <div class="ln" data-d="2650"><span class="tool-result"> github.create_issue uncertain</span></div>
455
+ <div class="ln" data-d="2950">&nbsp;</div>
456
+ <div class="ln" data-d="3050"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">find</span> open bugs mentioning oauth callback</span></div>
457
+ <div class="ln" data-d="3450"><span class="tool-arrow">→</span> <span class="tool-name">github.search_issues({query:"oauth callback"})</span></div>
458
+ <div class="ln" data-d="3900"><span class="ai-out">Found 3 related issues. The newest regression is #482.</span></div>
459
+ </div>
460
+
461
+ <!-- SSH -->
462
+ <div class="panel" id="panel-ssh">
463
+ <div class="ln" data-d="0"><span class="muted"># remote hosts are explicit, named, and still safety-gated</span></div>
464
+ <div class="ln" data-d="220"><span class="code">.shmakk/hosts.json</span></div>
465
+ <div class="ln" data-d="500"><span class="code">{ "hosts": { "staging": {</span></div>
466
+ <div class="ln" data-d="740"><span class="code"> "host": "deploy@10.0.0.5", "port": 2247, "timeout_sec": 30</span></div>
467
+ <div class="ln" data-d="980"><span class="code">}}}</span></div>
468
+ <div class="ln" data-d="1350"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">check</span> staging disk and restart api if it is healthy</span></div>
469
+ <div class="ln" data-d="1750"><span class="tool-arrow">→</span> <span class="tool-name">ssh_run(staging, df -h /srv/app)</span></div>
470
+ <div class="ln" data-d="2150"><span class="tool-result"> /srv/app 42G used 68G free</span></div>
471
+ <div class="ln" data-d="2450"><span class="tool-arrow">→</span> <span class="tool-name">ssh_run(staging, systemctl status api)</span></div>
472
+ <div class="ln" data-d="2850"><span class="tool-result"> active (running)</span></div>
473
+ <div class="ln" data-d="3150"><span class="confirm">Run remote restart on staging? [y/N] </span><span class="user-input">y</span></div>
474
+ <div class="ln" data-d="3450"><span class="tool-arrow">→</span> <span class="tool-name">ssh_run(staging, sudo systemctl restart api)</span></div>
475
+ <div class="ln" data-d="3900"><span class="ai-out">Restarted. Health check returned 200 OK.</span></div>
476
+ </div>
477
+
478
+ <!-- SELF COMMANDS -->
479
+ <div class="panel" id="panel-self">
480
+ <div class="ln" data-d="0"><span class="muted"># self commands control shmakk itself, not your shell</span></div>
481
+ <div class="ln" data-d="260"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">show</span> plan</span></div>
482
+ <div class="ln" data-d="620"><span class="shmakk-section">Plan · auth migration</span></div>
483
+ <div class="ln" data-d="850"><span class="tool-result"> [x] inspect routes</span></div>
484
+ <div class="ln" data-d="1050"><span class="tool-result"> [ ] migrate token store</span></div>
485
+ <div class="ln" data-d="1250"><span class="tool-result"> [ ] add regression tests</span></div>
486
+ <div class="ln" data-d="1650"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">mcp</span> status</span></div>
487
+ <div class="ln" data-d="2050"><span class="tool-result">browser: running · github: running · obs: disabled</span></div>
488
+ <div class="ln" data-d="2450"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">set</span> model to flash</span></div>
489
+ <div class="ln" data-d="2850"><span class="ai-out">model set to flash</span></div>
490
+ <div class="ln" data-d="3250"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">review</span> edits</span></div>
491
+ <div class="ln" data-d="3650"><span class="ai-out">opening edit review for 4 pending file changes...</span></div>
492
+ </div>
493
+
376
494
  <!-- SKILLS -->
377
495
  <div class="panel" id="panel-skills">
378
- <div class="ln" data-d="0"><span class="muted"># install a skill from any URL — shmakk handles the rest</span></div>
496
+ <div class="ln" data-d="0"><span class="muted"># workspace and global skill registries</span></div>
379
497
  <div class="ln" data-d="100">&nbsp;</div>
380
- <div class="ln" data-d="200"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">shmakk</span> --install-skill https://example.com/skills/rust-expert.md</span></div>
498
+ <div class="ln" data-d="200"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">shmakk</span> --install-skill https://example.com/skills/rust-expert.md</span></div>
381
499
  <div class="ln" data-d="600"><span class="task-label">[shmakk task] (Ctrl-C to interrupt)</span></div>
382
500
  <div class="ln" data-d="900"><span class="thinking">⊥ fetching skill...</span></div>
383
501
  <div class="ln" data-d="1500"><span class="tool-result"> fetched: rust-expert.md (2.1 KB)</span></div>
384
- <div class="ln" data-d="1700"><span class="tool-result"> installed to: ~/.shmakk/skills/rust-expert</span></div>
385
- <div class="ln" data-d="1900"><span class="ai-out">Skill 'rust-expert' ready. It will be loaded automatically</span></div>
386
- <div class="ln" data-d="2000"><span class="ai-out">when relevant context is detected.</span></div>
502
+ <div class="ln" data-d="1700"><span class="tool-result"> registered in: ~/app/.shmakk/skills.json</span></div>
503
+ <div class="ln" data-d="1900"><span class="ai-out">Skill 'rust-expert' is available in this workspace.</span></div>
387
504
  <div class="ln" data-d="2400">&nbsp;</div>
388
- <div class="ln" data-d="2500"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">shmakk</span> --list-skills</span></div>
389
- <div class="ln" data-d="2900"><span class="tool-result"> rust-expert loaded from https://example.com/skills/rust-expert.md</span></div>
390
- <div class="ln" data-d="3050"><span class="tool-result"> docker-compose loaded from https://example.com/skills/docker.md</span></div>
391
- <div class="ln" data-d="3200"><span class="tool-result"> git-flow loaded from https://example.com/skills/git-flow.md</span></div>
392
- <div class="ln" data-d="3500">&nbsp;</div>
393
- <div class="ln" data-d="3600"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">shmakk</span> --load-skill rust-expert</span></div>
394
- <div class="ln" data-d="4000"><span class="ai-out">rust-expert skill active for this session.</span></div>
395
- <div class="ln" data-d="4300">&nbsp;</div>
396
- <div class="ln" data-d="4400"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~</span><span class="muted">&gt;</span> <span class="cur"></span></div>
505
+ <div class="ln" data-d="2500"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">shmakk</span> -G --install-skill https://example.com/skills/docker.md</span></div>
506
+ <div class="ln" data-d="2900"><span class="tool-result"> registered globally: ~/.config/shmakk/skills.json</span></div>
507
+ <div class="ln" data-d="3200"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">list</span> skills dev</span></div>
508
+ <div class="ln" data-d="3550"><span class="tool-result"> workspace: rust-expert</span></div>
509
+ <div class="ln" data-d="3750"><span class="tool-result"> global: docker, git-flow, code-review</span></div>
510
+ <div class="ln" data-d="3950">&nbsp;</div>
511
+ <div class="ln" data-d="4050"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="user-input"><span class="cmd-first">load</span> skill rust-expert</span></div>
512
+ <div class="ln" data-d="4450"><span class="ai-out">rust-expert skill active for this session.</span></div>
513
+ <div class="ln" data-d="4650">&nbsp;</div>
514
+ <div class="ln" data-d="4750"><span class="hostname">marcus@tobarko.ai</span> <span class="path">~/app</span><span class="muted">&gt;</span> <span class="cur"></span></div>
397
515
  </div>
398
516
 
399
517
  <!-- PROFILES -->
@@ -483,7 +601,27 @@ body {
483
601
  </div>
484
602
  <div class="feat">
485
603
  <h3>Skills</h3>
486
- <p>Extend behaviour with any URL: <code>shmakk --install-skill &lt;url&gt;</code>. Loaded per-session or automatically when relevant context is detected.</p>
604
+ <p>Workspace and global registries. Install from a URL, list categories, load exactly the skill a session needs.</p>
605
+ </div>
606
+ <div class="feat">
607
+ <h3>Vim mode</h3>
608
+ <p>Wrap real <code>vi</code>/<code>vim</code>, keep your config, and add <code>:G</code>, <code>:Tw</code>, <code>:Cmd</code>, plus full-block suggestions.</p>
609
+ </div>
610
+ <div class="feat">
611
+ <h3>MCP</h3>
612
+ <p>Connect stdio MCP servers as agent tools. Per-tool safety classification, env interpolation, status inspection.</p>
613
+ </div>
614
+ <div class="feat">
615
+ <h3>SSH</h3>
616
+ <p>Named remote hosts for <code>ssh_run</code>, <code>ssh_push</code>, and <code>ssh_pull</code>. Key auth and safety prompts stay in place.</p>
617
+ </div>
618
+ <div class="feat">
619
+ <h3>Endpoints</h3>
620
+ <p>Configure <code>main</code> for quality and <code>fast</code> for low-latency tasks like Vim suggestions.</p>
621
+ </div>
622
+ <div class="feat">
623
+ <h3>Self commands</h3>
624
+ <p>Control shmakk from inside the session: <code>show plan</code>, <code>mcp status</code>, <code>set model</code>, <code>review edits</code>.</p>
487
625
  </div>
488
626
  <div class="feat">
489
627
  <h3>Runtime profiles</h3>
@@ -504,7 +642,7 @@ body {
504
642
  <script>
505
643
  let current = 'chat';
506
644
  let timers = [];
507
- const order = ['chat','project','typo','skills','profiles','voice'];
645
+ const order = ['chat','natural','project','typo','vim','endpoints','mcp','ssh','self','skills','profiles','voice'];
508
646
 
509
647
  function go(name) {
510
648
  timers.forEach(clearTimeout); timers = [];
package/docs/mcp.md ADDED
@@ -0,0 +1,78 @@
1
+ # shmakk MCP
2
+
3
+ shmakk can connect to Model Context Protocol servers over stdio and expose their tools to the agent.
4
+
5
+ ## Configuration
6
+
7
+ Config files are loaded from:
8
+
9
+ 1. `.shmakk/mcp.json` in the workspace
10
+ 2. `~/.config/shmakk/mcp.json` globally
11
+
12
+ Example:
13
+
14
+ ```json
15
+ {
16
+ "mcpServers": {
17
+ "browser": {
18
+ "command": "npx",
19
+ "args": ["-y", "@example/mcp-server-browser"],
20
+ "env": {
21
+ "BROWSER_TOKEN": "${BROWSER_TOKEN}"
22
+ },
23
+ "safety": "uncertain",
24
+ "safeTools": ["read_page", "screenshot"],
25
+ "unsafeTools": ["delete_cookies"],
26
+ "timeout": 30000,
27
+ "disabled": false
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ Fields:
34
+
35
+ | Field | Purpose |
36
+ |-------|---------|
37
+ | `command` | Executable to spawn |
38
+ | `args` | Command arguments |
39
+ | `env` | Extra environment variables; `${NAME}` is interpolated from the current environment |
40
+ | `safety` | Default safety classification for tools: `safe`, `uncertain`, or `unsafe` |
41
+ | `safeTools` | Tool names that are always considered safe |
42
+ | `unsafeTools` | Tool names that always require confirmation |
43
+ | `timeout` | Tool-call timeout in milliseconds |
44
+ | `disabled` | Skip this server when true |
45
+
46
+ ## Status
47
+
48
+ From outside a session:
49
+
50
+ ```bash
51
+ shmakk --mcp-status
52
+ ```
53
+
54
+ From inside a session:
55
+
56
+ ```text
57
+ mcp status
58
+ ```
59
+
60
+ ## Tool behavior
61
+
62
+ MCP servers start when a shmakk session starts. shmakk performs the MCP initialize handshake, discovers tools with `tools/list`, and calls tools with `tools/call`.
63
+
64
+ Text content is returned to the agent directly. Image content is preserved as base64 with a size cap so vision-capable providers can use it without blowing out context.
65
+
66
+ MCP tools go through the same review/safety flow as built-in tools. Use `safeTools` and `unsafeTools` when a server's default safety level is too broad.
67
+
68
+ ## Browser automation
69
+
70
+ shmakk also has built-in browser automation tools. If your setup uses Playwright, install it separately:
71
+
72
+ ```bash
73
+ npm install playwright
74
+ npx playwright install chromium
75
+ ```
76
+
77
+ Browser commands include navigation, clicking, typing, page reading, screenshots, evaluating JavaScript, selecting, waiting, scrolling, and closing.
78
+
package/docs/ssh.md ADDED
@@ -0,0 +1,82 @@
1
+ # shmakk SSH
2
+
3
+ shmakk can run commands and transfer files on configured remote hosts. SSH tools are available to the agent as:
4
+
5
+ | Tool | Purpose |
6
+ |------|---------|
7
+ | `ssh_run` | Run a shell command on a remote host |
8
+ | `ssh_push` | Copy a local workspace file to a remote path |
9
+ | `ssh_pull` | Copy a remote file into the local workspace |
10
+
11
+ ## Configuration
12
+
13
+ Hosts are loaded from:
14
+
15
+ 1. `.shmakk/hosts.json` in the workspace
16
+ 2. `~/.config/shmakk/hosts.json` globally
17
+
18
+ Example:
19
+
20
+ ```json
21
+ {
22
+ "hosts": {
23
+ "devbox": {
24
+ "host": "marcus@192.168.1.100",
25
+ "port": 22,
26
+ "auto_approve": false,
27
+ "timeout_sec": 30
28
+ },
29
+ "staging": {
30
+ "host": "deploy@10.0.0.5",
31
+ "port": 2247
32
+ }
33
+ },
34
+ "allow_ssh_config": false,
35
+ "default_timeout_sec": 30
36
+ }
37
+ ```
38
+
39
+ Fields:
40
+
41
+ | Field | Purpose |
42
+ |-------|---------|
43
+ | `host` | SSH target, usually `user@host` |
44
+ | `port` | SSH port, default `22` |
45
+ | `auto_approve` | Allow the agent to use this host with fewer confirmations when safety allows |
46
+ | `timeout_sec` | Per-host command timeout |
47
+ | `allow_ssh_config` | Also import host aliases from `~/.ssh/config` |
48
+ | `default_timeout_sec` | Default timeout for hosts without `timeout_sec` |
49
+
50
+ ## SSH config import
51
+
52
+ If `allow_ssh_config` is true, shmakk reads `~/.ssh/config` and imports simple `Host`, `HostName`, `Port`, and `User` entries as named targets. Wildcard `Host *` entries are ignored as targets.
53
+
54
+ ## Authentication
55
+
56
+ SSH key authentication via your normal `~/.ssh` setup is assumed. Commands use non-interactive options:
57
+
58
+ ```text
59
+ BatchMode=yes
60
+ StrictHostKeyChecking=accept-new
61
+ ConnectTimeout=10
62
+ ```
63
+
64
+ For persistent connections, add this to `~/.ssh/config`:
65
+
66
+ ```sshconfig
67
+ Host *
68
+ ControlMaster auto
69
+ ControlPath ~/.ssh/controlmasters/%r@%h:%p
70
+ ControlPersist 600
71
+ ```
72
+
73
+ Then create the control socket directory once:
74
+
75
+ ```bash
76
+ mkdir -p ~/.ssh/controlmasters
77
+ ```
78
+
79
+ ## Safety
80
+
81
+ Remote commands are still proposed through the agent tool system. Review mode and unsafe-command confirmations continue to apply.
82
+