Skip to content

Commit 5ccdeab

Browse files
authored
Update README.md
1 parent 36bb37e commit 5ccdeab

File tree

1 file changed

+234
-0
lines changed

1 file changed

+234
-0
lines changed

README.md

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,240 @@ OpenControl is a gateway that lets an LLM access any function from your codebase
2222
- **Universal**: Works with any LLM that supports a context protocol, like Anthropic's MCP or OpenAI's Tools.
2323
- **Secure**: Supports authentication through any OAuth provider.
2424

25+
## Get started
26+
27+
1. **Install dependencies**
28+
29+
```bash
30+
npm install opencontrol hono @ai-sdk/anthropic
31+
```
32+
33+
Here are we are going to use Anthropic's Claude.
34+
35+
2. **Create the server**
36+
37+
```bash
38+
touch src/opencontrol.ts
39+
```
40+
41+
```ts title=src/opencontrol.ts
42+
import { create } from "opencontrol"
43+
import { handle } from "hono/aws-lambda"
44+
45+
const app = create({
46+
// model: ...,
47+
// tools: [ ]
48+
})
49+
50+
export const handler = handle(app)
51+
```
52+
53+
3. **Pick the model**
54+
55+
```diff lang=ts title=src/opencontrol.ts
56+
+ import { Resource } from "sst"
57+
+ import { createAnthropic } from "@ai-sdk/anthropic"
58+
59+
const app = create({
60+
+ model: createAnthropic({
61+
+ apiKey: Resource.AnthropicKey.value,
62+
+ })("claude-3-7-sonnet-20250219")
63+
})
64+
```
65+
66+
4. **Define your tools**
67+
68+
```diff lang=ts title=src/opencontrol.ts
69+
+ import { tool } from "opencontrol/tool"
70+
+ import { Inventory } from "@acme/core/inventory/index"
71+
72+
+ const inventory = tool({
73+
+ name: "inventory_record",
74+
+ description: "Record new inventory event to track in or out amounts",
75+
+ args: Inventory.record.schema,
76+
+ async run(input) {
77+
+ return Inventory.record(input)
78+
+ }
79+
+ })
80+
81+
const app = create({
82+
tools: [
83+
+ inventory
84+
]
85+
})
86+
```
87+
88+
5. **Infrastructure**
89+
90+
We are using SST here, but you can since **OpenControl is just a Hono app, you can deploy it however you want**.
91+
92+
```ts title="sst.config.ts" {1,6}
93+
const anthropicKey = new sst.Secret("AnthropicKey")
94+
95+
const server = new sst.aws.OpenControl("MyServer", {
96+
server: {
97+
handler: "src/opencontrol.handler",
98+
link: [anthropicKey]
99+
}
100+
})
101+
```
102+
103+
We are defining a secret for the Anthropic API key and linking it to our OpenControl server.
104+
105+
6. **Link any resources**
106+
107+
```ts title="sst.config.ts" {6}
108+
const bucket = new sst.aws.Bucket("MyBucket")
109+
110+
const server = new sst.aws.OpenControl("MyServer", {
111+
server: {
112+
handler: "src/opencontrol.handler",
113+
link: [bucket]
114+
}
115+
})
116+
```
117+
118+
If your tools need to access to your resources, you can link them as well.
119+
120+
7. **Grant permissions**
121+
122+
If you are using the AWS tool, you'll need to give your OpenControl server permissions to access your AWS account.
123+
124+
```ts title="sst.config.ts" {4-6}
125+
const server = new sst.aws.OpenControl("MyServer", {
126+
server: {
127+
handler: "src/opencontrol.handler",
128+
policies: $dev
129+
? ["arn:aws:iam::aws:policy/AdministratorAccess"]
130+
: ["arn:aws:iam::aws:policy/ReadOnlyAccess"]
131+
}
132+
})
133+
```
134+
135+
Here we are giving it admin access in dev but read-only access in prod.
136+
137+
8. **Deploy**
138+
139+
Currently, OpenControl uses basic auth but we'll be adding support for OAuth soon.
140+
141+
```ts title="sst.config.ts"
142+
return {
143+
OpenControlUrl: server.url,
144+
OpenControlPassword: server.password
145+
}
146+
```
147+
148+
You can print out the URL of your server and it's password and deploy.
149+
150+
```bash
151+
sst deploy
152+
```
153+
154+
Now head over to the URL, login with the password, and you can use AI to talk to your infrastructure.
155+
156+
## Examples
157+
158+
Check out how [Terminal](https://www.terminal.shop/) uses OpenControl.
159+
160+
- [Server](https://github.com/terminaldotshop/terminal/blob/dev/packages/functions/src/opencontrol.ts)
161+
- [Infrastructure](https://github.com/terminaldotshop/terminal/blob/dev/infra/opencontrol.ts)
162+
163+
## Tools
164+
165+
Here are some examples of the tools you can use with OpenControl.
166+
167+
- **AWS**
168+
169+
```ts title=src/opencontrol.ts
170+
import { z } from "zod"
171+
import AWS from "aws-sdk"
172+
import { tool } from "opencontrol/tool"
173+
174+
const aws = tool({
175+
name: "aws",
176+
description: "Make a call to the AWS SDK for JavaScript v2",
177+
args: z.object({
178+
client: z.string().describe("Class name of the client to use"),
179+
command: z.string().describe("Command to call on the client"),
180+
args: z
181+
.record(z.string(), z.any())
182+
.optional()
183+
.describe("Arguments to pass to the command"),
184+
}),
185+
async run(input) {
186+
// @ts-ignore
187+
const client = new AWS[input.client]()
188+
return await client[input.command](input.args).promise()
189+
}
190+
})
191+
```
192+
193+
- **Stripe**
194+
195+
```ts title=src/opencontrol.ts
196+
import { z } from "zod"
197+
import { tool } from "opencontrol/tool"
198+
199+
const stripe = tool({
200+
name: "stripe",
201+
description: "make a call to the stripe api",
202+
args: z.object({
203+
method: z.string().describe("HTTP method to use"),
204+
path: z.string().describe("Path to call"),
205+
query: z.record(z.string()).optional().describe("Query params"),
206+
contentType: z.string().optional().describe("HTTP content type to use"),
207+
body: z.string().optional().describe("HTTP body to use if it is not GET"),
208+
}),
209+
async run(input) {
210+
const url = new URL("https://api.stripe.com" + input.path)
211+
if (input.query) url.search = new URLSearchParams(input.query).toString()
212+
const response = await fetch(url.toString(), {
213+
method: input.method,
214+
headers: {
215+
Authorization: `Bearer ${Resource.StripeSecret.value}`,
216+
"Content-Type": input.contentType,
217+
},
218+
body: input.body ? input.body : undefined,
219+
})
220+
if (!response.ok) throw new Error(await response.text())
221+
return response.text()
222+
}
223+
})
224+
```
225+
226+
- **SQL Database**
227+
228+
```ts title=src/opencontrol.ts
229+
import { z } from "zod"
230+
import { tool } from "opencontrol/tool"
231+
import { db } from "@acme/core/drizzle/index"
232+
233+
const databaseRead = tool({
234+
name: "database_query_readonly",
235+
description:
236+
"Readonly database query for MySQL, use this if there are no direct tools",
237+
args: z.object({ query: z.string() }),
238+
async run(input) {
239+
return db.transaction(async (tx) => tx.execute(input.query), {
240+
accessMode: "read only",
241+
isolationLevel: "read committed"
242+
})
243+
}
244+
})
245+
246+
const databaseWrite = tool({
247+
name: "database_query_write",
248+
description:
249+
"DANGEROUS operation that writes to the database. You MUST triple check with the user before using this tool - show them the query you are about to run.",
250+
args: z.object({ query: z.string() }),
251+
async run(input) {
252+
return db.transaction(async (tx) => tx.execute(input.query), {
253+
isolationLevel: "read committed"
254+
})
255+
}
256+
})
257+
```
258+
25259
---
26260

27261
OpenControl is created by the maintainers of [SST](https://sst.dev).

0 commit comments

Comments
 (0)