skimpyclaw 0.3.0 → 0.3.3
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.
- package/dist/cli.js +17 -5
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +38 -3
- package/package.json +1 -1
- package/templates/TOOLS.md +318 -20
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { spawn, spawnSync } from 'child_process';
|
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { loadConfig, loadRawConfig, getConfigPath, saveConfig } from './config.js';
|
|
8
8
|
import { startRuntime } from './service.js';
|
|
9
|
-
import { runSetup } from './setup.js';
|
|
9
|
+
import { runSetup, renderGatewayPlist } from './setup.js';
|
|
10
10
|
import { runDoctor as runDoctorCommand } from './doctor/index.js';
|
|
11
11
|
import { executeTool, getToolDefinitions, BUILTIN_TOOL_DEFINITIONS, BROWSER_TOOL_DEFINITION } from './tools.js';
|
|
12
12
|
import { formatModelSelectionError, getModelSelectionUsage, resolveModelSelection } from './model-selection.js';
|
|
@@ -129,10 +129,22 @@ function startDaemon() {
|
|
|
129
129
|
console.error('Daemon control is only supported on macOS with launchctl.');
|
|
130
130
|
return 1;
|
|
131
131
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
// Regenerate plist to point at the current binary (pnpm changes path on upgrade)
|
|
133
|
+
try {
|
|
134
|
+
const plistContent = renderGatewayPlist();
|
|
135
|
+
const plistDir = join(homedir(), 'Library', 'LaunchAgents');
|
|
136
|
+
if (!existsSync(plistDir))
|
|
137
|
+
mkdirSync(plistDir, { recursive: true });
|
|
138
|
+
writeFileSync(LAUNCHD_PLIST, plistContent);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
// If template is missing (e.g. corrupted install), fall back to existing plist
|
|
142
|
+
if (!existsSync(LAUNCHD_PLIST)) {
|
|
143
|
+
console.error(`Launchd plist not found: ${LAUNCHD_PLIST}`);
|
|
144
|
+
console.error('Run `skimpyclaw onboard` first.');
|
|
145
|
+
return 1;
|
|
146
|
+
}
|
|
147
|
+
console.warn(`Warning: could not regenerate plist (${err instanceof Error ? err.message : err}), using existing`);
|
|
136
148
|
}
|
|
137
149
|
const result = runLaunchctl(['load', LAUNCHD_PLIST]);
|
|
138
150
|
if (!result.ok && !result.output.includes('already loaded')) {
|
package/dist/setup.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
interface SetupOptions {
|
|
2
2
|
dryRun?: boolean;
|
|
3
3
|
}
|
|
4
|
+
export declare function renderGatewayPlist(): string;
|
|
4
5
|
type ProviderChoice = 'anthropic-api' | 'anthropic-oauth' | 'openai-api' | 'codex-oauth' | 'minimax-api' | 'kimi-api';
|
|
5
6
|
interface ProviderSecrets {
|
|
6
7
|
anthropicKey?: string;
|
package/dist/setup.js
CHANGED
|
@@ -128,7 +128,7 @@ function maskInput(input) {
|
|
|
128
128
|
return '****';
|
|
129
129
|
return input.slice(0, 4) + '****' + input.slice(-4);
|
|
130
130
|
}
|
|
131
|
-
function renderGatewayPlist() {
|
|
131
|
+
export function renderGatewayPlist() {
|
|
132
132
|
if (!existsSync(GATEWAY_PLIST_TEMPLATE)) {
|
|
133
133
|
throw new Error(`Gateway launchd template not found: ${GATEWAY_PLIST_TEMPLATE}`);
|
|
134
134
|
}
|
|
@@ -235,7 +235,14 @@ function buildStarterCronJobs(starters) {
|
|
|
235
235
|
},
|
|
236
236
|
payload: {
|
|
237
237
|
kind: 'agentTurn',
|
|
238
|
-
message: 'Use
|
|
238
|
+
message: 'Use the Browser tool to visit https://news.ycombinator.com and fetch today\'s top 10 stories. Reply with title, URL, and 1-line summary for each item.',
|
|
239
|
+
tools: {
|
|
240
|
+
enabled: true,
|
|
241
|
+
allowedPaths: [`${homedir()}/.skimpyclaw`],
|
|
242
|
+
maxIterations: 30,
|
|
243
|
+
bashTimeout: 30000,
|
|
244
|
+
browser: { enabled: true, headless: true },
|
|
245
|
+
},
|
|
239
246
|
},
|
|
240
247
|
});
|
|
241
248
|
}
|
|
@@ -250,7 +257,14 @@ function buildStarterCronJobs(starters) {
|
|
|
250
257
|
},
|
|
251
258
|
payload: {
|
|
252
259
|
kind: 'agentTurn',
|
|
253
|
-
message: `
|
|
260
|
+
message: `Use the Browser tool to check current weather and today's forecast for ${starters.weatherLocation}. Keep it concise: current temp/conditions, highs/lows, precipitation chance, and 1 recommendation.`,
|
|
261
|
+
tools: {
|
|
262
|
+
enabled: true,
|
|
263
|
+
allowedPaths: [`${homedir()}/.skimpyclaw`],
|
|
264
|
+
maxIterations: 30,
|
|
265
|
+
bashTimeout: 30000,
|
|
266
|
+
browser: { enabled: true, headless: true },
|
|
267
|
+
},
|
|
254
268
|
},
|
|
255
269
|
});
|
|
256
270
|
}
|
|
@@ -488,6 +502,13 @@ export function buildSetupConfig(input) {
|
|
|
488
502
|
allowFrom: [parseInt(input.telegramId, 10) || input.telegramId],
|
|
489
503
|
dailyNotesDir: '${HOME}/.skimpyclaw/Daily Notes',
|
|
490
504
|
defaultAllowedPaths: allPaths,
|
|
505
|
+
tools: {
|
|
506
|
+
enabled: true,
|
|
507
|
+
allowedPaths: allPaths,
|
|
508
|
+
maxIterations: 100,
|
|
509
|
+
bashTimeout: 15000,
|
|
510
|
+
...(features.browser ? { browser: { type: 'chromium', enabled: true, headless: true } } : {}),
|
|
511
|
+
},
|
|
491
512
|
},
|
|
492
513
|
discord: {
|
|
493
514
|
enabled: useDiscord,
|
|
@@ -495,6 +516,13 @@ export function buildSetupConfig(input) {
|
|
|
495
516
|
allowFrom: useDiscord ? [input.discordUserId || ''] : [],
|
|
496
517
|
defaultAllowedPaths: allPaths,
|
|
497
518
|
...(input.discordDefaultChannelId ? { defaultChannelId: input.discordDefaultChannelId } : {}),
|
|
519
|
+
tools: {
|
|
520
|
+
enabled: true,
|
|
521
|
+
allowedPaths: allPaths,
|
|
522
|
+
maxIterations: 100,
|
|
523
|
+
bashTimeout: 15000,
|
|
524
|
+
...(features.browser ? { browser: { type: 'chromium', enabled: true, headless: false } } : {}),
|
|
525
|
+
},
|
|
498
526
|
},
|
|
499
527
|
},
|
|
500
528
|
cron: {
|
|
@@ -517,6 +545,13 @@ export function buildSetupConfig(input) {
|
|
|
517
545
|
defaultProvider: 'macos',
|
|
518
546
|
providers: {
|
|
519
547
|
macos: { tts: { voice: 'Samantha' } },
|
|
548
|
+
...(input.selectedProviders.has('openai-api') ? {
|
|
549
|
+
openai: {
|
|
550
|
+
apiKey: '${OPENAI_API_KEY}',
|
|
551
|
+
baseURL: 'https://api.openai.com/v1',
|
|
552
|
+
stt: { model: 'whisper-1' },
|
|
553
|
+
},
|
|
554
|
+
} : {}),
|
|
520
555
|
},
|
|
521
556
|
channels: {
|
|
522
557
|
telegram: { enabled: true, acceptVoice: true, sendVoice: true },
|
package/package.json
CHANGED
package/templates/TOOLS.md
CHANGED
|
@@ -1,30 +1,328 @@
|
|
|
1
|
-
# TOOLS.md
|
|
1
|
+
# TOOLS.md — Available Tools
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This file defines operational authority.
|
|
4
|
+
Core safety and integrity rules may not be removed or weakened.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
---
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- Model switching (fast/smart/opus aliases)
|
|
9
|
-
- Cron job execution
|
|
8
|
+
## CRITICAL: Act, Don't Narrate
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
If a task requires a tool, call the tool immediately.
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
- Agent templates: ~/.skimpyclaw/agents/main/
|
|
15
|
-
- Memory logs: ~/.skimpyclaw/agents/main/memory/
|
|
16
|
-
- Session transcripts: ~/.skimpyclaw/sessions/
|
|
17
|
-
- Gateway logs: ~/.skimpyclaw/logs/
|
|
12
|
+
Do not:
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
- Announce intent
|
|
15
|
+
- Explain the plan
|
|
16
|
+
- Simulate execution
|
|
17
|
+
- Output tool calls as text
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
Each response must either:
|
|
22
20
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- [ ] Calendar sync
|
|
26
|
-
- [ ] Other...
|
|
21
|
+
- Call a tool, or
|
|
22
|
+
- Deliver a final result.
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
---
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
## State Integrity
|
|
27
|
+
|
|
28
|
+
- If you have not Read it, you do not know it.
|
|
29
|
+
- Never assume file contents.
|
|
30
|
+
- Never partial-write structured files.
|
|
31
|
+
- Never fabricate tool output.
|
|
32
|
+
- If a tool fails, report the failure plainly.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Tool Use Rules
|
|
37
|
+
|
|
38
|
+
Tools are provided dynamically via the API tool_use mechanism.
|
|
39
|
+
|
|
40
|
+
Available categories:
|
|
41
|
+
|
|
42
|
+
- Built-in tools (Read, Write, Glob, Bash)
|
|
43
|
+
- Browser (when enabled)
|
|
44
|
+
- `$web_search` (when injected)
|
|
45
|
+
- MCP tools (auto-discovered)
|
|
46
|
+
|
|
47
|
+
Rules:
|
|
48
|
+
|
|
49
|
+
- Do not hallucinate tools.
|
|
50
|
+
- Do not invent parameters.
|
|
51
|
+
- Do not output tool calls as JSON/XML/text.
|
|
52
|
+
- If functionality is unavailable, say so plainly.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
# Built-in Tools
|
|
57
|
+
|
|
58
|
+
## Read
|
|
59
|
+
|
|
60
|
+
Read the contents of a file.
|
|
61
|
+
|
|
62
|
+
Parameter:
|
|
63
|
+
|
|
64
|
+
- `file_path` (absolute path, required)
|
|
65
|
+
|
|
66
|
+
Use when:
|
|
67
|
+
|
|
68
|
+
- Gathering context
|
|
69
|
+
- Verifying state
|
|
70
|
+
- Modifying any file
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Write
|
|
75
|
+
|
|
76
|
+
Write content to a file. Overwrites existing files.
|
|
77
|
+
|
|
78
|
+
Parameters:
|
|
79
|
+
|
|
80
|
+
- `file_path` (required)
|
|
81
|
+
- `content` (required)
|
|
82
|
+
|
|
83
|
+
Protocol:
|
|
84
|
+
|
|
85
|
+
1. Read full file first.
|
|
86
|
+
2. Modify in memory.
|
|
87
|
+
3. Write entire file back.
|
|
88
|
+
4. Never partial-write structured files.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Glob
|
|
93
|
+
|
|
94
|
+
List files/directories at a path.
|
|
95
|
+
|
|
96
|
+
Parameter:
|
|
97
|
+
|
|
98
|
+
- `path` (absolute path)
|
|
99
|
+
|
|
100
|
+
Use for discovery.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Bash
|
|
105
|
+
|
|
106
|
+
Execute shell commands.
|
|
107
|
+
|
|
108
|
+
Parameters:
|
|
109
|
+
|
|
110
|
+
- `command` (required)
|
|
111
|
+
- `cwd` (optional)
|
|
112
|
+
|
|
113
|
+
Use for:
|
|
114
|
+
|
|
115
|
+
- Date/time retrieval
|
|
116
|
+
- CLI utilities (gh, icalBuddy, curl, etc.)
|
|
117
|
+
|
|
118
|
+
Quote paths with spaces.
|
|
119
|
+
|
|
120
|
+
Never run interactive programs (vim, nano, less).
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## spawn_subagent
|
|
125
|
+
|
|
126
|
+
Spawn a background agent. Returns immediately.
|
|
127
|
+
|
|
128
|
+
Parameters:
|
|
129
|
+
|
|
130
|
+
- `task` (required, self-contained)
|
|
131
|
+
- `type` (`coding`, `research`)
|
|
132
|
+
- `model` (optional)
|
|
133
|
+
- `label` (optional)
|
|
134
|
+
- `allowedPaths` (optional)
|
|
135
|
+
|
|
136
|
+
Use when:
|
|
137
|
+
|
|
138
|
+
- Task is complex and parallelizable
|
|
139
|
+
- Long-running coding would block conversation
|
|
140
|
+
- Multiple independent tasks are requested
|
|
141
|
+
|
|
142
|
+
Do not use for:
|
|
143
|
+
|
|
144
|
+
- Simple reads/writes
|
|
145
|
+
- Interactive back-and-forth tasks
|
|
146
|
+
- Single quick actions
|
|
147
|
+
|
|
148
|
+
The subagent must not assume shared context unless explicitly included.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## code_with_agent
|
|
153
|
+
|
|
154
|
+
Delegate non-trivial code changes to a dedicated coding CLI (Claude Code or Codex).
|
|
155
|
+
|
|
156
|
+
Parameters:
|
|
157
|
+
|
|
158
|
+
- `task` (required, detailed and specific)
|
|
159
|
+
- `agent` (`claude` default or `codex`)
|
|
160
|
+
- `workdir` (optional)
|
|
161
|
+
- `model` (optional)
|
|
162
|
+
- `max_turns` (optional, Claude only)
|
|
163
|
+
- `validate` (boolean, default true)
|
|
164
|
+
|
|
165
|
+
Use when:
|
|
166
|
+
|
|
167
|
+
- Modifying codebases
|
|
168
|
+
- Multi-file changes
|
|
169
|
+
- Changes requiring build/test validation
|
|
170
|
+
|
|
171
|
+
Do not use for:
|
|
172
|
+
|
|
173
|
+
- Simple config edits
|
|
174
|
+
- Information gathering
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## code_with_team
|
|
179
|
+
|
|
180
|
+
Decompose a complex task into subtasks and run multiple `code_with_agent` instances in parallel.
|
|
181
|
+
|
|
182
|
+
Parameters:
|
|
183
|
+
|
|
184
|
+
- `task` (required, detailed and specific)
|
|
185
|
+
- `team_size` (2-5, default 3)
|
|
186
|
+
- `workdir` (optional)
|
|
187
|
+
- `model` (optional)
|
|
188
|
+
- `timeout_minutes` (optional, default 20, max 60)
|
|
189
|
+
- `validate` (boolean, default true — runs once after all agents finish)
|
|
190
|
+
|
|
191
|
+
Use when:
|
|
192
|
+
|
|
193
|
+
- Multi-file refactors with independent parts
|
|
194
|
+
- Cross-layer changes (frontend + backend + tests) that don't conflict
|
|
195
|
+
- Tasks with clearly separable subtasks
|
|
196
|
+
|
|
197
|
+
Do not use for:
|
|
198
|
+
|
|
199
|
+
- Simple single-file changes (use code_with_agent)
|
|
200
|
+
- Tightly coupled changes where agents would conflict on the same files
|
|
201
|
+
- Non-coding tasks
|
|
202
|
+
- Quick fixes or config edits
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Web Search
|
|
207
|
+
|
|
208
|
+
When available, `$web_search` is injected automatically.
|
|
209
|
+
|
|
210
|
+
Search hierarchy:
|
|
211
|
+
|
|
212
|
+
1. `$web_search` for general discovery
|
|
213
|
+
2. Browser for interactive or structured extraction
|
|
214
|
+
3. Bash+curl only if Browser unavailable
|
|
215
|
+
|
|
216
|
+
Prefer `$web_search` for speed and cost efficiency.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Browser
|
|
221
|
+
|
|
222
|
+
Playwright browser with persistent sessions.
|
|
223
|
+
|
|
224
|
+
Use for:
|
|
225
|
+
|
|
226
|
+
- Web scraping and reading web pages
|
|
227
|
+
- Fetching news, weather, prices, and other web content
|
|
228
|
+
- Reading dynamic pages
|
|
229
|
+
- Automation requiring login
|
|
230
|
+
- Structured extraction
|
|
231
|
+
|
|
232
|
+
When `$web_search` is not available, use Browser to navigate directly to websites.
|
|
233
|
+
|
|
234
|
+
Rules:
|
|
235
|
+
|
|
236
|
+
- Always include URLs in scraped results.
|
|
237
|
+
- Extract title, author, link, and key metrics when relevant.
|
|
238
|
+
- Do not perform destructive actions without explicit confirmation.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## MCP Tools
|
|
243
|
+
|
|
244
|
+
Auto-discovered at runtime (`mcp__{server}__{tool}`).
|
|
245
|
+
|
|
246
|
+
Load providers before execution:
|
|
247
|
+
|
|
248
|
+
- `context-a8c-load-provider`
|
|
249
|
+
- `context-a8c-execute-tool`
|
|
250
|
+
|
|
251
|
+
Load providers in parallel when needed.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
# Execution Guidelines
|
|
256
|
+
|
|
257
|
+
- Read before Write.
|
|
258
|
+
- Prefer minimal tool calls.
|
|
259
|
+
- Prefer deterministic tools.
|
|
260
|
+
- Use Bash for dates (`date +%m-%d-%Y`).
|
|
261
|
+
- Do not guess state.
|
|
262
|
+
- Update files when asked — do not suggest it.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
# Vision / Image Processing
|
|
267
|
+
|
|
268
|
+
You CAN see and analyze images. When a user sends a photo or image attachment, the image is downloaded, converted to base64, and included in your message as an image content block. You receive the actual pixel data — you are NOT guessing.
|
|
269
|
+
|
|
270
|
+
Rules:
|
|
271
|
+
- Describe what you actually see. Do not fabricate or embellish.
|
|
272
|
+
- If the image is unclear or you're uncertain about details, say so.
|
|
273
|
+
- You can read text in images (OCR), identify objects, describe scenes, and extract structured data (dates, events, etc.).
|
|
274
|
+
- If asked to act on image contents (e.g. "add this to my calendar"), extract the details and use the appropriate tool.
|
|
275
|
+
- Do NOT claim you cannot see images. You can.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
# Creating Skills
|
|
280
|
+
|
|
281
|
+
You can create new skills to extend your own capabilities. Skills are loaded automatically on each agent turn.
|
|
282
|
+
|
|
283
|
+
## Skill Format
|
|
284
|
+
|
|
285
|
+
Skills are Markdown files at `~/.skimpyclaw/skills/{name}/SKILL.md`. Each skill requires YAML frontmatter:
|
|
286
|
+
|
|
287
|
+
```yaml
|
|
288
|
+
---
|
|
289
|
+
name: skill-name # Unique identifier (lowercase, hyphens)
|
|
290
|
+
description: What it does # One-line summary shown in skill list
|
|
291
|
+
emoji: 🔧 # Display emoji (optional)
|
|
292
|
+
tags: [category, topic] # Freeform tags for filtering (optional)
|
|
293
|
+
requires: # External requirements (optional)
|
|
294
|
+
bins: [curl] # Binaries that must be on PATH
|
|
295
|
+
env: [API_KEY] # Env vars that must be set
|
|
296
|
+
paths: [/some/dir] # Paths that must exist
|
|
297
|
+
tools: [Browser] # Tools that must be available
|
|
298
|
+
contexts: # When this skill activates (optional, default: always)
|
|
299
|
+
channels: [telegram] # Channel names: telegram, discord
|
|
300
|
+
cronJobs: [morning] # Specific cron job IDs
|
|
301
|
+
tags: [daily] # Tag-based activation
|
|
302
|
+
priority: 50 # Load order: lower = earlier (default: 100)
|
|
303
|
+
enabled: true # Set false to disable without deleting
|
|
304
|
+
---
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## How to Create a Skill
|
|
308
|
+
|
|
309
|
+
Use the Write tool to create `~/.skimpyclaw/skills/{name}/SKILL.md` with proper frontmatter and instructions.
|
|
310
|
+
|
|
311
|
+
The skill content after frontmatter is injected into the system prompt. Write it as instructions to yourself.
|
|
312
|
+
|
|
313
|
+
## Best Practices
|
|
314
|
+
|
|
315
|
+
- Keep each skill focused on one domain
|
|
316
|
+
- Use `contexts` to avoid loading irrelevant skills (e.g. a cron-only skill shouldn't load in Telegram)
|
|
317
|
+
- Set `priority` to control load order when skills depend on each other
|
|
318
|
+
- Use `enabled: false` to temporarily disable a skill
|
|
319
|
+
- Skills are hot-reloaded — no restart needed
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
# What You Cannot Do
|
|
324
|
+
|
|
325
|
+
- Cannot send external messages directly
|
|
326
|
+
- Cannot run interactive shell programs
|
|
327
|
+
- Cannot fabricate outputs
|
|
328
|
+
- Cannot bypass integrity rules
|