HashDo

Developer Docs

HashDo Card Developer Guide

What is a Card?

A card is a self-contained, interactive UI component that fetches live data and renders it visually. Cards work as MCP tools in AI platforms (ChatGPT, Claude, VS Code) and as standalone HTML widgets.

Quick Start

Create a new directory for your card and add a card.ts (or card.js) file:

my-cards/
  hello-world/
    card.ts       # Card definition
    main.hbs      # Optional: Handlebars template file

Card Definition

Every card exports a CardDefinition object with these fields:

import { defineCard } from '@hashdo/core';

export default defineCard({
  name: 'do-hello',
  description: 'A friendly greeting card',

  inputs: {
    name: {
      type: 'string',
      required: true,
      description: 'Name to greet',
    },
  },

  async getData({ inputs, state }) {
    return {
      viewModel: {
        greeting: `Hello, ${inputs.name}!`,
        visits: ((state.visits as number) || 0) + 1,
      },
      state: {
        visits: ((state.visits as number) || 0) + 1,
      },
      textOutput: `Hello, ${inputs.name}!`,
    };
  },

  template: (vm) => `
    <div style="padding:20px; font-family:system-ui;">
      <h2>${vm.greeting}</h2>
      <p>Visit #${vm.visits}</p>
    </div>
  `,
});

Card Fields Reference

Input Types

Actions

Actions let users (or AI agents) trigger operations on the card:

actions: {
  toggleUnits: {
    label: 'Switch Units',
    description: 'Toggle between Celsius and Fahrenheit',
    permission: 'auto',  // auto | confirm | explicit
    async handler({ cardInputs, state, actionInputs }) {
      const next = state.units === 'celsius' ? 'fahrenheit' : 'celsius';
      return {
        state: { ...state, units: next },
        message: `Switched to ${next}`,
      };
    },
  },
}

Templates

Cards can use inline template functions or external Handlebars files:

Inline (recommended for simple cards):

template: (vm) => `<div>${vm.greeting}</div>`

Handlebars file:

template: 'main.hbs'  // Relative to card directory

State Management

Cards persist state across renders. Return a state object from getData() and it will be passed back on subsequent renders via context.state. Use this for counters, preferences, cached data, etc.

Text Output

The textOutput field in getData() provides a plain-text or markdown summary for chat-based AI clients. This appears in the conversation alongside the rendered card visual.

Testing Your Card

  1. Preview server: Run hashdo preview ./my-cards and visit http://localhost:3000
  2. Online editor: Use the Card Editor to prototype and test cards in the browser
  3. MCP server: Run hashdo serve ./my-cards to test with Claude or VS Code

Directory Structure

Cards are discovered by scanning a directory for subdirectories containing card.ts or card.js:

my-cards/
  weather/
    card.ts          # Card definition (required)
    main.hbs         # Handlebars template (optional)
    icon.svg         # Card icon (optional)
  stock-quote/
    card.ts
  qr-code/
    card.ts

Submitting Cards

  1. Fork the HashDo repository on GitHub
  2. Create your card directory under v2/demo-cards/
  3. Test locally with hashdo preview
  4. Submit a pull request with your card

Card submission guidelines:

CLI Commands

hashdo serve [dir]     # Start MCP server (stdio)
hashdo preview [dir]   # HTTP preview server for development
hashdo start [dir]     # Production server (preview + MCP + REST API)
hashdo list [dir]      # List discovered cards

API Endpoints

When running hashdo start, these REST endpoints are available: