cara liom

Developer guide · Plugin SDK

Writing plugins

A plugin adds one feature to Cara Liom. The Plugin SDK gives your code a safe, typed way to show a screen, read contact data, and save plugin data.

01 · The basics

What is the Plugin SDK?

SDK means “software development kit.” It is code and tools that help you build software for another app. The Cara Liom Plugin SDK has shared rules and helper functions. Your plugin uses them to talk to Cara Liom.

A plugin does not open the app’s files or database. It asks the SDK for the data it needs. Cara Liom checks each request and returns only the allowed data. This keeps plugins separate from the app’s private code.

A schema is a set of rules for data. The declaration lists each schema. Cara Liom checks saved data against these rules.

A declaration

A JSON file lists the plugin name, data, screens, and access it needs.

SDK clients

Small tools read contacts and save the plugin’s own data.

React helpers

Hooks load data and help save changes from a plugin screen.

02 · Start a project

Make a new plugin

The SDK has templates for a screen, contact data, a command, or a trusted plugin. Use the contact-data template if your plugin adds a tab to a contact.

caraliom-plugin new ../my-plugin \
  --template contact-data \
  --language typescript \
  --id app.example.my-plugin \
  --name "My Plugin"

The tool creates a new project. It does not change an existing folder. Install its packages, then run the project scripts. The tests check the plugin using the same SDK clients that the app uses.

03 · Use SDK modules

Import the tool you need

The SDK has separate entry points for different jobs. Use /client for contact and storage clients. Use /react for React hooks. Use /ui for shared buttons and form parts.

import { contactClient } from "@caraliom/plugin-sdk/client";
import { useContact } from "@caraliom/plugin-sdk/react";
import { Button } from "@caraliom/plugin-sdk/ui";

Backend code uses @caraliom/plugin-sdk/backend. It is separate from the screen code. A plugin without a backend does not need this import.

04 · Declare its shape

Tell Cara Liom what it adds

The file caraliom.plugin.json is the plugin declaration. It sets the plugin ID, name, and version. It can also list data storage, screens, and services. Cara Liom checks these details before it loads the plugin.

This short example adds a contact tab. The ID must be unique. The entry points to the file that contains the tab.

{
  "id": "app.example.my-plugin",
  "name": "My Plugin",
  "version": "1.0.0",
  "kind": "community",
  "contributions": {
    "contactTabs": {
      "my-tab": {
        "label": "My tab",
        "entry": "view.tsx",
        "export": "MyTab"
      }
    }
  }
}

05 · Read contacts

Ask for only the fields you need

The SDK contact client can read one contact, read a short list, or search through pages of contacts. You choose the fields to read. For example, a list may need a name and email, but not every field in the contact.

In a React screen, use useContact, useContacts, or useContactQuery. Use contactClient when you need direct control, such as scanning pages or listening for changes.

The client returns typed data. It checks the reply from the app before giving the data to your code. Use a subscription when your screen should refresh after contacts change. Stop the subscription when the screen closes.

06 · Save plugin data

Keep plugin data in its own space

The declaration names each place where a plugin can save data. Contact extensions hold a small value for one contact. Named records hold a list of values, such as an interaction history. Settings hold plugin preferences. The host checks saved values against the schema in the declaration.

Use useExtensionDraft, useRecordDraft, or useSettingsDraft for editable forms. These helpers track loading, edits, and saves. They also help stop navigation from losing unsaved changes.

Every write names the version it read. If another change happened first, the host returns a conflict. Read the latest value and let the user choose what to save. Do not silently replace newer data.

07 · Build and test

Check the plugin before sharing

The SDK build checks the declaration, source files, and imports. It creates the app-ready manifest and bundles the plugin’s screens. Build after you change the declaration so the generated client types match it.

pnpm install
pnpm run build
pnpm run check

If the project has a test script, run it too. Test loading, empty data, save errors, and changes made elsewhere. Read the Contact Cadence listing for a working example that uses contact scans, contact extensions, and named records.

08 · Backend code

Use a backend only when needed

A screen-only plugin does not need a backend. Add a backend when the plugin has declared operations or data changes that must run outside its screen. The backend uses defineBackend and must provide the handlers named in the declaration.

The app starts backend code inside its plugin boundary. A community plugin can use only the services and data access that its declaration allows. Do not put private keys or passwords in a screen bundle.