Documentation / Local API

Local API

Discover the active Cairn process, authenticate with its owner-only token, and call the live descriptor registry.

API 1.0 scope

The current API is a local control and plugin-management surface. It does not expose workspace, terminal, session, screen-band, or layout operations.

Connection sequence

  1. Discover. Read $CAIRN_HOME/state/control.json, or ~/.local/state/ghostty/control.json when CAIRN_HOME is unset. It is a symlink to the active mode-0600 control.<pid>.json.
  2. Verify the instance. Parse apiVersion, pid, socketPath, tokenPath, startedAt, and transport. Read the mode-0600 token file.
  3. Connect locally. Open the mode-0600 Unix-domain socket. Cairn rejects peers whose effective user ID differs from the server’s before routing requests.
  4. Authenticate once. The first useful call is api/hello. Request only the capabilities you need; Cairn grants the intersection available to the token.
  5. Exchange NDJSON. Send one UTF-8 JSON-RPC 2.0 object per newline. Each record is limited to 4 MiB. Responses and event notifications use the same connection.
{"jsonrpc":"2.0","id":1,"method":"api/hello","params":{
  "token":"<contents of tokenPath>",
  "capabilities":["api.read"]
}}

Methods

The table below is generated from DeveloperAPICatalog and PluginAPICatalog.

api/describe

api.read

Return the live method, event, and capability catalog.

Params

{

}

Result

{
  "apiVersion" : "string",
  "capabilities" : [

  ],
  "events" : [

  ],
  "methods" : [

  ],
  "transport" : "string"
}

api/hello

public handshake

Authenticate a connection and negotiate capabilities.

Params

{
  "capabilities" : [
    "string"
  ],
  "token" : "string"
}

Result

{
  "apiVersion" : "string",
  "grantedCapabilities" : [
    "string"
  ],
  "sessionId" : "uuid"
}

api/ping

api.read

Check authenticated API liveness.

Params

{
  "nonce" : "any JSON value"
}

Result

{
  "nonce" : "any JSON value",
  "ok" : true
}

api/subscribe

events.subscribe

Subscribe this session to named API events.

Params

{
  "events" : [
    "event name"
  ]
}

Result

{
  "subscriptionId" : "uuid"
}

api/unsubscribe

events.subscribe

Remove one event subscription from this session.

Params

{
  "subscriptionId" : "uuid"
}

Result

{
  "removed" : true
}

plugins/grants/set

plugins.manage

Replace one plugin's explicit capability grants.

Params

{
  "capabilities" : [
    "manifest-declared capability"
  ],
  "pluginId" : "reverse-DNS plugin identifier"
}

Result

{
  "grantedCapabilities" : [
    "capability"
  ],
  "pluginId" : "reverse-DNS plugin identifier"
}

plugins/list

plugins.read

List discovered plugins and their explicit grants.

Params

{

}

Result

{
  "plugins" : [
    {
      "activationEvents" : [
        "activation event"
      ],
      "commands" : [
        "command identifier"
      ],
      "declaredCapabilities" : [
        "capability"
      ],
      "grantedCapabilities" : [
        "capability"
      ],
      "id" : "reverse-DNS plugin identifier",
      "name" : "display name",
      "panels" : [
        "panel identifier"
      ],
      "version" : "plugin version"
    }
  ]
}

plugins/reload

plugins.manage

Rediscover plugin manifests and stop replaced processes.

Params

{

}

Result

{
  "pluginCount" : 0
}

Events

Authenticate with events.subscribe, call api/subscribe with one or more known event names, and retain the returned subscription UUID. Notifications have no id. Use api/unsubscribe to stop delivery.

{"jsonrpc":"2.0","id":2,"method":"api/subscribe",
 "params":{"events":["api/catalogChanged","api/serverStopping"]}}

{"jsonrpc":"2.0","method":"api/catalogChanged",
 "params":{"apiVersion":"1.0"}}
EventMeaningCapabilityParams
api/catalogChanged The live descriptor catalog changed. events.subscribe { "apiVersion" : "string" }
api/serverStopping The local developer API server is stopping. events.subscribe { "pid" : 0 }

Subscriptions belong to the calling connection. Cairn removes them when the socket closes and re-checks the event capability at publish time.