AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Opencode Sdk

skill-timmy6942025-opencode-builder-skill-opencode-sdk · by Timmy6942025

|

No reviews yet
0 installs
41 views
0.0% view→install

Install

$ agentstack add skill-timmy6942025-opencode-builder-skill-opencode-sdk

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-timmy6942025-opencode-builder-skill-opencode-sdk)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Opencode Sdk? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

OpenCode JavaScript/TypeScript SDK (@opencode-ai/sdk)

> 📚 Official Docs: For the latest information, always refer to the official documentation: > https://opencode.ai/docs/sdk/

Type-safe JavaScript/TypeScript client for the OpenCode server. Use it to build integrations, automate workflows, and control OpenCode programmatically.

All types are auto-generated from the server's OpenAPI 3.1 specification and available in the types file.


Installation

npm install @opencode-ai/sdk
# or
bun add @opencode-ai/sdk

Two Client Modes

Full Lifecycle (createOpencode)

Starts an OpenCode server and returns a connected client. Use this when you own the server lifecycle.

import { createOpencode } from "@opencode-ai/sdk"

const { client, server } = await createOpencode({
  hostname: "127.0.0.1",
  port: 4096,
  timeout: 5000,
  config: {
    model: "anthropic/claude-3-5-sonnet-20241022",
  },
})

console.log(`Server running at ${server.url}`)

// Use the client...

server.close()

Options:

| Option | Type | Description | Default | |---|---|---|---| | hostname | string | Server hostname | 127.0.0.1 | | port | number | Server port | 4096 | | signal | AbortSignal | Abort signal for cancellation | undefined | | timeout | number | Timeout in ms for server start | 5000 | | config | Config | Configuration object | {} |

The instance still picks up your opencode.json, but inline config overrides or adds to it. The returned server object has a .url property and a .close() method to shut down the server process.

Client Only (createOpencodeClient)

Connects to an already-running OpenCode server. Use this when the server is managed externally (e.g., opencode serve or a TUI instance).

import { createOpencodeClient } from "@opencode-ai/sdk"

const client = createOpencodeClient({
  baseUrl: "http://localhost:4096",
  throwOnError: true,
  responseStyle: "data",
})

Options:

| Option | Type | Description | Default | |---|---|---|---| | baseUrl | string | URL of the server | http://localhost:4096 | | fetch | function | Custom fetch implementation | globalThis.fetch | | parseAs | string | Response parsing method | auto | | responseStyle | string | Return style: "data" or "fields" | "fields" | | throwOnError | boolean | Throw errors instead of returning them | false |


Response Styles

The responseStyle option controls how API responses are returned:

  • "fields" (default): Returns { data, error, response } — you check error manually.
  • "data": Returns just the data payload directly. When combined with throwOnError: true, throws on error.
// "fields" style — check error manually
const result = await client.session.get({ path: { id: "abc" } })
if (result.error) {
  console.error("Error:", result.error)
} else {
  console.log(result.data)
}

// "data" style — returns payload directly
const session = await client.session.get({ path: { id: "abc" } })
// session is the Session object directly

Error Handling

throwOnError

When throwOnError is false (default), errors are returned in the error field of the response object. When true, they throw and should be caught:

try {
  const session = await client.session.get({ path: { id: "invalid-id" } })
} catch (error) {
  console.error("Failed to get session:", (error as Error).message)
}

Error Types

The SDK can return the following error types:

| Error Name | Description | |---|---| | ProviderAuthError | Authentication failure with a provider. Contains providerID and message. | | UnknownError | An unexpected error occurred. Contains message. | | MessageOutputLengthError | Model output exceeded the maximum length. | | MessageAbortedError | The message generation was aborted. Contains message. | | ApiError | An API-level error. Contains message, statusCode, isRetryable, responseHeaders, responseBody. | | BadRequest | Invalid request parameters. Contains message and kind (Params, Headers, Query, Body, Payload). | | NotFoundError | Resource not found. Contains message. |

StructuredOutputError

If the model fails to produce valid structured output after all retries, the response will include a StructuredOutputError:

if (result.data.info.error?.name === "StructuredOutputError") {
  console.error("Failed to produce structured output:", result.data.info.error.message)
  console.error("Attempts:", result.data.info.error.retries)
}

Types

Import TypeScript definitions directly from the SDK:

import type {
  Session,
  Message,
  AssistantMessage,
  UserMessage,
  Part,
  TextPart,
  FilePart,
  ToolPart,
  ReasoningPart,
  Config,
  Project,
  Provider,
  Agent,
  Symbol,
  FileNode,
  FileContent,
  File,
  Command,
  Todo,
  AgentConfig,
  ProviderConfig,
  Auth,
  Event,
  GlobalEvent,
} from "@opencode-ai/sdk"

All types are generated from the server's OpenAPI specification.


Structured Output

Request validated JSON from the model by specifying a format with a JSON schema. The model uses a StructuredOutput tool to return matching JSON.

Basic Usage

const result = await client.session.prompt({
  path: { id: sessionId },
  body: {
    parts: [{ type: "text", text: "Research Anthropic and provide company info" }],
    format: {
      type: "json_schema",
      schema: {
        type: "object",
        properties: {
          company: { type: "string", description: "Company name" },
          founded: { type: "number", description: "Year founded" },
          products: {
            type: "array",
            items: { type: "string" },
            description: "Main products",
          },
        },
        required: ["company", "founded"],
      },
    },
  },
})

console.log(result.data.info.structured_output)
// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] }

Output Format Types

| Type | Description | |---|---| | "text" | Default. Standard text response (no structured output) | | "json_schema" | Returns validated JSON matching the provided schema |

JSON Schema Format

When using type: "json_schema", provide:

| Field | Type | Description | |---|---|---| | type | "json_schema" | Required. Specifies JSON schema mode | | schema | object | Required. JSON Schema object defining the output structure | | retryCount | number | Optional. Number of validation retries (default: 2) |

Error Handling

If the model fails to produce valid structured output after all retries, the response will include a StructuredOutputError:

if (result.data.info.error?.name === "StructuredOutputError") {
  console.error("Failed to produce structured output:", result.data.info.error.message)
  console.error("Attempts:", result.data.info.error.retries)
}

Best Practices

  1. Provide clear descriptions in your schema properties to help the model understand what data to extract.
  2. Use required to specify which fields must be present.
  3. Keep schemas focused — complex nested schemas may be harder for the model to fill correctly.
  4. Set appropriate retryCount — increase for complex schemas, decrease for simple ones.

Core Workflows

Session Management

import { createOpencode } from "@opencode-ai/sdk"

const { client, server } = await createOpencode()

// Create a session
const session = await client.session.create({
  body: { title: "My session" },
})
console.log("Session ID:", session.id)

// Create a child session
const childSession = await client.session.create({
  body: { title: "Child session", parentID: session.id },
})

// List all sessions
const sessions = await client.session.list()

// Get a session by ID
const retrieved = await client.session.get({ path: { id: session.id } })

// Update session title
await client.session.update({
  path: { id: session.id },
  body: { title: "Updated Title" },
})

// List child sessions
const children = await client.session.children({ path: { id: session.id } })

// Get todo list for a session
const todos = await client.session.todo({ path: { id: session.id } })

// Delete a session
await client.session.delete({ path: { id: childSession.id } })

Prompting

// Send a basic prompt
const result = await client.session.prompt({
  path: { id: session.id },
  body: {
    parts: [{ type: "text", text: "Hello!" }],
  },
})
console.log(result.data.info) // AssistantMessage

// Send prompt with a specific model
const result2 = await client.session.prompt({
  path: { id: session.id },
  body: {
    model: { providerID: "anthropic", modelID: "claude-3-5-sonnet-20241022" },
    parts: [{ type: "text", text: "Explain this codebase" }],
  },
})

// Send prompt with a specific agent
const result3 = await client.session.prompt({
  path: { id: session.id },
  body: {
    agent: "plan",
    parts: [{ type: "text", text: "Create a plan for this feature" }],
  },
})

// Send prompt with system override
const result4 = await client.session.prompt({
  path: { id: session.id },
  body: {
    system: "You are a senior Go developer. Be concise.",
    parts: [{ type: "text", text: "Review this function" }],
  },
})

// Send prompt with tool control
const result5 = await client.session.prompt({
  path: { id: session.id },
  body: {
    tools: { read: true, write: false, bash: false },
    parts: [{ type: "text", text: "Read and analyze the code" }],
  },
})

// Inject context without triggering AI response (noReply)
await client.session.prompt({
  path: { id: session.id },
  body: {
    noReply: true,
    parts: [{ type: "text", text: "You are a helpful assistant." }],
  },
})

// Send prompt with file parts
const result6 = await client.session.prompt({
  path: { id: session.id },
  body: {
    parts: [
      { type: "text", text: "Review this file" },
      {
        type: "file",
        mime: "text/plain",
        url: "file:///path/to/file.ts",
      },
    ],
  },
})

// Send prompt with agent invocation part
const result7 = await client.session.prompt({
  path: { id: session.id },
  body: {
    parts: [
      {
        type: "agent",
        name: "explore",
        source: { value: "Find all usages of createOpencode", start: 0, end: 30 },
      },
    ],
  },
})

// Send prompt asynchronously (fire and forget)
await client.session.prompt_async({
  path: { id: session.id },
  body: {
    parts: [{ type: "text", text: "Process this in the background" }],
  },
})

Commands

// Execute a slash command
const cmdResult = await client.session.command({
  path: { id: session.id },
  body: {
    command: "compact",
    arguments: "",
  },
})

// List available commands
const commands = await client.command.list()

Shell

// Run a shell command
const shellResult = await client.session.shell({
  path: { id: session.id },
  body: {
    agent: "build",
    command: "ls -la",
  },
})

// Run shell with specific model
const shellResult2 = await client.session.shell({
  path: { id: session.id },
  body: {
    agent: "build",
    model: { providerID: "anthropic", modelID: "claude-3-5-sonnet-20241022" },
    command: "git status",
  },
})

Messages

// List messages in a session
const messages = await client.session.messages({ path: { id: session.id } })
for (const msg of messages) {
  console.log(msg.info.role, msg.parts.map(p => p.type))
}

// List messages with limit
const recentMessages = await client.session.messages({
  path: { id: session.id },
  query: { limit: 10 },
})

// Get a single message
const msg = await client.session.message({
  path: { id: session.id, messageID: "msg-123" },
})

Abort

// Abort a running session
await client.session.abort({ path: { id: session.id } })

Share / Unshare

// Share a session (generates a shareable URL)
const shared = await client.session.share({ path: { id: session.id } })
console.log("Share URL:", shared.share?.url)

// Unshare a session
const unshared = await client.session.unshare({ path: { id: session.id } })

Diff

// Get the diff for a session
const diffs = await client.session.diff({ path: { id: session.id } })
for (const diff of diffs) {
  console.log(`${diff.file}: +${diff.additions} -${diff.deletions}`)
}

// Get diff for a specific message
const msgDiffs = await client.session.diff({
  path: { id: session.id },
  query: { messageID: "msg-123" },
})

Summarize

// Summarize a session
await client.session.summarize({
  path: { id: session.id },
  body: {
    providerID: "anthropic",
    modelID: "claude-3-5-sonnet-20241022",
  },
})

Revert / Unrevert

// Revert a specific message
await client.session.revert({
  path: { id: session.id },
  body: {
    messageID: "msg-123",
    partID: "part-456", // optional — revert a specific part
  },
})

// Restore all reverted messages
await client.session.unrevert({ path: { id: session.id } })

Permissions Response

// Respond to a permission request
await client.postSessionByIdPermissionsByPermissionId({
  path: {
    id: session.id,
    permissionID: "perm-123",
  },
  body: {
    response: "always", // "once" | "always" | "reject"
  },
})

Fork

// Fork a session at a specific message
const forked = await client.session.fork({
  path: { id: session.id },
  body: {
    messageID: "msg-123", // optional — fork from the beginning if omitted
  },
})
console.log("Forked session:", forked.id)

Init

// Analyze the current app and create AGENTS.md
await client.session.init({
  path: { id: session.id },
  body: {
    messageID: "msg-123",
    providerID: "anthropic",
    modelID: "claude-3-5-sonnet-20241022",
  },
})

Session Status

// Get status for all sessions
const statuses = await client.session.status()
// Returns: { [sessionID: string]: SessionStatus }
// SessionStatus is: { type: "idle" } | { type: "busy" } | { type: "retry", attempt: number, message: string, next: number }

File Operations

// Read a file
const content = await client.file.read({
  query: { path: "src/index.ts" },
})
console.log(content.content) // file content string

// List files and directories at a path
const fileList = await client.file.list({
  query: { path: "src" },
})
// Returns FileNode[] with { name, path, absolute, type, ignored }

// Search for text in files (ripgrep-style)
const textResults = await client.find.text({
  query: { pattern: "function.*opencode" },
})
for (const match of textResults) {
  console.log(`${match.path.text}:${match.line_number}: ${match.lines.text}`)
}

// Find files by name (fuzzy match)
const files = await client.find.files({
  query: { query: "*.ts" },
})

// Find directories
const dirs = await client.find.files({
  query: { query: "packages", type: "directory", limit: 20 },
})

// Find files with directory override
const customDirFiles = await client.find.files({
  query: { query: "*.json", directory: "/some/other/path" },
})

// Find workspace symbols
const symbols = await client.find.symbols({
  query: { query: "createOpencode" },
})

// Get file status (tracked files with git status)
const status = await client.file.status()
// Returns File[] with { path, added, removed, status: "added" | "deleted" | "modified" }

find.files query parameters:

| Parameter | Type | Description | |---|---|---| | query | string | Required. Search string (fuzzy match) | | type | "file" or "directory" | Optional. Limit results to files or directories | | directory

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.