Notes Browser JSON-RPC 2.0 Control API

Overview

The notes_browser supports remote control via JSON-RPC 2.0 protocol over three transport modes:

All requests use line-delimited JSON format. Each JSON-RPC request is sent as a single line followed by newline (LF) character.

Configuration

TCP Mode

Configuration Methods

API Methods

Status Methods

status.ping

Health check - returns current page key

Request:  {"jsonrpc": "2.0", "id": 1, "method": "status.ping", "params": {}}
Response: {"jsonrpc": "2.0", "id": 1, "result": {"ok": true, "page": "current/page/key"}}

status.capabilities

List all available RPC methods and browser capabilities

Request:  {"jsonrpc": "2.0", "id": 1, "method": "status.capabilities", "params": {}}
Response: {"jsonrpc": "2.0", "id": 1, "result": {"version": 1, "read_only": true, "methods": [...]}}

Navigation Methods

navigate.go_to_page

Navigate to a specific page by key

Params: {"key": "page/key"}
Result: {"page": "page/key"}

navigate.back

Go back in navigation history

Params: {}
Result: {"page": "previous/page"}

navigate.forward

Go forward in navigation history

Params: {}
Result: {"page": "next/page"}

navigate.home

Params: {}
Result: {"page": ""}

navigate.refresh

Refresh current page from data source

Params: {}
Result: {"page": "current/page"}

Page Methods

page.get_current

Get current page key and URL

Params: {}
Result: {"key": "current/page", "url": "http://base/url/current/page"}

page.get_document_json

Get current page JSONHTL document

Params: {}
Result: {"document": {"title": "...", "content": [...]}}

page.put_document_json

Write a JSONHTL document to a page key

Params: {"key": "page/key", "document": {...}}
Result: {"status": "ok", "key": "page/key"}

page.get_rendered_text

Get all rendered text from current page (blocks joined by newlines)

Params: {}
Result: {"text": "rendered page text..."}

View Methods

view.get_zoom

Get current zoom percentage

Params: {}
Result: {"zoom_percent": 100}

view.zoom_in

Increase zoom by 10%

Params: {}
Result: {"zoom_percent": 110}
Params: {}
Result: {"zoom_percent": 100}

view.zoom_set

Set zoom to specific percentage

Params: {"zoom_percent": 150}
Result: {"zoom_percent": 150}

view.scroll_pages

Scroll by number of pages (positive=down, negative=up)

Params: {"pages": 1}
Result: {"scrolled": true, "pages": 1}

Selection Methods

selection.get

Get current selection range and mode

Params: {}
Result: {"selection": {"block_start": 0, "offset_start": 0, "block_end": 0, "offset_end": 5}, "selection_mode": "logical-only"}

selection.set_by_block_offsets

Set selection by block indices and offsets

Params: {"block_index_start": 0, "offset_start": 0, "block_index_end": 0, "offset_end": 5}
Result: {"selection": {...}, "native_selected": true, "selection_mode": "native-word"}

selection.native_select_word_by_text

Select first occurrence of a word using native word-selection

Params: {"text": "word", "occurrence": 1}
Result: {"selected_text": "word", "selection_mode": "native-word"}

selection.native_select_line_by_text

Select a line containing text using native line-selection

Params: {"text": "partial text", "occurrence": 1}
Result: {"selected_text": "full line containing partial text...", "selection_mode": "native-line"}

selection.read_text

Read text from current selection

Params: {}
Result: {"text": "selected text...", "selection_mode": "logical-only"}

selection.write_text

Replace selected text and persist document

Params: {"text": "replacement text"}
Result: {"selection": {...}, "text": "replacement text", "selection_mode": "logical-only"}

selection.set_and_capture

Set selection and capture screenshot with highlighted region

Params: {"block_index_start": 0, "offset_start": 0, "block_index_end": 0, "offset_end": 5, "path": "/path/to/output.png"}
Result: {"selection": {...}, "text": "...", "path": "/path/to/output.png"}

Link Methods

links.get_current

Get current page link information

Params: {}
Result: {"key": "current/page", "url": "http://base/url/current/page"}

UI Methods

ui.capture_screenshot

Capture current window as PNG

Params: {"path": "optional/output/path.png"}
Result: {"path": "/absolute/path/to/screenshot.png"}

ui.capture_sixel

Capture window as SIXEL terminal graphics format

Params: {"path": "optional/output.txt", "include_data": true}
Result: {"format": "sixel-body", "width": 1024, "height": 768, "colors": 216, "sixel": "...", "path": "..."}

ui.set_window_size

Resize browser window

Params: {"width": 1024, "height": 768}
Result: {"width": 1024, "height": 768}

ui.quit

Close browser window and exit

Params: {}
Result: {"status": "quitting"}

Error Handling

JSON-RPC 2.0 errors follow standard format:

Example: TCP Control Session

import socket
import json

def send_rpc(method, params=None):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect(('127.0.0.1', 8711))
        cmd = {
            'jsonrpc': '2.0',
            'id': 1,
            'method': method,
            'params': params or {}
        }
        sock.sendall((json.dumps(cmd) + '\n').encode('utf-8'))
        response = sock.recv(8192).decode('utf-8')
        return json.loads(response)
    finally:
        sock.close()

# Navigate and capture
send_rpc('navigate.go_to_page', {'key': 'setup/notes-browser'})
send_rpc('ui.capture_screenshot', {'path': 'test.png'})
import socket
import json

def send_rpc(method, params=None):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect(('127.0.0.1', 8711))
        cmd = {
            'jsonrpc': '2.0',
            'id': 1,
            'method': method,
            'params': params or {}
        }
        sock.sendall((json.dumps(cmd) + '\n').encode('utf-8'))
        response = sock.recv(8192).decode('utf-8')
        return json.loads(response)
    finally:
        sock.close()

# Navigate and capture
send_rpc('navigate.go_to_page', {'key': 'setup/notes-browser'})
send_rpc('ui.capture_screenshot', {'path': 'test.png'})
send_rpc('ui.quit')

Launch Notes Browser with Control Enabled

# TCP only (default)
python3 notes_browser.py --url http://127.0.0.1:8021 --control-tcp-enabled

# TCP on custom port
python3 notes_browser.py --url http://127.0.0.1:8021 \
  --control-tcp-enabled --control-tcp-port 9000

# TCP + UDP (both enabled)
python3 notes_browser.py --url http://127.0.0.1:8021 \
  --control-tcp-enabled --control-udp-enabled

# From config file
python3 notes_browser.py --config ~/.notes_browser.yaml

Configuration File Format (~/.notes_browser.yaml)

notes_url: http://127.0.0.1:8021
html_base_url: http://127.0.0.1/notes
control_tcp_enabled: true
control_tcp_port: 8711
control_host: 127.0.0.1
control_token: ''
render_font_family: "'Courier New', Courier, monospace"
render_font_size_pt: 10
version 2  ·  created 2026-07-19  ·  kind reference  ·  updated 2026-08-26