← Back to news
ZBuild News

Build a Full-Stack Bookmark Manager with OpenCode in 30 Minutes (Step-by-Step)

A project-based OpenCode tutorial where you build a complete bookmark manager with tags, search, and a REST API — using OpenCode's AI agent in the terminal. Every feature is introduced as you need it, not in a features list.

Published
2026-03-27
Author
ZBuild Team
Reading Time
14 min read
opencode tutorialopencode guideopencode installopencode setupopencode configurationopencode ai coding agent
Build a Full-Stack Bookmark Manager with OpenCode in 30 Minutes (Step-by-Step)
ZBuild Teamen
XLinkedIn

What We Are Building

Forget feature lists. The best way to learn a tool is to build something with it.

In this tutorial, you will use OpenCode — the open-source AI coding agent with 120K+ GitHub stars — to build a complete bookmark manager from scratch. The app will have:

  • A REST API with Express.js and TypeScript
  • A SQLite database with full-text search
  • A tag system for organizing bookmarks
  • A simple but functional frontend
  • Unit tests

Every OpenCode feature gets introduced the moment you need it — not in an abstract features section. By the end, you will know how to install OpenCode, configure models, use Build and Plan modes, set up MCP servers, and create custom agents — all because you used them to build a real project.

Time: ~30 minutes Prerequisites: Node.js 18+ installed, a terminal (macOS, Linux, or WSL on Windows) Cost: Free (using OpenCode Zen models)


Phase 1: Installing OpenCode and Setting Up the Project (5 minutes)

Install OpenCode

Open your terminal and run one of these commands:

# Option 1: npm (recommended)
npm i -g opencode-ai@latest

# Option 2: Homebrew (macOS/Linux)
brew install sst/tap/opencode

# Option 3: One-line installer
curl -fsSL https://opencode.ai/install.sh | bash

Verify the installation:

opencode --version

You should see the version number. As of March 2026, the latest stable release is available on the OpenCode GitHub repository.

Create the Project Directory

mkdir bookmark-manager && cd bookmark-manager
git init
npm init -y

Launch OpenCode for the First Time

opencode

This opens OpenCode's TUI (Terminal User Interface) — a full-screen interactive interface built with Bubble Tea. You will see a chat input at the bottom and a conversation pane in the main area.

Choose a Model

On first launch, OpenCode will ask you to select a model. You have three paths:

Free (Zen models): Type /models and select one of the free Zen models. For this tutorial, Grok Code Fast 1 or GLM 4.7 work well. These are free and require no API key.

Local (Ollama): If you have Ollama installed, OpenCode will detect it automatically. The recommended model for Ollama is glm-4.7:cloud.

Paid (bring your own key): Type /connect to link your Anthropic, OpenAI, or Google API key. Keys are stored locally in ~/.local/share/opencode/auth.json.

For this tutorial, any model works. Higher-capability models (Claude Sonnet 4.6, GPT-5.4) will produce better results on complex tasks, but the free Zen models handle everything we are building here.


Phase 2: Scaffolding the Project with Build Mode (4 minutes)

OpenCode starts in Build mode by default. Build mode gives the AI agent full access to create files, edit code, and run commands. This is what we want for scaffolding.

Your First Prompt

Type this into the OpenCode chat:

Set up a TypeScript Node.js project with Express for a bookmark manager REST API.
Use SQLite via better-sqlite3 for the database. Add TypeScript, ts-node, and
nodemon as dev dependencies. Create a src/ directory with an index.ts entry point
that starts an Express server on port 3000.

OpenCode will:

  1. Create a tsconfig.json
  2. Install dependencies with npm install
  3. Create src/index.ts with the Express server setup
  4. Update package.json with start scripts

Watch the TUI — you will see the agent executing terminal commands, creating files, and explaining what it does at each step. This is not code generation in a vacuum; OpenCode has full access to your filesystem and terminal.

Verify It Works

Once OpenCode finishes, tell it:

Run the server and verify it starts correctly on port 3000.

OpenCode will run npx nodemon src/index.ts and confirm the server is listening. You should see output like Server running on http://localhost:3000.

What Just Happened (Feature: Build Mode)

Build mode is OpenCode's default agent. It has access to all tools: file read/write, terminal execution, and code editing. According to the OpenCode documentation, you can think of it as an AI pair programmer with full access to your development environment.


Phase 3: Creating the Data Model and Database (4 minutes)

Design the Schema

Type this prompt:

Create a database module at src/db.ts that:
1. Initializes a SQLite database at ./data/bookmarks.db
2. Creates a bookmarks table with: id (auto-increment), url (text, unique),
   title (text), description (text, nullable), created_at (datetime),
   updated_at (datetime)
3. Creates a tags table with: id (auto-increment), name (text, unique)
4. Creates a bookmark_tags junction table for many-to-many relationships
5. Enables WAL mode for concurrent read performance
6. Creates an FTS5 virtual table for full-text search on title and description
Export a function to get the database instance.

OpenCode will generate the full database module. Pay attention to how it handles the FTS5 (Full-Text Search 5) setup — this is a SQLite feature that will power our search functionality later.

Initialize the Database on Server Start

Import the database module in index.ts and initialize it when the server starts.
Log a confirmation message.

Create the opencode.json Config

This is a good moment to introduce project configuration. Create a file by telling OpenCode:

Create an opencode.json file in the project root with the project name
"bookmark-manager" and a rule that says "This is a TypeScript Express API
using better-sqlite3. Follow RESTful conventions. Use async/await. Return
JSON responses with consistent error formatting."

This creates the project configuration file that OpenCode reads on startup. It gives the AI persistent context about your project — coding standards, architecture decisions, and constraints — so you do not have to repeat them in every prompt.


Phase 4: Building the REST API Endpoints (5 minutes)

Generate the Routes

Create a routes module at src/routes/bookmarks.ts with these endpoints:
- POST /api/bookmarks — create a bookmark (validate url and title are present)
- GET /api/bookmarks — list all bookmarks with pagination (page, limit params)
- GET /api/bookmarks/:id — get a single bookmark with its tags
- PUT /api/bookmarks/:id — update a bookmark
- DELETE /api/bookmarks/:id — delete a bookmark and its tag associations
Use proper HTTP status codes. Return JSON with a consistent shape:
{ success: boolean, data: any, error?: string }

Register the Routes

Import the bookmark routes in index.ts and register them. Also add
express.json() middleware and a global error handler.

Test with curl

Start the server, then create a test bookmark using curl:
curl -X POST http://localhost:3000/api/bookmarks \
  -H "Content-Type: application/json" \
  -d '{"url": "https://opencode.ai", "title": "OpenCode - AI Coding Agent"}'
Then fetch all bookmarks to verify it was saved.

OpenCode will execute these commands in your terminal and show you the responses. This is where the tool shines — you never leave the terminal, and the AI verifies its own work.


Phase 5: Adding Search with FTS5 (4 minutes)

Introduce Plan Mode

Before building search, let us use Plan mode to think through the implementation. Switch modes:

/plan

Now you are in Plan mode. The AI can read your code and analyze it but cannot modify any files. This is useful for planning before making changes.

Analyze my current database schema and FTS5 table. Plan how to implement a
search endpoint that queries the FTS5 table and returns bookmarks ranked by
relevance. Consider edge cases: empty queries, special characters, partial
matches.

OpenCode will examine your code, write a plan to .opencode/plans/, and explain its approach without touching any files. Read the plan, adjust if needed, then switch back:

/build

Implement Search

Based on the plan, implement a GET /api/bookmarks/search?q=query endpoint
that uses the FTS5 virtual table for full-text search. Include snippet
highlighting and relevance ranking. Handle edge cases from the plan.

Test Search

Create three more test bookmarks with different titles and descriptions,
then test the search endpoint with a query that should match two of them.

What Just Happened (Feature: Plan Mode)

The Plan/Build workflow is how experienced developers use OpenCode on complex tasks. Plan first, review the approach, then build. The plan files are saved to .opencode/plans/ and can be referenced later by the build agent. This prevents the AI from making large structural decisions on the fly.


Phase 6: Implementing the Tag System (4 minutes)

Create Tag Endpoints

Create a routes module at src/routes/tags.ts with:
- POST /api/tags — create a new tag
- GET /api/tags — list all tags with bookmark counts
- POST /api/bookmarks/:id/tags — add a tag to a bookmark
- DELETE /api/bookmarks/:id/tags/:tagId — remove a tag from a bookmark
- GET /api/bookmarks?tag=tagname — filter bookmarks by tag (update existing
  list endpoint to support this query parameter)
Register the tag routes in index.ts.

Test the Tag Flow

Create two tags: "dev-tools" and "tutorials". Add the "dev-tools" tag to
the OpenCode bookmark. Then fetch bookmarks filtered by the "dev-tools" tag.

Phase 7: Building a Simple Frontend (5 minutes)

Generate the Frontend

Create a public/ directory with a single-page frontend:
- index.html with a clean, minimal design (no framework, just HTML/CSS/JS)
- A form to add bookmarks (url, title, description)
- A search bar that queries the search endpoint with debounced input
- A list of bookmarks showing title, url, tags, and a delete button
- A tag filter sidebar that shows all tags with counts
- Use fetch() for API calls. Mobile responsive. No build step needed.
Serve the public/ directory as static files from Express.

OpenCode will generate the complete frontend — HTML structure, CSS styling, and JavaScript for API interactions — in one pass. The advantage of building this in the terminal with an AI agent is that it can immediately test whether the frontend connects to the API.

Test the Full Stack

Start the server, open http://localhost:3000 in a description, and verify
that adding a bookmark from the form, searching, and filtering by tag all
work correctly.

Phase 8: Adding Tests with a Custom Agent (5 minutes)

Create a Custom Test Agent

This is where OpenCode's custom agents feature comes in. Instead of using the generic Build agent for testing, we will create a specialized one.

Add this to your opencode.json:

{
  "agents": {
    "test": {
      "name": "Test Writer",
      "instructions": "You are a testing specialist. Write comprehensive tests using Vitest. Focus on edge cases and error paths. Never modify source code — only create and edit test files.",
      "tools": ["read", "write", "terminal"]
    }
  }
}

Now switch to the test agent:

/agent test

Generate Tests

Write comprehensive tests for the bookmark API using Vitest and supertest.
Cover:
- Creating a bookmark with valid data
- Creating a bookmark with missing required fields
- Fetching all bookmarks with pagination
- Searching with FTS5 (matching and non-matching queries)
- Adding and removing tags
- Deleting a bookmark removes its tag associations
Use an in-memory SQLite database for test isolation.

Run the Tests

Install vitest and supertest as dev dependencies, add a test script to
package.json, then run the test suite.

What Just Happened (Feature: Custom Agents)

Custom agents let you create focused personas with specific instructions and tool access. The test agent we created can only read files, write test files, and run terminal commands — it cannot modify source code. This constraint prevents the common problem of AI "fixing" your source code when tests fail instead of fixing the tests.

You can create agents for any specialized workflow: code review, documentation, database migrations, DevOps scripts. The OpenCode agents documentation has more examples.


Bonus: Connecting an MCP Server for Enhanced Functionality

If you want to extend your bookmark manager, you can connect external tools via MCP (Model Context Protocol) servers.

Example: Adding a Link Preview MCP Server

Imagine you want OpenCode to automatically fetch metadata (title, description, favicon) from URLs when creating bookmarks. You can connect an MCP server that does HTTP fetching:

Add this to your opencode.json:

{
  "mcp": {
    "link-preview": {
      "type": "local",
      "command": ["npx", "link-preview-mcp-server"]
    }
  }
}

Now OpenCode has a new tool available: it can fetch URL metadata as part of its workflow. When you ask it to "add a bookmark for https://example.com and auto-fill the title and description," it will use the MCP server to fetch that data.

Remote MCP Servers

For cloud services, use remote MCP servers with automatic OAuth handling:

{
  "mcp": {
    "cloud-storage": {
      "type": "remote",
      "url": "https://mcp.example.com/storage",
      "headers": {
        "Authorization": "Bearer ${STORAGE_TOKEN}"
      }
    }
  }
}

OpenCode detects 401 responses and initiates the OAuth flow automatically if the server supports Dynamic Client Registration.


Bonus: Using OpenCode in CI/CD

OpenCode has a CLI mode that runs without the TUI — perfect for automation. You can use it in GitHub Actions or any CI pipeline:

# Run a single prompt and exit
opencode -p "Review the changes in the last commit for security issues" --no-tui

# Use a specific model
opencode -m "claude-sonnet-4-6" -p "Generate a changelog entry for this release" --no-tui

For our bookmark manager, you could add a CI step that runs OpenCode to review PRs automatically. The OpenCode GitHub integration provides a more streamlined version of this workflow.


The Complete Project Structure

After following this tutorial, your project should look like this:

bookmark-manager/
  opencode.json          # OpenCode project config + custom agents + MCP
  package.json
  tsconfig.json
  src/
    index.ts             # Express server entry point
    db.ts                # SQLite database module with FTS5
    routes/
      bookmarks.ts       # CRUD + search endpoints
      tags.ts            # Tag management endpoints
  public/
    index.html           # Single-page frontend
  tests/
    bookmarks.test.ts    # API test suite
  data/
    bookmarks.db         # SQLite database (gitignored)
  .opencode/
    plans/               # Plans from Plan mode sessions

What You Learned

By building a real project, you practiced these OpenCode capabilities:

FeatureWhere You Used It
InstallationPhase 1 — npm, Homebrew, or curl
Zen models (free)Phase 1 — choosing a model without an API key
Build modePhases 2-7 — full development with file and terminal access
Plan modePhase 5 — analyzing code and planning search before implementing
opencode.jsonPhase 3 — project config with rules for consistent AI behavior
Custom agentsPhase 8 — a test-writing agent that cannot modify source code
MCP serversBonus — extending OpenCode with external tools
CLI modeBonus — running OpenCode in CI/CD without the TUI

The key difference between OpenCode and other AI coding tools is that it is entirely open source, runs in your terminal, and does not store your code or context data. You control the models, the data stays local, and the community of 800+ contributors keeps it evolving fast.

For teams using multiple AI tools, OpenCode works well as the terminal-based complement to IDE assistants. At ZBuild, we often use it alongside editor-based tools for different parts of the development workflow.


Next Steps

Now that you have a working bookmark manager and a solid understanding of OpenCode, here are some directions to explore:

  1. Add authentication — Use the Build agent to add JWT-based auth with user accounts
  2. Deploy to production — Ask OpenCode to generate a Dockerfile and deploy to Fly.io or Railway
  3. Build a browser extension — Create a Chrome extension that adds bookmarks via the API
  4. Explore more Zen models — Try Big Pickle, MiniMax M2.1, or run a local model through Ollama
  5. Create more custom agents — A "refactor" agent, a "docs" agent, or a "security audit" agent

The OpenCode documentation and the awesome-opencode repository have more plugins, themes, and community configurations to explore.


Sources

Back to all news
Enjoyed this article?
FAQ

Common questions

What are we building in this tutorial?+
A full-stack bookmark manager with a Node.js/Express REST API, SQLite database, tag system, full-text search, and a simple HTML/CSS/JS frontend. The entire app is built using OpenCode as the AI coding agent in the terminal, demonstrating real workflows rather than listing features.
Do I need an API key to follow this tutorial?+
No. OpenCode offers free Zen models including Grok Code Fast, GLM 4.7, and Big Pickle that work without API keys. You can also run fully offline with local models via Ollama. If you have a Claude, GPT, or Gemini API key, you can use those for higher quality output.
How long does the full project take to build?+
About 30 minutes if you follow along step by step. The tutorial is structured in 7 phases: project setup, data model, API endpoints, search, tags, frontend, and testing. Each phase takes 3-5 minutes with OpenCode handling the code generation.
Can I use OpenCode in VS Code or Cursor?+
Yes. OpenCode runs in any integrated terminal. Open a split terminal in VS Code (Cmd+Esc on Mac) or Cursor and launch OpenCode from there. It automatically shares your selection and open file context with the AI agent.
What is the difference between Build mode and Plan mode?+
Build mode gives the AI agent full access to read, write, and execute code. Plan mode restricts it to read-only analysis — the agent can examine your code and create plan files but cannot modify anything. We use Plan mode in this tutorial before major refactoring steps.
How do I add MCP servers to OpenCode?+
Add them in your opencode.json config under the mcp key. Each MCP server needs a unique name, a type (local or remote), and connection details. Local servers use a command field; remote servers use a url field with optional headers. OpenCode handles OAuth for remote MCP servers automatically.
Recommended Tools

Useful follow-ups related to this article.

Browse All Tools

Build with ZBuild

Turn your idea into a working app — no coding required.

46,000+ developers built with ZBuild this month

Now try it yourself

Describe what you want — ZBuild builds it for you.

46,000+ developers built with ZBuild this month
More Reading

Related articles