bashkit 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.
- package/AGENTS.md +442 -0
- package/LICENSE +21 -0
- package/README.md +713 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.js +179 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +1805 -0
- package/dist/middleware/anthropic-cache.d.ts +17 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/sandbox/e2b.d.ts +9 -0
- package/dist/sandbox/index.d.ts +4 -0
- package/dist/sandbox/interface.d.ts +21 -0
- package/dist/sandbox/local.d.ts +5 -0
- package/dist/sandbox/vercel.d.ts +13 -0
- package/dist/setup/index.d.ts +2 -0
- package/dist/setup/setup-environment.d.ts +36 -0
- package/dist/setup/types.d.ts +47 -0
- package/dist/skills/discovery.d.ts +9 -0
- package/dist/skills/fetch.d.ts +56 -0
- package/dist/skills/index.d.ts +6 -0
- package/dist/skills/loader.d.ts +11 -0
- package/dist/skills/types.d.ts +29 -0
- package/dist/skills/xml.d.ts +26 -0
- package/dist/tools/bash.d.ts +18 -0
- package/dist/tools/edit.d.ts +16 -0
- package/dist/tools/exit-plan-mode.d.ts +11 -0
- package/dist/tools/glob.d.ts +14 -0
- package/dist/tools/grep.d.ts +42 -0
- package/dist/tools/index.d.ts +45 -0
- package/dist/tools/read.d.ts +25 -0
- package/dist/tools/task.d.ts +50 -0
- package/dist/tools/todo-write.d.ts +28 -0
- package/dist/tools/web-fetch.d.ts +20 -0
- package/dist/tools/web-search.d.ts +24 -0
- package/dist/tools/write.d.ts +14 -0
- package/dist/types.d.ts +32 -0
- package/dist/utils/compact-conversation.d.ts +85 -0
- package/dist/utils/context-status.d.ts +71 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/prune-messages.d.ts +32 -0
- package/package.json +84 -0
package/README.md
ADDED
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
# bashkit
|
|
2
|
+
|
|
3
|
+
Agentic coding tools for Vercel AI SDK. Give AI agents the ability to execute code, read/write files, and perform coding tasks in a sandboxed environment.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`bashkit` provides a set of tools that work with the Vercel AI SDK to enable agentic coding capabilities. It gives AI models like Claude the ability to:
|
|
8
|
+
|
|
9
|
+
- Execute bash commands in a persistent shell
|
|
10
|
+
- Read files and list directories
|
|
11
|
+
- Create and write files
|
|
12
|
+
- Edit existing files with string replacement
|
|
13
|
+
- Search for files by pattern
|
|
14
|
+
- Search file contents with regex
|
|
15
|
+
- Spawn sub-agents for complex tasks
|
|
16
|
+
- Track task progress with todos
|
|
17
|
+
- Search the web and fetch URLs
|
|
18
|
+
- Load skills on-demand via the [Agent Skills](https://agentskills.io) standard
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bun add bashkit ai zod
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For web tools, also install:
|
|
27
|
+
```bash
|
|
28
|
+
bun add parallel-web
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### With Filesystem Access (Desktop Apps, Local Scripts, Servers)
|
|
34
|
+
|
|
35
|
+
When you have direct filesystem access, use `LocalSandbox`:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { createAgentTools, createLocalSandbox } from 'bashkit';
|
|
39
|
+
import { anthropic } from '@ai-sdk/anthropic';
|
|
40
|
+
import { generateText, stepCountIs } from 'ai';
|
|
41
|
+
|
|
42
|
+
// Create a local sandbox (runs directly on your filesystem)
|
|
43
|
+
const sandbox = createLocalSandbox({ cwd: '/tmp/workspace' });
|
|
44
|
+
|
|
45
|
+
// Create tools bound to the sandbox
|
|
46
|
+
const tools = createAgentTools(sandbox);
|
|
47
|
+
|
|
48
|
+
// Use with Vercel AI SDK
|
|
49
|
+
const result = await generateText({
|
|
50
|
+
model: anthropic('claude-sonnet-4-5'),
|
|
51
|
+
tools,
|
|
52
|
+
prompt: 'Create a simple Express server in server.js',
|
|
53
|
+
stopWhen: stepCountIs(10),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log(result.text);
|
|
57
|
+
|
|
58
|
+
// Cleanup
|
|
59
|
+
await sandbox.destroy();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Without Filesystem Access (Web/Serverless Environments)
|
|
63
|
+
|
|
64
|
+
When you're in a web or serverless environment without filesystem access, use `VercelSandbox` or `E2BSandbox`:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { createAgentTools, createVercelSandbox } from 'bashkit';
|
|
68
|
+
import { anthropic } from '@ai-sdk/anthropic';
|
|
69
|
+
import { streamText, stepCountIs } from 'ai';
|
|
70
|
+
|
|
71
|
+
// Create a Vercel sandbox (isolated Firecracker microVM)
|
|
72
|
+
const sandbox = createVercelSandbox({
|
|
73
|
+
runtime: 'node22',
|
|
74
|
+
resources: { vcpus: 2 },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const tools = createAgentTools(sandbox);
|
|
78
|
+
|
|
79
|
+
const result = streamText({
|
|
80
|
+
model: anthropic('claude-sonnet-4-5'),
|
|
81
|
+
messages,
|
|
82
|
+
tools,
|
|
83
|
+
stopWhen: stepCountIs(10),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Cleanup
|
|
87
|
+
await sandbox.destroy();
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Available Tools
|
|
91
|
+
|
|
92
|
+
### Sandbox-based Tools (from `createAgentTools`)
|
|
93
|
+
|
|
94
|
+
| Tool | Purpose | Key Inputs |
|
|
95
|
+
|------|---------|------------|
|
|
96
|
+
| `Bash` | Execute shell commands | `command`, `timeout?`, `description?` |
|
|
97
|
+
| `Read` | Read files or list directories | `file_path`, `offset?`, `limit?` |
|
|
98
|
+
| `Write` | Create/overwrite files | `file_path`, `content` |
|
|
99
|
+
| `Edit` | Replace strings in files | `file_path`, `old_string`, `new_string`, `replace_all?` |
|
|
100
|
+
| `Glob` | Find files by pattern | `pattern`, `path?` |
|
|
101
|
+
| `Grep` | Search file contents | `pattern`, `path?`, `output_mode?`, `-i?`, `-C?` |
|
|
102
|
+
|
|
103
|
+
### Workflow Tools (created separately)
|
|
104
|
+
|
|
105
|
+
| Tool | Purpose | Factory |
|
|
106
|
+
|------|---------|---------|
|
|
107
|
+
| `Task` | Spawn sub-agents | `createTaskTool({ model, tools, subagentTypes? })` |
|
|
108
|
+
| `TodoWrite` | Track task progress | `createTodoWriteTool(state, config?, onUpdate?)` |
|
|
109
|
+
| `ExitPlanMode` | Exit planning mode | `createExitPlanModeTool(config?, onPlanSubmit?)` |
|
|
110
|
+
|
|
111
|
+
### Web Tools (require `parallel-web` peer dependency)
|
|
112
|
+
|
|
113
|
+
| Tool | Purpose | Factory |
|
|
114
|
+
|------|---------|---------|
|
|
115
|
+
| `WebSearch` | Search the web | `createWebSearchTool({ apiKey })` |
|
|
116
|
+
| `WebFetch` | Fetch URL and process with AI | `createWebFetchTool({ apiKey, model })` |
|
|
117
|
+
|
|
118
|
+
## Sandbox Types
|
|
119
|
+
|
|
120
|
+
### LocalSandbox
|
|
121
|
+
|
|
122
|
+
Runs commands directly on your filesystem. **Use when you have filesystem access** (desktop apps, local scripts, servers you control).
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { createLocalSandbox } from 'bashkit';
|
|
126
|
+
|
|
127
|
+
const sandbox = createLocalSandbox({ cwd: '/tmp/workspace' });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### VercelSandbox
|
|
131
|
+
|
|
132
|
+
Runs in isolated Firecracker microVMs on Vercel's infrastructure. **Use when you don't have filesystem access** (web apps, serverless functions, browser environments).
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { createVercelSandbox } from 'bashkit';
|
|
136
|
+
|
|
137
|
+
const sandbox = createVercelSandbox({
|
|
138
|
+
runtime: 'node22',
|
|
139
|
+
resources: { vcpus: 2 },
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### E2BSandbox
|
|
144
|
+
|
|
145
|
+
Runs in E2B's cloud sandboxes. Requires `@e2b/code-interpreter` peer dependency. **Use when you don't have filesystem access** and need E2B's features.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { createE2BSandbox } from 'bashkit';
|
|
149
|
+
|
|
150
|
+
const sandbox = createE2BSandbox({
|
|
151
|
+
// E2B config
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Configuration
|
|
156
|
+
|
|
157
|
+
You can configure tools with security restrictions and limits:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const tools = createAgentTools(sandbox, {
|
|
161
|
+
tools: {
|
|
162
|
+
Bash: {
|
|
163
|
+
timeout: 30000,
|
|
164
|
+
blockedCommands: ['rm -rf', 'curl'],
|
|
165
|
+
maxOutputLength: 10000,
|
|
166
|
+
},
|
|
167
|
+
Read: {
|
|
168
|
+
allowedPaths: ['/workspace/**'],
|
|
169
|
+
},
|
|
170
|
+
Write: {
|
|
171
|
+
maxFileSize: 1_000_000, // 1MB limit
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
webSearch: {
|
|
175
|
+
apiKey: process.env.PARALLEL_API_KEY,
|
|
176
|
+
},
|
|
177
|
+
webFetch: {
|
|
178
|
+
apiKey: process.env.PARALLEL_API_KEY,
|
|
179
|
+
model: anthropic('claude-haiku-4'),
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Configuration Options
|
|
185
|
+
|
|
186
|
+
#### Global Config
|
|
187
|
+
- `defaultTimeout` (number): Default timeout for all tools in milliseconds
|
|
188
|
+
- `workingDirectory` (string): Default working directory for the sandbox
|
|
189
|
+
|
|
190
|
+
#### Per-Tool Config
|
|
191
|
+
- `timeout` (number): Tool-specific timeout
|
|
192
|
+
- `maxFileSize` (number): Maximum file size in bytes (Write)
|
|
193
|
+
- `maxOutputLength` (number): Maximum output length (Bash)
|
|
194
|
+
- `allowedPaths` (string[]): Restrict file operations to specific paths
|
|
195
|
+
- `blockedCommands` (string[]): Block commands containing these strings (Bash)
|
|
196
|
+
|
|
197
|
+
## Sub-agents with Task Tool
|
|
198
|
+
|
|
199
|
+
The Task tool spawns new `generateText` calls for complex subtasks:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { createTaskTool } from 'bashkit';
|
|
203
|
+
|
|
204
|
+
const taskTool = createTaskTool({
|
|
205
|
+
model: anthropic('claude-sonnet-4-5'),
|
|
206
|
+
tools: sandboxTools,
|
|
207
|
+
subagentTypes: {
|
|
208
|
+
research: {
|
|
209
|
+
model: anthropic('claude-haiku-4'), // Cheaper model for research
|
|
210
|
+
systemPrompt: 'You are a research specialist. Find information only.',
|
|
211
|
+
tools: ['Read', 'Grep', 'Glob'], // Limited tools
|
|
212
|
+
},
|
|
213
|
+
coding: {
|
|
214
|
+
systemPrompt: 'You are a coding expert. Write clean code.',
|
|
215
|
+
tools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Add to tools
|
|
221
|
+
const allTools = { ...sandboxTools, Task: taskTool };
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The parent agent calls Task like any other tool:
|
|
225
|
+
```typescript
|
|
226
|
+
// Agent decides to delegate:
|
|
227
|
+
{ tool: "Task", args: {
|
|
228
|
+
description: "Research API patterns",
|
|
229
|
+
prompt: "Find best practices for REST APIs",
|
|
230
|
+
subagent_type: "research"
|
|
231
|
+
}}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Context Management
|
|
235
|
+
|
|
236
|
+
### Conversation Compaction
|
|
237
|
+
|
|
238
|
+
Automatically summarize conversations when they exceed token limits:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { compactConversation, MODEL_CONTEXT_LIMITS } from 'bashkit';
|
|
242
|
+
|
|
243
|
+
let compactState = { conversationSummary: '' };
|
|
244
|
+
|
|
245
|
+
const result = await compactConversation(messages, {
|
|
246
|
+
maxTokens: MODEL_CONTEXT_LIMITS['claude-sonnet-4-5'],
|
|
247
|
+
summarizerModel: anthropic('claude-haiku-4'), // Fast/cheap model
|
|
248
|
+
compactionThreshold: 0.85, // Trigger at 85% usage
|
|
249
|
+
protectRecentMessages: 10, // Keep last 10 messages intact
|
|
250
|
+
}, compactState);
|
|
251
|
+
|
|
252
|
+
messages = result.messages;
|
|
253
|
+
compactState = result.state;
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Context Status Monitoring
|
|
257
|
+
|
|
258
|
+
Monitor context usage and inject guidance to prevent agents from rushing:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { getContextStatus, contextNeedsCompaction } from 'bashkit';
|
|
262
|
+
|
|
263
|
+
const status = getContextStatus(messages, MODEL_CONTEXT_LIMITS['claude-sonnet-4-5']);
|
|
264
|
+
|
|
265
|
+
if (status.guidance) {
|
|
266
|
+
// Inject into system prompt
|
|
267
|
+
system = `${system}\n\n<context_status>${status.guidance}</context_status>`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (contextNeedsCompaction(status)) {
|
|
271
|
+
// Trigger compaction
|
|
272
|
+
const compacted = await compactConversation(messages, config, state);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Prompt Caching
|
|
277
|
+
|
|
278
|
+
Enable Anthropic prompt caching to reduce costs on repeated prefixes:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
import { wrapLanguageModel } from 'ai';
|
|
282
|
+
import { anthropicPromptCacheMiddleware } from 'bashkit';
|
|
283
|
+
|
|
284
|
+
const model = wrapLanguageModel({
|
|
285
|
+
model: anthropic('claude-sonnet-4-5'),
|
|
286
|
+
middleware: anthropicPromptCacheMiddleware,
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Check cache stats in result
|
|
290
|
+
console.log({
|
|
291
|
+
cacheCreation: result.providerMetadata?.anthropic?.cacheCreationInputTokens,
|
|
292
|
+
cacheRead: result.providerMetadata?.anthropic?.cacheReadInputTokens,
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Agent Skills
|
|
297
|
+
|
|
298
|
+
bashkit supports the [Agent Skills](https://agentskills.io) standard - an open format for giving agents new capabilities and expertise. Skills are folders containing a `SKILL.md` file with instructions that agents can load on-demand.
|
|
299
|
+
|
|
300
|
+
> **Note:** Skill discovery is designed for **LocalSandbox** use cases where the agent has access to the user's filesystem. For cloud sandboxes (VercelSandbox/E2B), you would bundle skills with your app and inject them directly into the system prompt.
|
|
301
|
+
|
|
302
|
+
### Progressive Disclosure
|
|
303
|
+
|
|
304
|
+
Skills use progressive disclosure to keep context lean:
|
|
305
|
+
1. **At startup**: Only skill metadata (name, description, path) is loaded (~50-100 tokens per skill)
|
|
306
|
+
2. **On activation**: Agent reads the full `SKILL.md` via the Read tool when needed
|
|
307
|
+
|
|
308
|
+
### Discovering Skills
|
|
309
|
+
|
|
310
|
+
When using LocalSandbox, skills are discovered from:
|
|
311
|
+
1. `.skills/` in the project directory (highest priority)
|
|
312
|
+
2. `~/.bashkit/skills/` for user-global skills
|
|
313
|
+
|
|
314
|
+
This allows agents to pick up project-specific skills and user-installed skills automatically.
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { discoverSkills, skillsToXml } from 'bashkit';
|
|
318
|
+
|
|
319
|
+
// Discover skills (metadata only - fast, low context)
|
|
320
|
+
const skills = await discoverSkills();
|
|
321
|
+
|
|
322
|
+
// Or with custom paths
|
|
323
|
+
const skills = await discoverSkills({
|
|
324
|
+
paths: ['.skills', '/path/to/shared/skills'],
|
|
325
|
+
cwd: '/my/project',
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Using Skills with Agents
|
|
330
|
+
|
|
331
|
+
Inject skill metadata into the system prompt using XML format (recommended for Claude):
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { discoverSkills, skillsToXml, createAgentTools, createLocalSandbox } from 'bashkit';
|
|
335
|
+
|
|
336
|
+
const skills = await discoverSkills();
|
|
337
|
+
const sandbox = createLocalSandbox({ cwd: '/tmp/workspace' });
|
|
338
|
+
const tools = createAgentTools(sandbox);
|
|
339
|
+
|
|
340
|
+
const result = await generateText({
|
|
341
|
+
model: anthropic('claude-sonnet-4-5'),
|
|
342
|
+
tools,
|
|
343
|
+
system: `You are a coding assistant.
|
|
344
|
+
|
|
345
|
+
${skillsToXml(skills)}
|
|
346
|
+
|
|
347
|
+
When a task matches a skill, use the Read tool to load its full instructions from the location path.`,
|
|
348
|
+
prompt: 'Extract text from invoice.pdf',
|
|
349
|
+
stopWhen: stepCountIs(10),
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// Agent will call Read({ file_path: "/path/to/.skills/pdf-processing/SKILL.md" })
|
|
353
|
+
// when it decides to use the pdf-processing skill
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Creating Skills
|
|
357
|
+
|
|
358
|
+
Create a folder with a `SKILL.md` file:
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
.skills/
|
|
362
|
+
└── pdf-processing/
|
|
363
|
+
└── SKILL.md
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
The `SKILL.md` file has YAML frontmatter and markdown instructions:
|
|
367
|
+
|
|
368
|
+
```markdown
|
|
369
|
+
---
|
|
370
|
+
name: pdf-processing
|
|
371
|
+
description: Extract text and tables from PDF files, fill forms, merge documents.
|
|
372
|
+
license: MIT
|
|
373
|
+
compatibility: Requires poppler-utils
|
|
374
|
+
metadata:
|
|
375
|
+
author: my-org
|
|
376
|
+
version: "1.0"
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
# PDF Processing
|
|
380
|
+
|
|
381
|
+
## When to use this skill
|
|
382
|
+
Use when the user needs to work with PDF files...
|
|
383
|
+
|
|
384
|
+
## How to extract text
|
|
385
|
+
1. Use pdftotext for text extraction...
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Required fields:**
|
|
389
|
+
- `name`: 1-64 chars, lowercase letters, numbers, and hyphens. Must match folder name.
|
|
390
|
+
- `description`: 1-1024 chars. Describes when to use this skill.
|
|
391
|
+
|
|
392
|
+
**Optional fields:**
|
|
393
|
+
- `license`: License info
|
|
394
|
+
- `compatibility`: Environment requirements
|
|
395
|
+
- `metadata`: Arbitrary key-value pairs
|
|
396
|
+
- `allowed-tools`: Space-delimited list of pre-approved tools (experimental)
|
|
397
|
+
|
|
398
|
+
### Using Remote Skills
|
|
399
|
+
|
|
400
|
+
Fetch complete skill folders from GitHub repositories, including all scripts and resources:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import { fetchSkill, fetchSkills, setupAgentEnvironment } from 'bashkit';
|
|
404
|
+
|
|
405
|
+
// Fetch a complete skill folder from Anthropic's official skills repo
|
|
406
|
+
const pdfSkill = await fetchSkill('anthropics/skills/pdf');
|
|
407
|
+
// Returns a SkillBundle:
|
|
408
|
+
// {
|
|
409
|
+
// name: 'pdf',
|
|
410
|
+
// files: {
|
|
411
|
+
// 'SKILL.md': '...',
|
|
412
|
+
// 'scripts/extract_text.py': '...',
|
|
413
|
+
// 'forms.md': '...',
|
|
414
|
+
// // ... all files in the skill folder
|
|
415
|
+
// }
|
|
416
|
+
// }
|
|
417
|
+
|
|
418
|
+
// Or batch fetch multiple skills
|
|
419
|
+
const remoteSkills = await fetchSkills([
|
|
420
|
+
'anthropics/skills/pdf',
|
|
421
|
+
'anthropics/skills/web-research',
|
|
422
|
+
]);
|
|
423
|
+
// Returns: { 'pdf': SkillBundle, 'web-research': SkillBundle }
|
|
424
|
+
|
|
425
|
+
// Use with setupAgentEnvironment - writes all files to .skills/
|
|
426
|
+
const config = {
|
|
427
|
+
skills: {
|
|
428
|
+
...remoteSkills, // SkillBundles (all files)
|
|
429
|
+
'my-custom': myCustomSkillContent, // Inline string (just SKILL.md)
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const { skills } = await setupAgentEnvironment(sandbox, config);
|
|
434
|
+
// Creates: .skills/pdf/SKILL.md, .skills/pdf/scripts/*, etc.
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**GitHub reference format:** `owner/repo/skillName`
|
|
438
|
+
- `anthropics/skills/pdf` → fetches all files from `https://github.com/anthropics/skills/tree/main/skills/pdf`
|
|
439
|
+
|
|
440
|
+
### API Reference
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
// Discover skills from filesystem
|
|
444
|
+
discoverSkills(options?: DiscoverSkillsOptions): Promise<SkillMetadata[]>
|
|
445
|
+
|
|
446
|
+
// Fetch complete skill folders from GitHub
|
|
447
|
+
fetchSkill(ref: string): Promise<SkillBundle>
|
|
448
|
+
fetchSkills(refs: string[]): Promise<Record<string, SkillBundle>>
|
|
449
|
+
|
|
450
|
+
// SkillBundle type
|
|
451
|
+
interface SkillBundle {
|
|
452
|
+
name: string;
|
|
453
|
+
files: Record<string, string>; // relative path -> content
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Generate XML for system prompts
|
|
457
|
+
skillsToXml(skills: SkillMetadata[]): string
|
|
458
|
+
|
|
459
|
+
// Parse a single SKILL.md file
|
|
460
|
+
parseSkillMetadata(content: string, skillPath: string): SkillMetadata
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Setting Up Agent Environments
|
|
464
|
+
|
|
465
|
+
For cloud sandboxes (VercelSandbox/E2B), use `setupAgentEnvironment` to create workspace directories and seed skills.
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
import {
|
|
469
|
+
setupAgentEnvironment,
|
|
470
|
+
skillsToXml,
|
|
471
|
+
createAgentTools,
|
|
472
|
+
createVercelSandbox
|
|
473
|
+
} from 'bashkit';
|
|
474
|
+
|
|
475
|
+
// Define your environment config
|
|
476
|
+
const config = {
|
|
477
|
+
workspace: {
|
|
478
|
+
notes: 'files/notes/',
|
|
479
|
+
outputs: 'files/outputs/',
|
|
480
|
+
},
|
|
481
|
+
skills: {
|
|
482
|
+
'web-research': `---
|
|
483
|
+
name: web-research
|
|
484
|
+
description: Research topics using web search and save findings.
|
|
485
|
+
---
|
|
486
|
+
# Web Research
|
|
487
|
+
Use WebSearch to find information...
|
|
488
|
+
`,
|
|
489
|
+
},
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
// Create sandbox and set up environment
|
|
493
|
+
const sandbox = createVercelSandbox({});
|
|
494
|
+
const { skills } = await setupAgentEnvironment(sandbox, config);
|
|
495
|
+
|
|
496
|
+
// Build prompt using the same config (stays in sync!)
|
|
497
|
+
const systemPrompt = `You are a research assistant.
|
|
498
|
+
|
|
499
|
+
**ENVIRONMENT:**
|
|
500
|
+
- Save notes to: ${config.workspace.notes}
|
|
501
|
+
- Save outputs to: ${config.workspace.outputs}
|
|
502
|
+
|
|
503
|
+
${skillsToXml(skills)}
|
|
504
|
+
`;
|
|
505
|
+
|
|
506
|
+
// Create tools and run
|
|
507
|
+
const tools = createAgentTools(sandbox);
|
|
508
|
+
|
|
509
|
+
const result = await generateText({
|
|
510
|
+
model: anthropic('claude-sonnet-4-5'),
|
|
511
|
+
tools,
|
|
512
|
+
system: systemPrompt,
|
|
513
|
+
messages,
|
|
514
|
+
});
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### What setupAgentEnvironment Does
|
|
518
|
+
|
|
519
|
+
1. **Creates workspace directories** - All paths in `config.workspace` are created
|
|
520
|
+
2. **Seeds skills** - Skills in `config.skills` are written to `.skills/` directory
|
|
521
|
+
3. **Returns skill metadata** - For use with `skillsToXml()`
|
|
522
|
+
|
|
523
|
+
### Using with Subagents
|
|
524
|
+
|
|
525
|
+
Use the same config for subagent prompts:
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
const taskTool = createTaskTool({
|
|
529
|
+
model,
|
|
530
|
+
tools,
|
|
531
|
+
subagentTypes: {
|
|
532
|
+
researcher: {
|
|
533
|
+
systemPrompt: `You are a researcher.
|
|
534
|
+
Save findings to: ${config.workspace.notes}`,
|
|
535
|
+
tools: ['WebSearch', 'Write'],
|
|
536
|
+
},
|
|
537
|
+
'report-writer': {
|
|
538
|
+
systemPrompt: `Read from: ${config.workspace.notes}
|
|
539
|
+
Save reports to: ${config.workspace.outputs}`,
|
|
540
|
+
tools: ['Read', 'Glob', 'Write'],
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
});
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
## Sandbox Interface
|
|
547
|
+
|
|
548
|
+
`bashkit` uses a bring-your-own-sandbox architecture. You can implement custom sandboxes:
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
interface Sandbox {
|
|
552
|
+
exec(command: string, options?: ExecOptions): Promise<ExecResult>;
|
|
553
|
+
readFile(path: string): Promise<string>;
|
|
554
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
555
|
+
readDir(path: string): Promise<string[]>;
|
|
556
|
+
fileExists(path: string): Promise<boolean>;
|
|
557
|
+
destroy(): Promise<void>;
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Custom Sandbox Example
|
|
562
|
+
|
|
563
|
+
```typescript
|
|
564
|
+
import type { Sandbox } from 'bashkit';
|
|
565
|
+
|
|
566
|
+
class DockerSandbox implements Sandbox {
|
|
567
|
+
// Your implementation
|
|
568
|
+
async exec(command: string) { /* ... */ }
|
|
569
|
+
async readFile(path: string) { /* ... */ }
|
|
570
|
+
// ... other methods
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const sandbox = new DockerSandbox();
|
|
574
|
+
const tools = createAgentTools(sandbox);
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
## Architecture
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
┌─────────────────────────────────────┐
|
|
581
|
+
│ Your Next.js App / Script │
|
|
582
|
+
│ │
|
|
583
|
+
│ ┌─────────────────────────────┐ │
|
|
584
|
+
│ │ Vercel AI SDK │ │
|
|
585
|
+
│ │ (streamText/generateText) │ │
|
|
586
|
+
│ └──────────┬──────────────────┘ │
|
|
587
|
+
│ │ │
|
|
588
|
+
│ ┌──────────▼──────────────────┐ │
|
|
589
|
+
│ │ bashkit Tools │ │
|
|
590
|
+
│ │ (Bash, Read, Write, etc) │ │
|
|
591
|
+
│ └──────────┬──────────────────┘ │
|
|
592
|
+
│ │ │
|
|
593
|
+
│ ┌──────────▼──────────────────┐ │
|
|
594
|
+
│ │ Sandbox │ │
|
|
595
|
+
│ │ (Local/Vercel/E2B/Custom) │ │
|
|
596
|
+
│ └─────────────────────────────┘ │
|
|
597
|
+
└─────────────────────────────────────┘
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
**Flow:**
|
|
601
|
+
1. User sends prompt to AI via Vercel AI SDK
|
|
602
|
+
2. AI decides it needs to use a tool (e.g., create a file)
|
|
603
|
+
3. Tool receives the call and executes via the Sandbox
|
|
604
|
+
4. Result returns to AI, which continues or completes
|
|
605
|
+
|
|
606
|
+
## Design Principles
|
|
607
|
+
|
|
608
|
+
1. **Bring Your Own Sandbox**: Start with LocalSandbox for dev, swap in VercelSandbox/E2BSandbox for production
|
|
609
|
+
2. **Type-Safe**: Full TypeScript support with proper type inference
|
|
610
|
+
3. **Configurable**: Security controls and limits at the tool level
|
|
611
|
+
4. **Vercel AI SDK Native**: Uses standard `tool()` format
|
|
612
|
+
5. **Composable**: Mix and match tools, utilities, and middleware as needed
|
|
613
|
+
|
|
614
|
+
## Examples
|
|
615
|
+
|
|
616
|
+
See the `examples/` directory for complete working examples:
|
|
617
|
+
|
|
618
|
+
- `basic.ts` - Full example with todos, sub-agents, and prompt caching
|
|
619
|
+
- `test-tools.ts` - Testing individual tools
|
|
620
|
+
- `test-web-tools.ts` - Web search and fetch examples
|
|
621
|
+
|
|
622
|
+
## API Reference
|
|
623
|
+
|
|
624
|
+
### `createAgentTools(sandbox, config?)`
|
|
625
|
+
|
|
626
|
+
Creates a set of agent tools bound to a sandbox instance.
|
|
627
|
+
|
|
628
|
+
**Parameters:**
|
|
629
|
+
- `sandbox` (Sandbox): Sandbox instance for code execution
|
|
630
|
+
- `config` (AgentConfig, optional): Configuration for tools and web tools
|
|
631
|
+
|
|
632
|
+
**Returns:** Object with tool definitions compatible with Vercel AI SDK
|
|
633
|
+
|
|
634
|
+
### Sandbox Factories
|
|
635
|
+
|
|
636
|
+
- `createLocalSandbox(config?)` - Local execution sandbox
|
|
637
|
+
- `createVercelSandbox(config?)` - Vercel Firecracker sandbox
|
|
638
|
+
- `createE2BSandbox(config?)` - E2B cloud sandbox
|
|
639
|
+
|
|
640
|
+
### Workflow Tools
|
|
641
|
+
|
|
642
|
+
- `createTaskTool(config)` - Spawn sub-agents for complex tasks
|
|
643
|
+
- `createTodoWriteTool(state, config?, onUpdate?)` - Track task progress
|
|
644
|
+
- `createExitPlanModeTool(config?, onPlanSubmit?)` - Exit planning mode
|
|
645
|
+
|
|
646
|
+
### Utilities
|
|
647
|
+
|
|
648
|
+
- `compactConversation(messages, config, state)` - Summarize long conversations
|
|
649
|
+
- `getContextStatus(messages, maxTokens, config?)` - Monitor context usage
|
|
650
|
+
- `pruneMessagesByTokens(messages, config?)` - Remove old messages
|
|
651
|
+
- `estimateMessagesTokens(messages)` - Estimate token count
|
|
652
|
+
|
|
653
|
+
### Skills
|
|
654
|
+
|
|
655
|
+
- `discoverSkills(options?)` - Discover skills from filesystem (metadata only)
|
|
656
|
+
- `skillsToXml(skills)` - Generate XML for system prompts
|
|
657
|
+
- `parseSkillMetadata(content, path)` - Parse a SKILL.md file
|
|
658
|
+
|
|
659
|
+
### Setup
|
|
660
|
+
|
|
661
|
+
- `setupAgentEnvironment(sandbox, config)` - Set up workspace directories and seed skills
|
|
662
|
+
|
|
663
|
+
### Middleware
|
|
664
|
+
|
|
665
|
+
- `anthropicPromptCacheMiddleware` - Enable prompt caching for Anthropic models
|
|
666
|
+
|
|
667
|
+
## Future Roadmap
|
|
668
|
+
|
|
669
|
+
The following features are planned for future releases:
|
|
670
|
+
|
|
671
|
+
### Agent Profiles Loader
|
|
672
|
+
|
|
673
|
+
Load pre-configured subagent types from JSON/TypeScript configs:
|
|
674
|
+
|
|
675
|
+
```json
|
|
676
|
+
// .bashkit/agents.json
|
|
677
|
+
{
|
|
678
|
+
"subagentTypes": {
|
|
679
|
+
"research": {
|
|
680
|
+
"systemPrompt": "You are a research specialist...",
|
|
681
|
+
"tools": ["Read", "Grep", "Glob", "WebSearch"]
|
|
682
|
+
},
|
|
683
|
+
"coding": {
|
|
684
|
+
"systemPrompt": "You are a coding expert...",
|
|
685
|
+
"tools": ["Read", "Write", "Edit", "Bash"]
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Helper function to auto-load profiles:
|
|
692
|
+
```typescript
|
|
693
|
+
import { createTaskToolWithProfiles } from 'bashkit';
|
|
694
|
+
|
|
695
|
+
const taskTool = createTaskToolWithProfiles({
|
|
696
|
+
model,
|
|
697
|
+
tools,
|
|
698
|
+
profilesPath: '.bashkit/agents.json', // Auto-loads
|
|
699
|
+
});
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
This will make it easy to:
|
|
703
|
+
- Share agent configurations across projects
|
|
704
|
+
- Standardize agent patterns within teams
|
|
705
|
+
- Quickly set up specialized agents for different tasks
|
|
706
|
+
|
|
707
|
+
## Contributing
|
|
708
|
+
|
|
709
|
+
Contributions welcome! Please open an issue or PR.
|
|
710
|
+
|
|
711
|
+
## License
|
|
712
|
+
|
|
713
|
+
MIT
|