agent-neckbeard 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/dist/index.cjs +670 -0
- package/dist/index.d.cts +215 -0
- package/dist/index.d.ts +215 -0
- package/dist/index.js +628 -0
- package/package.json +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<img width="1024" height="1024" alt="image" src="https://github.com/user-attachments/assets/52b7f9cf-b9c7-4cae-be11-62273cd1489a" />
|
|
2
|
+
|
|
3
|
+
# neckbeard
|
|
4
|
+
|
|
5
|
+
There's a weird thing that happens when you try to deploy an AI agent.
|
|
6
|
+
|
|
7
|
+
Most people think of agents as fancy API calls. You send a prompt, you get a response. But that's not what's actually happening. The agent is running code. It's executing bash commands, writing files, installing packages. It runs for minutes at a time, maintaining state between steps. It's a process, not a request.
|
|
8
|
+
|
|
9
|
+
This creates an obvious problem: do you really want that process running on your production server?
|
|
10
|
+
|
|
11
|
+
Anthropic's answer is no. Their [hosting docs](https://docs.claude.com/en/docs/agent-sdk/hosting) say you should run the entire agent inside a sandbox. Not just intercept the dangerous tool calls—put the whole thing in a container where it can't escape.
|
|
12
|
+
|
|
13
|
+
That sounds simple. It's not.
|
|
14
|
+
|
|
15
|
+
## The Plumbing Problem
|
|
16
|
+
|
|
17
|
+
Sandboxes like E2B give you a fresh Linux container. Your agent code lives in your repo. Bridging these two worlds is surprisingly annoying.
|
|
18
|
+
|
|
19
|
+
First, you have to get your code into the sandbox. You could bake it into a custom template, but then you're rebuilding templates every time you change a line. You could git clone on boot, but that's slow and requires auth. You could bundle and upload at runtime, which works, but now you're writing bundler configs.
|
|
20
|
+
|
|
21
|
+
Then you have to pass input. How do you get the user's prompt into a process running inside a sandbox? CLI arguments require escaping and have length limits. Environment variables have size limits. Writing to a file works, but adds boilerplate.
|
|
22
|
+
|
|
23
|
+
The worst part is output. When you run `sandbox.exec("node agent.js")`, you get back everything the process printed. SDK logs, debug output, streaming tokens, and somewhere in there, your actual result. Good luck parsing that reliably.
|
|
24
|
+
|
|
25
|
+
So you end up writing results to a file, reading it back, parsing JSON, validating the shape, handling errors. Every team building sandboxed agents writes some version of this plumbing. It's tedious.
|
|
26
|
+
|
|
27
|
+
## What This Does
|
|
28
|
+
|
|
29
|
+
Neckbeard handles all of that so you can just write your agent:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { Agent } from 'agent-neckbeard';
|
|
33
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
34
|
+
import { z } from 'zod';
|
|
35
|
+
|
|
36
|
+
const agent = new Agent({
|
|
37
|
+
template: 'code-interpreter-v1',
|
|
38
|
+
inputSchema: z.object({ topic: z.string() }),
|
|
39
|
+
outputSchema: z.object({
|
|
40
|
+
title: z.string(),
|
|
41
|
+
summary: z.string(),
|
|
42
|
+
keyPoints: z.array(z.string()),
|
|
43
|
+
}),
|
|
44
|
+
envs: {
|
|
45
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
|
|
46
|
+
},
|
|
47
|
+
run: async (input) => {
|
|
48
|
+
for await (const message of query({
|
|
49
|
+
prompt: `Research "${input.topic}" and return JSON`,
|
|
50
|
+
options: { maxTurns: 10 },
|
|
51
|
+
})) {
|
|
52
|
+
if (message.type === 'result') {
|
|
53
|
+
return JSON.parse(message.result ?? '{}');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const sandboxId = await agent.deploy(); // bundles, uploads to E2B, returns sandboxId
|
|
60
|
+
const result = await agent.run({ topic: 'TypeScript generics' });
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`deploy()` bundles your code with esbuild and uploads it. `run()` writes input to a file, executes, reads the result back, and validates it against your schema. You don't think about file paths or stdout parsing.
|
|
64
|
+
|
|
65
|
+
## Setup
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm install agent-neckbeard
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
export E2B_API_KEY=your-key
|
|
73
|
+
export ANTHROPIC_API_KEY=your-key # Pass via envs config, not auto-forwarded
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## The Details
|
|
77
|
+
|
|
78
|
+
The constructor takes a few options:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
new Agent({
|
|
82
|
+
template: string, // E2B template (e.g. 'code-interpreter-v1')
|
|
83
|
+
inputSchema: ZodSchema,
|
|
84
|
+
outputSchema: ZodSchema,
|
|
85
|
+
run: (input, ctx) => Promise,
|
|
86
|
+
maxDuration?: number, // seconds, default 300
|
|
87
|
+
dependencies?: {
|
|
88
|
+
apt?: string[],
|
|
89
|
+
commands?: string[],
|
|
90
|
+
},
|
|
91
|
+
files?: [{ url, path }], // pre-download into sandbox
|
|
92
|
+
claudeDir?: string, // upload .claude/ skills directory
|
|
93
|
+
envs?: Record<string, string | undefined>, // environment variables for sandbox
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`deploy()` returns the sandbox ID, which you can save for reconnecting later:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const sandboxId = await agent.deploy();
|
|
101
|
+
// Later, reconnect to the same sandbox:
|
|
102
|
+
const result = await agent.run({ topic: 'hello' }, { sandboxId });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The `files` option downloads things into the sandbox before your agent runs—useful for models or config files. Relative paths resolve from `/home/user/`.
|
|
106
|
+
|
|
107
|
+
The `claudeDir` option uploads a local `.claude/` directory to the sandbox, enabling Claude Agent SDK skills. Point it at a directory containing `.claude/skills/*/SKILL.md` files.
|
|
108
|
+
|
|
109
|
+
The `envs` option passes environment variables to the sandbox. These are available to your agent code via `process.env` and `ctx.env`. Undefined values are filtered out:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const agent = new Agent({
|
|
113
|
+
template: 'code-interpreter-v1',
|
|
114
|
+
envs: {
|
|
115
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
|
|
116
|
+
MY_API_KEY: process.env.MY_API_KEY,
|
|
117
|
+
},
|
|
118
|
+
// ...
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Some packages can't be bundled because they spawn child processes or have native modules. The Claude Agent SDK is like this. These get automatically marked as external and installed via npm in the sandbox.
|
|
123
|
+
|
|
124
|
+
The `run` function gets a context object with an `executionId`, an `AbortSignal`, environment variables, and a logger.
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT
|