OpenCode logoCoding agent·Anomaly

OpenCode + Powabase

Run it with any model. Powabase looks the same on the other end.

OpenCode is open source and works with 75+ model providers, so you're not tied to one vendor. Add the skill and it builds on Powabase the same way no matter which model you point it at.

Rather have it built? Powabase engineers build MVPs free for annual Scale and Enterprise plans.

Quick start

Three steps and OpenCode is building on Powabase.

  1. 1

    Install the Powabase skill

    Run it once in your project. From then on the agent knows the Powabase API and how to call it.

    Terminal
    npx skills add powabase-ai/agent-skills
  2. 2

    Start OpenCode

    Start OpenCode in your repo, with whatever model provider you've set up.

    Terminal
    opencode
  3. 3

    Describe the app

    Describe what you need and OpenCode assembles the project behind a REST API. Use an example below as a template.

Example apps

Real apps, each from one prompt. Copy any of them and give it to OpenCode.

RAG support chatbot

Ingest our product docs, help center, and resolved tickets into a knowledge base, embedding on upload. Expose a support agent that answers with inline citations, streams over SSE, and hands off to a human when confidence is low. Add email and Google sign-in, isolate every conversation per organization with row-level security, and ship it as an embeddable chat widget.

Internal knowledge assistant

Index our wikis, runbooks, and exported threads into a knowledge base, chunking and embedding on upload. Expose an agent that answers with citations and respects per-department access, keep it fresh with scheduled re-indexing of changed sources, and add SSO sign-in plus an analytics view of unanswered questions.

AI help desk

Model tickets, organizations, and agents with row-level security, and auto-triage incoming tickets with an agent that predicts category and priority and drafts a reply from the knowledge base. Escalate low-confidence cases, run SLA timers as scheduled jobs, add email auth, and provide a live queue dashboard.

Sales CRM

Model companies, contacts, deals, and activities in Postgres with row-level security per team and roles for reps and managers. Build a pipeline board with stage tracking, an activity timeline, and semantic search across notes, plus a dashboard of weighted pipeline and win rate. Wire OAuth sign-in and an audit log of every change.

News monitoring app

Pull RSS feeds and news APIs on a schedule, deduplicate and embed each article, and run an agent that clusters related stories, summarizes them, and tags entities and sentiment. Let users define watchlists and alert rules, isolate data per workspace, and deliver a realtime feed plus a daily email digest via a cron job.

Invoice & receipt automation

Accept PDF and image uploads to storage, then extract vendor, line items, totals, and dates with an extraction agent and write validated records to Postgres, routing low-confidence fields to human review. Add approval workflows, per-team access control, exports to accounting formats, and a searchable archive.

Where OpenCode keeps your keys

OpenCode reads its config from ~/.config/opencode/opencode.json and from an opencode.json in your project, and any value in either can pull from the environment with {env:VAR_NAME}. An unset variable becomes an empty string rather than an error. The Powabase MCP server needs no key there because it uses OAuth. Your app's Service Role key belongs in a gitignored .env that server code reads, never in anything the browser loads.

OpenCode docs

Connect over MCP

Config lives at ~/.config/opencode/opencode.json or opencode.json in the project root (JSON file, remote type).

JSON file, remote type
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "powabase": {
      "type": "remote",
      "url": "https://mcp.powabase.ai/mcp",
      "enabled": true
    }
  }
}

OpenCode notices that the server needs OAuth and starts the browser sign-in itself. If it doesn't, run opencode mcp auth powabase. When the same key is set in both files, the project opencode.json wins over the global one.

Append ?read_only=true to the MCP URL and the server exposes only the tools that don't write. We use it for sessions that should inspect a project and never mutate it.

OpenCode MCP docs

OpenCode example

src/agent.ts
// Server-side: answer a question with an agent grounded in one knowledge base.
export async function answer(agentId: string, kbId: string, message: string) {
  const key = process.env.API_KEY!; // Service Role (Secret) Key
  const res = await fetch(`${process.env.BASE_URL}/api/agents/${agentId}/run`, {
    method: "POST",
    headers: {
      apikey: key,
      Authorization: `Bearer ${key}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      message,
      knowledge_bases: [{ id: kbId, top_k: 5 }],
      citations_enabled: true,
    }),
  });
  if (!res.ok) throw new Error(`Agent run failed: ${res.status}`);
  return res.json(); // includes session_id for follow-up turns
}

The request is the same whichever model OpenCode runs. Swapping models changes the code OpenCode writes, not the API it writes against.

Connecting to Powabase from any tool

Mechanics that don’t change from tool to tool.

Anon (Publishable) Key
Client-side
Respects Row Level Security, so it's safe to ship to a browser.
Service Role (Secret) Key
Server-side only
Bypasses RLS. Never put it in anything that ships to a browser.
Keys & RLS docs ↗
  • Every call to /api/* or /rest/v1/* needs two headers, apikey and Authorization: Bearer, both set to the same key. Sending only one is the most common cause of a 401.

    Docs
  • The Database URL from the Connect modal is PgBouncer in transaction mode, not a direct Postgres connection. Disable prepared statements in your driver, or you'll hit prepared statement "..." does not exist. No LISTEN/NOTIFY and no session-level SET across statements. Use Realtime for change notifications; SET LOCAL inside a transaction otherwise. The username and database in the URL are both your project ref, not postgres.

    Docs
  • @supabase/supabase-js mostly works for the BaaS surface (PostgREST, Auth, Storage, Realtime) when you point it at your project URL with the Anon key. It doesn't cover the /api/* AI surface (agents, knowledge bases, orchestrations), which you call over plain REST. There's no /graphql/v1 route: point any GraphQL client at POST /rest/v1/rpc/graphql instead.

    Docs

Common errors

Powabase is in your config, but its tools never load
Cause: The automatic OAuth sign-in didn't start, or the browser tab was closed before it finished.
Fix: Run opencode mcp auth powabase to open the sign-in again, then restart the session.
A {env:...} value in opencode.json comes through blank
Cause: OpenCode replaces an unset variable with an empty string instead of failing.
Fix: Export the variable in the shell that launches OpenCode, then start OpenCode again.
401 Unauthorized
Cause: Only one of the apikey / Authorization headers was sent.
Fix: Send both, set to the same key. Docs
prepared statement "..." does not exist
Cause: PgBouncer's transaction-mode pooler moved you to a different server connection.
Fix: Disable prepared statements in your driver's config. Docs
A query that should return rows comes back empty, or a write is silently rejected
Cause: Row Level Security on your own tables. New public tables ship with RLS off, but once you add policies they gate every request.
Fix: Check the policy's USING/WITH CHECK clause and confirm which role (anon, authenticated, service_role) you actually authenticated as. Docs
The Service Role key turns up in a browser bundle or other client-visible code
Cause: It was used somewhere that ships to the client instead of staying server-side.
Fix: Move the call server-side; use the Anon key with RLS for anything client-visible. If it shipped, rotate it in Studio. Docs

FAQ

Add an entry under "mcp" in opencode.json with "type": "remote" and "url": "https://mcp.powabase.ai/mcp". OpenCode picks it up on the next start and handles the OAuth sign-in.

Yes. For most OAuth servers, OpenCode detects the requirement and opens the browser flow on its own. opencode mcp auth <server-name> triggers it by hand.

On the Powabase side, yes: the REST API, the keys, and the MCP tools don't change with the model. What changes is how well the model uses them. With a weaker model, installing the skill and naming the endpoints in your prompt helps.

Global (~/.config/opencode/opencode.json) if you want Powabase in every repo; the project's opencode.json if only one repo should see it. The project file takes precedence when both set the same thing.