plugins/src/harper-fabric/skills/harper-realtime/SKILL.md
This skill should be used when adding or troubleshooting Harper (HarperDB/Fabric) real-time behavior: MQTT topics, WebSocket resource subscriptions, resource publish/subscribe handlers, SSE-style streaming routes, and local subscriber verification. Pairs with harper-resources, harper-config-yaml, harper-schema-graphql, and harper-build-and-deploy.
npx skillsauth add codyswanngt/lisa harper-realtimeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
Security scan pending...
This skill is queued for security scanning. Results will appear when the scan completes.
Harper exposes live data through the same Resource model used for REST and GraphQL. Exported tables/resources can be addressed as MQTT topics and WebSocket paths, while custom resources can override the messaging handlers when the default table behavior is not enough.
Use real-time primitives when the product needs pushed state: live feeds, activity streams, collaborative views, device telemetry, or status updates. Do not replace these with client polling unless the issue explicitly asks for polling.
@table @export creates a default exported table resource.resources.js creates a resource
endpoint with the class name as the path/topic root.resource/# for a resource
subtree and resource/+/status for one path segment.ws://localhost:9926/Activity/123 subscribes to the Activity resource record
with id 123.Keep the URL/topic names stable. If a UI depends on Activity/123, changing the
resource export name is an API break.
The MQTT plugin routes broker messages through Resource methods:
| Method | Use |
| --- | --- |
| subscribe(target, context) | Authorize and shape subscription reads for a resource or record. |
| publish(target, message, context) | Accept or transform messages written to a topic/resource. |
| connect(incomingMessages) | Customize WebSocket connection behavior for a resource. |
For table-backed resources, prefer default behavior until the product needs a
custom message shape, authorization check, fan-out, or derived event. When
overriding, preserve built-in table behavior with super.subscribe(...) or
super.publish(...) where that behavior is still wanted.
export class Activity extends tables.Activity {
static async publish(target, message, context) {
const payload = await message;
await super.publish(target, payload, context);
return { ...payload, acceptedAt: Date.now() };
}
}
For WebSocket-only behavior, implement connect(incomingMessages) and return an
async iterable. Use the default super.connect() stream when you only need to
push extra server messages or clean up on disconnect.
| Transport | Best fit | Notes |
| --- | --- | --- |
| MQTT | Device streams, backend subscribers, wildcard topics, durable clients. | Plain MQTT defaults to port 1883; MQTTS defaults to 8883. |
| MQTT over WebSocket | Browser or edge clients using MQTT semantics. | Uses the HTTP port, default 9926, with the mqtt WebSocket subprotocol. |
| Resource WebSocket | Browser live views tied to one REST resource path. | Enabled with the rest plugin unless rest.webSocket: false is set. |
| SSE/custom streaming route | One-way browser updates when WebSocket is not appropriate. | Implement as a project route; do not assume SSE automatically subscribes to Resource changes. |
Authentication is usually required for MQTT. When mqtt.requireAuthentication is
false, authorization still applies at the resource/table level, so public
connections must be explicitly allowed by roles or resource logic.
Component-level config.yaml enables the app surface:
rest: true
graphqlSchema:
files: schema.graphql
jsResource:
files: resources.js
The root Harper harper-config.yaml, not the component config.yaml, owns broker
ports and MQTT authentication:
mqtt:
network:
port: 1883
securePort: 8883
webSocket: true
requireAuthentication: true
Keep the rest, graphqlSchema, and jsResource declarations together when a
project has a custom component config.yaml. Harper does not merge custom
component config with defaults. See [[harper-config-yaml]].
Resource/<id>) when the UI watches one
entity; use collection or wildcard subscriptions only when the product needs a
feed.For clustered/Fabric deployments, real-time behavior must match the deploy target:
replicated=true when deploying a component that needs to run across Fabric
nodes. See [[harper-build-and-deploy]].Build generated Harper assets from source:
bun run build
Start the component:
harper dev harper-app
In another shell, subscribe to a topic or WebSocket path:
npx mqtt sub -h localhost -p 1883 -u HDB_ADMIN -P "$HARPER_PASSWORD" -t 'Activity/#' -v
npx wscat -c ws://localhost:9926/Activity/123
Publish or mutate the watched record:
npx mqtt pub -h localhost -p 1883 -u HDB_ADMIN -P "$HARPER_PASSWORD" -t 'Activity/123' -m '{"status":"live"}'
Confirm the subscriber receives the expected message shape and that a normal REST/GraphQL read returns the same resulting state.
Record the command, topic/path, payload, and observed message in PR evidence. If a local Harper binary or credentials are unavailable, report that blocker instead of claiming the subscription was verified.
src/; harper-app/resources.js is a
generated artifact. See [[harper-resources]].config.yaml, update the project Fabric runbook and
re-run the smoke path. See [[harper-config-yaml]].plugins/src/harper-fabric, run
bun run build:plugins, and commit both source and generated plugin copies.tools
Configure the official SonarQube plugin + MCP as Lisa's single Sonar substrate across every supported coding agent. Installs/updates the SonarQube CLI, authenticates (browser login on a dev machine, or SONARQUBE_CLI_TOKEN headless), selects the Test Manager target, runs `sonar integrate <agent>` for each supported agent (Claude, Codex, Cursor, Copilot, Antigravity) and wires the MCP for OpenCode, then writes only non-secret policy to .lisa.config.json. Separate from the CI SonarCloud scan gate, which is unchanged.
tools
Configure the official SonarQube plugin + MCP as Lisa's single Sonar substrate across every supported coding agent. Installs/updates the SonarQube CLI, authenticates (browser login on a dev machine, or SONARQUBE_CLI_TOKEN headless), selects the Test Manager target, runs `sonar integrate <agent>` for each supported agent (Claude, Codex, Cursor, Copilot, Antigravity) and wires the MCP for OpenCode, then writes only non-secret policy to .lisa.config.json. Separate from the CI SonarCloud scan gate, which is unchanged.
tools
Configure the official SonarQube plugin + MCP as Lisa's single Sonar substrate across every supported coding agent. Installs/updates the SonarQube CLI, authenticates (browser login on a dev machine, or SONARQUBE_CLI_TOKEN headless), selects the Test Manager target, runs `sonar integrate <agent>` for each supported agent (Claude, Codex, Cursor, Copilot, Antigravity) and wires the MCP for OpenCode, then writes only non-secret policy to .lisa.config.json. Separate from the CI SonarCloud scan gate, which is unchanged.
tools
Configure the official SonarQube plugin + MCP as Lisa's single Sonar substrate across every supported coding agent. Installs/updates the SonarQube CLI, authenticates (browser login on a dev machine, or SONARQUBE_CLI_TOKEN headless), selects the Test Manager target, runs `sonar integrate <agent>` for each supported agent (Claude, Codex, Cursor, Copilot, Antigravity) and wires the MCP for OpenCode, then writes only non-secret policy to .lisa.config.json. Separate from the CI SonarCloud scan gate, which is unchanged.