Skip to content
This repository was archived by the owner on Mar 28, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
dist
.DS_Store
.git-old
example-plugin/
146 changes: 5 additions & 141 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,145 +8,9 @@ Buddy is a terminal-first AI assistant with a guided onboarding flow, a chat TUI
npm install -g @teichai/buddy
```

## Getting started
## Docs

Run `buddy onboard` for a guided first-time setup. It starts by asking whether the Buddy server is local or remote, then walks you through provider setup, naming, and safety defaults one step at a time before a final review screen saves everything.

After onboarding:

- Run `buddy` to open the chat UI.
- Run `buddy config` to tweak advanced settings like Discord and blocked directories.
- Run `buddy server start` to launch the local server in the background when you want a dedicated daemon.

## Plugins

Buddy can auto-load custom tool plugins from `~/.buddy/plugins`. Each plugin lives in its own folder, ships a compiled ESM entrypoint, and can expose one or more tools to the model.

### Folder layout

```text
~/.buddy/plugins/
weather-tools/
package.json
dist/
index.js
```

Buddy scans each direct child directory of `~/.buddy/plugins` on every chat turn. The folder contents are the source of truth in v1, so there are no extra enable or disable flags yet.

### `package.json`

Each plugin folder must include a `package.json` with `name`, `version`, and `buddy.entry`:

```json
{
"name": "@acme/weather-tools",
"version": "1.0.0",
"type": "module",
"buddy": {
"entry": "./dist/index.js"
}
}
```

### Authoring API

Buddy exposes a TypeScript SDK at `@teichai/buddy/plugin`.

```ts
import { definePlugin, defineTool } from "@teichai/buddy/plugin";

export default definePlugin({
id: "weather-tools",
name: "Weather Tools",
description: "Weather helpers for Buddy",
author: "Acme, Inc.",
repositoryUrl: "https://github.com/acme/weather-tools",
tools: [
defineTool({
id: "forecast",
description: "Fetch a weather forecast for a city.",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "City to look up." }
},
required: ["city"],
additionalProperties: false
},
summarize(args) {
return {
summary: `Fetch forecast for ${String(args.city ?? "unknown city")}`,
path: `weather:${String(args.city ?? "unknown")}`
};
},
async execute(_context, args) {
return `Sunny in ${String(args.city ?? "unknown")}`;
}
})
]
});
```

Plugin metadata:

- Required: `id`, `tools`
- Optional: `name`, `version`, `description`, `author`, `repositoryUrl`

`repositoryUrl` must be an absolute `http` or `https` URL if you provide it.

### Approval behavior

Tools can opt into approval in two ways.

Static approval:

```ts
defineTool({
id: "dangerous-action",
description: "Run a risky action.",
requiresApproval: true,
parameters: { type: "object", additionalProperties: false },
summarize() {
return { summary: "Run dangerous action", path: "dangerous-action" };
},
async execute() {
return "done";
}
});
```

Conditional approval from inside the tool:

```ts
import { defineTool, requestApproval } from "@teichai/buddy/plugin";

defineTool({
id: "deploy",
description: "Deploy the current release.",
parameters: {
type: "object",
properties: {
force: { type: "boolean" }
},
additionalProperties: false
},
summarize() {
return { summary: "Deploy release", path: "release" };
},
async execute(_context, args) {
if (args.force === true) {
return requestApproval({
summary: "Force deploy release",
path: "release",
reason: "Force mode bypasses the normal deployment checks.",
continueWith: async () => "forced deploy complete"
});
}

return "deploy complete";
}
});
```

In v1, plugin permissions are Buddy approval semantics for tool calls. Plugins are still trusted in-process code.
- [Getting started](./docs/getting-started.md)
- [Plugin overview](./docs/plugins/overview.md)
- [Plugin authoring](./docs/plugins/authoring.md)
- [Plugin approvals](./docs/plugins/approval.md)
9 changes: 9 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Getting started

Run `buddy onboard` for a guided first-time setup. It starts by asking whether the Buddy server is local or remote, then walks you through provider setup, naming, and safety defaults one step at a time before a final review screen saves everything.

After onboarding:

- Run `buddy` to open the chat UI.
- Run `buddy config` to tweak advanced settings like Discord and blocked directories.
- Run `buddy server start` to launch the local server in the background when you want a dedicated daemon.
55 changes: 55 additions & 0 deletions docs/plugins/approval.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Plugin approvals

Tools can opt into approval in two ways.

## Static approval

```ts
defineTool({
id: "dangerous-action",
description: "Run a risky action.",
requiresApproval: true,
parameters: { type: "object", additionalProperties: false },
summarize() {
return { summary: "Run dangerous action", path: "dangerous-action" };
},
async execute() {
return "done";
}
});
```

## Conditional approval

```ts
import { defineTool, requestApproval } from "@teichai/buddy/plugin";

defineTool({
id: "deploy",
description: "Deploy the current release.",
parameters: {
type: "object",
properties: {
force: { type: "boolean" }
},
additionalProperties: false
},
summarize() {
return { summary: "Deploy release", path: "release" };
},
async execute(_context, args) {
if (args.force === true) {
return requestApproval({
summary: "Force deploy release",
path: "release",
reason: "Force mode bypasses the normal deployment checks.",
continueWith: async () => "forced deploy complete"
});
}

return "deploy complete";
}
});
```

In v1, plugin permissions are Buddy approval semantics for tool calls. Plugins are still trusted in-process code.
45 changes: 45 additions & 0 deletions docs/plugins/authoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Plugin authoring

Buddy exposes a TypeScript SDK at `@teichai/buddy/plugin`.

```ts
import { definePlugin, defineTool } from "@teichai/buddy/plugin";

export default definePlugin({
id: "weather-tools",
name: "Weather Tools",
description: "Weather helpers for Buddy",
author: "Acme, Inc.",
repositoryUrl: "https://github.com/acme/weather-tools",
tools: [
defineTool({
id: "forecast",
description: "Fetch a weather forecast for a city.",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "City to look up." }
},
required: ["city"],
additionalProperties: false
},
summarize(args) {
return {
summary: `Fetch forecast for ${String(args.city ?? "unknown city")}`,
path: `weather:${String(args.city ?? "unknown")}`
};
},
async execute(_context, args) {
return `Sunny in ${String(args.city ?? "unknown")}`;
}
})
]
});
```

Plugin metadata:

- Required: `id`, `tools`
- Optional: `name`, `version`, `description`, `author`, `repositoryUrl`

`repositoryUrl` must be an absolute `http` or `https` URL if you provide it.
36 changes: 36 additions & 0 deletions docs/plugins/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Plugin overview

Buddy can auto-load custom tool plugins from `~/.buddy/plugins`. Each plugin lives in its own folder, ships a compiled ESM entrypoint, and can expose one or more tools to the model.

At runtime, plugins do not need their own private `node_modules/` just to import the Buddy SDK. Buddy resolves `@teichai/buddy/plugin` for them, and plugins can also reuse dependencies that are already available from Buddy or a shared parent `node_modules` such as `~/.buddy/plugins/node_modules`.

## Folder layout

```text
~/.buddy/plugins/
weather-tools/
package.json
dist/
index.js
```

Buddy scans each direct child directory of `~/.buddy/plugins` on every chat turn. The folder contents are the source of truth in v1, so there are no extra enable or disable flags yet.

## `package.json`

Each plugin folder must include a `package.json` with `name`, `version`, and `buddy.entry`:

```json
{
"name": "@acme/weather-tools",
"version": "1.0.0",
"type": "module",
"buddy": {
"entry": "./dist/index.js"
}
}
```

## Example Plugin

Find our example plugin [here](https://github.com/TeichAI/example-plugin).
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@teichai/buddy",
"version": "0.0.4",
"version": "0.0.5",
"description": "Terminal-first AI assistant with onboarding, chat UI, and local or remote server support.",
"license": "MIT",
"type": "module",
Expand All @@ -16,6 +16,7 @@
"files": [
"dist",
"LICENSE",
"docs",
"README.md"
],
"repository": {
Expand Down
Loading
Loading