JSON-RPC 2.0 interface for editor and client integration. Launched via gitsocial rpc.
Communication uses JSON-RPC 2.0 over stdio (stdin/stdout). Each message is a single line of JSON terminated by \n. Stderr is reserved for logging.
Client (editor) gitsocial rpc
│ │
│ ── request (stdin) ──────────────► │
│ │
│ ◄── response (stdout) ─────────── │
│ │
│ ◄── notification (stdout) ──────── │ (server-initiated, no id)
Requests and responses follow JSON-RPC 2.0. All messages MUST be valid JSON on a single line.
Request:
{"jsonrpc":"2.0","id":1,"method":"social.getPosts","params":{"scope":"timeline","limit":50}}
Success response:
{"jsonrpc":"2.0","id":1,"result":[...]}
Error response:
{"jsonrpc":"2.0","id":1,"error":{"code":-32001,"message":"not found","data":{"appCode":"NOT_FOUND"}}}
Server notification (no id):
{"jsonrpc":"2.0","method":"notifications.changed","params":{"unreadCount":3}}
Clients MAY send JSON-RPC batch requests (array of request objects). The server MUST respond with a batch response in the same order.
The client spawns gitsocial rpc as a subprocess. The server reads from stdin and writes to stdout. The server MUST NOT produce output before receiving initialize.
The first request MUST be initialize. The server opens the cache, resolves the workspace, and returns server capabilities.
Method: initialize
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| workdir | string | yes | Absolute path to the git repository working directory |
| cacheDir | string | no | Cache directory (default: ~/.cache/gitsocial) |
| clientName | string | no | Client identifier (e.g., "vscode", "neovim") |
| clientVersion | string | no | Client version |
Result:
{
"version": "0.1.0",
"repoURL": "https://github.com/user/repo",
"extensions": {
"social": {"initialized": true, "branch": "gitmsg/social"},
"pm": {"initialized": true, "branch": "gitmsg/pm"},
"review": {"initialized": false, "branch": ""},
"release": {"initialized": false, "branch": ""}
}
}
Method: shutdown
Params: none
The server closes the cache, flushes pending writes, and exits with code 0. Clients SHOULD send shutdown before killing the process.
Method: ping
Params: none
Result: "pong"
For keepalive and health checks.
JSON-RPC 2.0 standard errors:
| Code | Meaning |
|---|---|
-32700 | Parse error |
-32600 | Invalid request |
-32601 | Method not found |
-32602 | Invalid params |
-32603 | Internal error |
Application errors use the -32000 to -32099 range:
| Code | App Code | Meaning |
|---|---|---|
-32000 | INTERNAL | Unexpected server error |
-32001 | NOT_FOUND | Item not found |
-32002 | NOT_A_REPOSITORY | Workdir is not a git repository |
-32003 | NOT_INITIALIZED | Extension not initialized |
-32004 | INVALID_ARGUMENT | Invalid parameter value |
-32005 | PERMISSION_DENIED | Operation not permitted |
-32006 | NETWORK_ERROR | Network operation failed |
-32007 | CONFLICT | Concurrent modification conflict |
-32010 | NOT_READY | Server not yet initialized |
Error responses include the application code in data.appCode for programmatic handling:
{"code":-32001,"message":"post not found","data":{"appCode":"NOT_FOUND"}}
Methods are namespaced as namespace.method. The workdir set during initialize is implicit — individual methods do not accept it.
Returns posts for a given scope.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| scope | string | yes | "timeline", "workspace", "mine", "repo:<url>", "list:<id>", "post:<ref>", "thread:<ref>" |
| limit | int | no | Max posts to return (0 = all) |
| types | string[] | no | Filter by type: "post", "comment", "repost", "quote" |
| since | string | no | ISO 8601 timestamp lower bound |
| until | string | no | ISO 8601 timestamp upper bound |
| sort | string | no | Sort order: "newest" (default), "oldest" |
Result: Post[]
[{
"id": "#commit:abc123456789@gitmsg/social",
"repository": "https://github.com/user/repo",
"branch": "gitmsg/social",
"author": {"name": "Alice", "email": "[email protected]"},
"timestamp": "2025-01-06T10:00:00Z",
"content": "Hello world",
"type": "post",
"interactions": {"comments": 2, "reposts": 1, "quotes": 0},
"isEdited": false,
"isRetracted": false
}]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| content | string | yes | Post body |
Result: Post
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Post ref to edit |
| content | string | yes | New content |
Result: Post
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Post ref to retract |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| target | string | yes | Ref of post to comment on |
| content | string | yes | Comment body |
Result: Post
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| target | string | yes | Ref of post to repost |
Result: Post
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| target | string | yes | Ref of post to quote |
| content | string | yes | Quote body |
Result: Post
Params: none
Result: List[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| id | string | yes | List ID |
Result: List
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| id | string | yes | List ID (slug) |
| name | string | yes | Display name |
Result: List
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| id | string | yes | List ID |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| listId | string | yes | List ID |
| repoURL | string | yes | Repository URL to add |
| branch | string | no | Branch (uses default if omitted) |
| allBranches | boolean | no | Follow all branches (stores branch:*). Mutually exclusive with branch. |
Result: string (added repo URL)
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| listId | string | yes | List ID |
| repoURL | string | yes | Repository URL to remove |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| scope | string | no | "all" (default), "list:<id>" |
Result: Repository[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| scope | string | no | Scope filter |
| limit | int | no | Max entries |
| types | string[] | no | Filter by log entry type |
| author | string | no | Filter by author |
| after | string | no | ISO 8601 lower bound |
| before | string | no | ISO 8601 upper bound |
Result: LogEntry[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| repoURL | string | no | Repository URL (default: workspace) |
| branch | string | no | Branch |
| states | string[] | no | Filter: "open", "closed", "canceled" |
| limit | int | no | Max results |
Result: Issue[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Issue ref |
Result: Issue
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| subject | string | yes | Issue title |
| body | string | no | Issue description |
| state | string | no | Initial state (default: "open") |
| assignees | string[] | no | Assignee emails |
| due | string | no | ISO 8601 due date |
| milestone | string | no | Milestone ref |
| sprint | string | no | Sprint ref |
| parent | string | no | Parent issue ref. root is derived from it per GITPM.md §1.7, so a client normally sends this alone. |
| root | string | no | Top-level ancestor ref. Only send this to override the derivation; sending parent alone is the usual case. |
| labels | Label[] | no | [{"scope":"priority","value":"high"}] |
Result: Issue
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Issue ref |
| subject | string | no | New title |
| body | string | no | New description |
| state | string | no | New state |
| assignees | string[] | no | New assignees |
| due | string | no | New due date |
| milestone | string | no | New milestone ref |
| sprint | string | no | New sprint ref |
| parent | string | no | New parent ref. Sending it without root re-derives the root; sending "" clears both. |
| root | string | no | Top-level ancestor ref. Only send this to override the derivation. |
| labels | Label[] | no | New labels |
Result: Issue
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Issue ref |
Result: Issue
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Issue ref |
Result: Issue
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Issue ref |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| repoURL | string | no | Repository URL (default: workspace) |
| branch | string | no | Branch |
| states | string[] | no | Filter by state |
| limit | int | no | Max results |
Result: Milestone[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Milestone ref |
Result: Milestone
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| title | string | yes | Milestone title |
| body | string | no | Description |
| state | string | no | Initial state |
| due | string | no | ISO 8601 due date |
Result: Milestone
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Milestone ref |
| title | string | no | New title |
| body | string | no | New description |
| state | string | no | New state |
| due | string | no | New due date |
Result: Milestone
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Milestone ref |
Result: Milestone
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Milestone ref |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Milestone ref |
| states | string[] | no | Filter by state |
Result: Issue[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| repoURL | string | no | Repository URL (default: workspace) |
| branch | string | no | Branch |
| states | string[] | no | Filter: "planned", "active", "completed", "canceled" |
| limit | int | no | Max results |
Result: Sprint[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Sprint ref |
Result: Sprint
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| title | string | yes | Sprint title |
| body | string | no | Description |
| state | string | no | Initial state (default: "planned") |
| start | string | no | ISO 8601 start date |
| end | string | no | ISO 8601 end date |
Result: Sprint
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Sprint ref |
| title | string | no | New title |
| body | string | no | New description |
| state | string | no | New state |
| start | string | no | New start date |
| end | string | no | New end date |
Result: Sprint
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Sprint ref |
Result: Sprint
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Sprint ref |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Sprint ref |
| states | string[] | no | Filter by state |
Result: Issue[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| boardId | string | no | Board ID (default: first configured board) |
Result: BoardView
{
"id": "default",
"name": "Default Board",
"columns": [
{"name": "open", "label": "Open", "wip": null, "issues": [...]},
{"name": "closed", "label": "Done", "wip": null, "issues": [...]}
]
}
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Item ref (issue, milestone, or sprint) |
| content | string | yes | Comment body |
Result: Post (social comment)
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Item ref |
Result: Post[]
Returns the link graph around an item: what it blocks, what blocks it, and what it relates to.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Item ref |
Result: {"blocks": Issue[], "blockedBy": Issue[], "related": Issue[]}
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Item ref |
Result: bool
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| repoURL | string | no | Repository URL (default: workspace) |
| branch | string | no | Branch |
| states | string[] | no | Filter: "open", "merged", "closed" |
| includeForks | bool | no | Include PRs from registered forks |
| limit | int | no | Max results |
Result: PullRequest[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: PullRequest
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| subject | string | yes | PR title |
| body | string | no | PR description |
| base | string | yes | Base branch ref |
| head | string | yes | Head branch ref |
| closes | string[] | no | Issue refs to close on merge |
| reviewers | string[] | no | Reviewer emails |
Result: PullRequest
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
| subject | string | no | New title |
| body | string | no | New description |
| state | string | no | New state |
| base | string | no | New base |
| head | string | no | New head |
| closes | string[] | no | New close refs |
| reviewers | string[] | no | New reviewers |
Result: PullRequest
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
| strategy | string | no | Merge strategy: ff (default), squash, rebase, merge |
Result: PullRequest
Takes a draft PR out of draft state.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: PullRequest
Puts an open PR back into draft state.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: PullRequest
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: PullRequest
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: Feedback[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| content | string | yes | Feedback body |
| pullRequest | string | yes | PR ref |
| commit | string | no | Commit hash (12 chars) |
| file | string | no | File path |
| oldLine | int | no | Line in old file |
| newLine | int | no | Line in new file |
| oldLineEnd | int | no | End line in old file |
| newLineEnd | int | no | End line in new file |
| reviewState | string | no | "approved" or "changes-requested" |
| suggestion | bool | no | Body contains suggestion block |
Result: Feedback
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Feedback ref |
| content | string | no | New content |
| reviewState | string | no | New review state |
Result: Feedback
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Feedback ref |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Feedback ref containing suggestion |
Result: string (applied file path)
Returns the diff between a PR's base and head.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: FileDiff[]
[{
"oldFile": "a/theme.go",
"newFile": "b/theme.go",
"hunks": [{
"oldStart": 10, "oldCount": 5,
"newStart": 10, "newCount": 8,
"lines": [
{"type": "context", "content": "func init() {", "oldLine": 10, "newLine": 10},
{"type": "delete", "content": "\told := theme()", "oldLine": 11},
{"type": "add", "content": "\tnewTheme := darkTheme()", "newLine": 11}
]
}]
}]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: DiffStats
{"filesChanged": 5, "insertions": 120, "deletions": 45}
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
| file | string | yes | File path |
Result: FileDiff
Returns file content at a specific ref.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
| file | string | yes | File path |
| side | string | yes | "base" or "head" |
Result: string (file contents)
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: Post[]
Returns registered fork URLs (stored in core config, shared across all extensions).
Params: none
Result: string[] (fork URLs)
Registers a fork URL in the core config (shared across all extensions).
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| url | string | yes | Fork repository URL |
Result: true
Removes a fork URL from the core config.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| url | string | yes | Fork repository URL |
Result: true
Re-snapshots the PR's base and head tips from the live branches.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: PullRequest
Brings the head branch up to date with the base, then re-snapshots the tips.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
| strategy | string | no | rebase (default) or merge |
Result: PullRequest
Lists every version of the PR, oldest first.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: PRVersion[]
Range-diffs two versions of the PR.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
| from | int | yes | Version number to compare from |
| to | int | yes | Version number to compare to |
Result: string (the range-diff)
Each reviewer's latest review tagged with the version it was left against, so a client can tell a stale approval from a current one.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | PR ref |
Result: VersionAwareReview[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| repoURL | string | no | Repository URL (default: workspace) |
| branch | string | no | Branch |
| limit | int | no | Max results |
Result: Release[]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Release ref |
Result: Release
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| subject | string | yes | Release title |
| body | string | no | Release notes |
| tag | string | no | Git tag |
| version | string | no | Version string |
| prerelease | bool | no | Pre-release flag |
| artifacts | string[] | no | Artifact names |
| artifactURL | string | no | Download URL |
| checksums | string | no | Checksum data |
| signedBy | string | no | GPG signer |
| sbom | string | no | SBOM filename (e.g., sbom.spdx.json) |
Result: Release
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Release ref |
| subject | string | no | New title |
| body | string | no | New notes |
| tag | string | no | New tag |
| version | string | no | New version |
| prerelease | bool | no | New pre-release flag |
| artifacts | string[] | no | New artifacts |
| artifactURL | string | no | New download URL |
| checksums | string | no | New checksums |
| signedBy | string | no | New signer |
| sbom | string | no | New SBOM filename |
Result: Release
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Release ref |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Release ref |
Result: Post[]
Returns parsed SBOM summary for a release (format, package count, licenses, generator).
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Release ref |
Result: SBOMSummary
Returns the raw SBOM file content as a JSON string.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Release ref |
Result: string (raw SBOM JSON content)
Fetches updates from all subscribed repositories. Returns immediately with a fetch ID. Progress and completion are reported via server notifications.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| listId | string | no | Fetch only repositories in this list |
Result:
{"fetchId": "f-1"}
The server sends fetch.progress and fetch.complete notifications for this fetchId (see Section 5).
Pushes local changes to the remote.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| extensions | string[] | no | Extensions to push (default: all initialized) |
Result:
{"pushed": ["social", "pm"]}
Returns workspace and extension status.
Params: none
Result:
{
"workdir": "/path/to/repo",
"repoURL": "https://github.com/user/repo",
"extensions": {
"social": {"initialized": true, "branch": "gitmsg/social", "unpushed": 3},
"pm": {"initialized": true, "branch": "gitmsg/pm", "unpushed": 0},
"review": {"initialized": false},
"release": {"initialized": false}
}
}
Reads extension configuration.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| extension | string | yes | Extension name |
Result: object (extension-specific config JSON)
Writes extension configuration.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| extension | string | yes | Extension name |
| config | object | yes | Config object to write |
Result: true
Initializes an extension in the workspace.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| extension | string | yes | Extension name |
| branch | string | no | Custom branch name |
Result: true
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| unreadOnly | bool | no | Only unread (default: false) |
| types | string[] | no | Filter by type |
| limit | int | no | Max results |
Result: Notification[]
[{
"repoURL": "https://github.com/user/repo",
"hash": "abc123456789",
"branch": "gitmsg/social",
"type": "comment",
"source": "social",
"actor": {"name": "Bob", "email": "[email protected]"},
"timestamp": "2025-01-06T10:00:00Z",
"isRead": false
}]
Params: none
Result: int
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| repoURL | string | yes | Notification repo URL |
| hash | string | yes | Notification hash |
| branch | string | yes | Notification branch |
Result: true
Params: none
Result: true
Returns edit history for any item (post, issue, PR, release, etc.).
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| ref | string | yes | Item ref |
Result: MessageVersion[]
[
{"hash": "abc123456789", "timestamp": "2025-01-06T10:00:00Z", "author": {...}, "content": "v1"},
{"hash": "def234567890", "timestamp": "2025-01-06T11:00:00Z", "author": {...}, "content": "v2 (edited)"}
]
Params: none
Result: KeyValue[]
[
{"key": "fetch.parallel", "value": "4"},
{"key": "log.level", "value": "info"}
]
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| key | string | yes | Setting key |
| value | string | yes | Setting value |
Result: true
Cross-extension search (posts, issues, PRs, releases, feedback). search is the
real name: it spans every extension, so filing it under social. would
misdescribe it. social.search is registered as an alias for clients written
against the name this document used to give, and dispatches to the same handler.
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| query | string | no | Free-text query |
| author | string | no | Filter by author email |
| repo | string | no | Filter by repository URL |
| type | string | no | Filter by type: post, comment, repost, quote, issue, milestone, sprint, pr, feedback, release |
| hash | string | no | Filter by commit-hash prefix |
| after | string | no | ISO 8601 timestamp lower bound |
| before | string | no | ISO 8601 timestamp upper bound |
| limit | int | no | Max results (default: 20) |
| scope | string | no | timeline (default), list:<id>, repository:<url>, repos:<csv> |
| sort | string | no | score (default) or date |
Result: SearchResult
{
"query": "dark mode",
"results": [{"repo_url": "https://github.com/user/repo", "hash": "abc123456789", "branch": "gitmsg/social", "content": "dark mode toggle", "type": "post", "extension": "social", "score": 8.5}],
"total": 3,
"total_searched": 1240,
"has_more": false,
"execution_time_ms": 12
}
Server-initiated notifications (no id field) pushed to the client. Clients opt in by sending subscribe after initialization.
Method: subscribe
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| events | string[] | yes | Events to subscribe to: "fetch", "notifications", "workspace" |
Result: true
Method: unsubscribe
Params:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| events | string[] | yes | Events to unsubscribe from |
Result: true
{"jsonrpc":"2.0","method":"fetch.progress","params":{
"fetchId": "f-1",
"repository": "https://github.com/user/repo",
"processed": 3,
"total": 10
}}
{"jsonrpc":"2.0","method":"fetch.complete","params":{
"fetchId": "f-1",
"repositories": 10,
"newCommits": 42,
"errors": 0
}}
{"jsonrpc":"2.0","method":"fetch.error","params":{
"fetchId": "f-1",
"repository": "https://github.com/user/repo",
"message": "network timeout"
}}
Sent when the unread notification count changes (after fetch, after new local commits, or after mark-as-read).
{"jsonrpc":"2.0","method":"notifications.changed","params":{
"unreadCount": 5
}}
Sent when the server detects changes to gitmsg branches in the workspace (via filesystem watch on .git/refs/heads/gitmsg/).
{"jsonrpc":"2.0","method":"workspace.changed","params":{
"branches": ["gitmsg/social", "gitmsg/pm"]
}}
Types returned by methods. JSON field names use camelCase. Null/absent fields are omitted.
{
"id": "string (ref)",
"repository": "string (URL)",
"branch": "string",
"author": {"name": "string", "email": "string"},
"timestamp": "string (ISO 8601)",
"content": "string",
"type": "post | comment | repost | quote",
"interactions": {"comments": 0, "reposts": 0, "quotes": 0},
"originalPostId": "string (ref, optional)",
"parentCommentId": "string (ref, optional)",
"isEdited": false,
"isRetracted": false,
"isVirtual": false
}
{
"id": "string (ref)",
"repository": "string (URL)",
"branch": "string",
"author": {"name": "string", "email": "string"},
"timestamp": "string (ISO 8601)",
"subject": "string",
"body": "string",
"state": "open | closed | canceled",
"assignees": ["string (email)"],
"due": "string (ISO 8601, optional)",
"milestone": {"repoURL": "string", "hash": "string", "branch": "string"},
"sprint": {"repoURL": "string", "hash": "string", "branch": "string"},
"labels": [{"scope": "string", "value": "string"}],
"isEdited": false,
"isRetracted": false,
"comments": 0
}
{
"id": "string (ref)",
"repository": "string (URL)",
"branch": "string",
"author": {"name": "string", "email": "string"},
"timestamp": "string (ISO 8601)",
"title": "string",
"body": "string",
"state": "open | closed | canceled",
"due": "string (ISO 8601, optional)",
"isEdited": false,
"isRetracted": false,
"issueCount": 0,
"closedCount": 0
}
{
"id": "string (ref)",
"repository": "string (URL)",
"branch": "string",
"author": {"name": "string", "email": "string"},
"timestamp": "string (ISO 8601)",
"title": "string",
"body": "string",
"state": "planned | active | completed | canceled",
"start": "string (ISO 8601)",
"end": "string (ISO 8601)",
"isEdited": false,
"isRetracted": false,
"issueCount": 0,
"closedCount": 0
}
{
"id": "string (ref)",
"repository": "string (URL)",
"branch": "string",
"author": {"name": "string", "email": "string"},
"timestamp": "string (ISO 8601)",
"subject": "string",
"body": "string",
"state": "open | merged | closed",
"base": "string (branch ref)",
"baseTip": "string (12-char hash, base branch tip at creation/update)",
"head": "string (branch ref)",
"headTip": "string (12-char hash, head branch tip at creation/update)",
"closes": ["string (issue ref)"],
"reviewers": ["string (email)"],
"labels": ["string"],
"isEdited": false,
"isRetracted": false,
"comments": 0,
"reviewSummary": {
"approved": 0,
"changesRequested": 0,
"pending": 0,
"isBlocked": false,
"isApproved": false
},
"mergeBase": "string (12-char hash, merge-base at merge time, optional)",
"mergeHead": "string (12-char hash, head at merge time, optional)",
"mergedBy": {"name": "string", "email": "string"} | null,
"mergedAt": "string (ISO 8601)" | null,
"closedBy": {"name": "string", "email": "string"} | null,
"closedAt": "string (ISO 8601)" | null,
"originalAuthor": {"name": "string", "email": "string"} | null
}
{
"id": "string (ref)",
"repository": "string (URL)",
"branch": "string",
"author": {"name": "string", "email": "string"},
"timestamp": "string (ISO 8601)",
"content": "string",
"pullRequest": {"repoURL": "string", "hash": "string", "branch": "string"},
"commit": "string (optional)",
"file": "string (optional)",
"oldLine": 0,
"newLine": 0,
"reviewState": "approved | changes-requested (optional)",
"suggestion": false,
"isEdited": false,
"isRetracted": false,
"comments": 0
}
{
"number": 0,
"label": "string",
"commit_hash": "string",
"repo_url": "string (URL)",
"branch": "string",
"author_name": "string",
"author_email": "string",
"timestamp": "string (ISO 8601)",
"subject": "string (optional)",
"body": "string (optional)",
"base_tip": "string (optional)",
"head_tip": "string (optional)",
"state": "open | merged | closed",
"is_retracted": false
}
{
"reviewer_name": "string",
"reviewer_email": "string",
"state": "approved | changes-requested",
"reviewed_at": "string (ISO 8601)",
"reviewed_version": 0,
"reviewed_label": "string",
"current_version": 0,
"current_label": "string",
"head_changed": false,
"code_changed": false,
"stale": false
}
{
"id": "string (ref)",
"repository": "string (URL)",
"branch": "string",
"author": {"name": "string", "email": "string"},
"timestamp": "string (ISO 8601)",
"subject": "string",
"body": "string",
"version": "string",
"tag": "string",
"prerelease": false,
"artifacts": ["string"],
"artifactURL": "string (optional)",
"checksums": "string (optional)",
"signedBy": "string (optional)",
"sbom": "string (optional, e.g. sbom.spdx.json)",
"isEdited": false,
"isRetracted": false,
"comments": 0
}
{
"format": "spdx | cyclonedx | syft",
"packages": 127,
"generator": "string (optional, e.g. syft-1.0.0)",
"licenses": {"MIT": 42, "Apache-2.0": 15},
"generated": "string (ISO 8601, optional)",
"items": [
{"name": "string", "version": "string", "license": "string"}
]
}
{
"repoURL": "string",
"hash": "string",
"branch": "string",
"type": "string",
"source": "social | pm | review | core",
"actor": {"name": "string", "email": "string"},
"actorRepo": "string (optional)",
"timestamp": "string (ISO 8601)",
"isRead": false
}
The server MUST handle concurrent requests. Long-running operations (core.fetch) run asynchronously and report progress via notifications. Read operations (getPosts, getIssues, etc.) MUST NOT block on writes.
The cache layer already serializes DB access via ExecLocked/QueryLocked. The RPC server adds no additional locking.
All methods operate on the workspace set during initialize. To switch workspaces, the client shuts down and spawns a new server. Multi-root editors spawn one server per workspace.
time.Time serializes as ISO 8601 stringnil pointers are omitted from JSON (not null)Result[T] maps to JSON-RPC: a successful result (result.Ok) becomes result, a failed one (result.Err) becomes error#commit:hash@branch or url#commit:hash@branch formatMethods are registered per extension. If an extension is not initialized, its methods return -32003 NOT_INITIALIZED. Clients check initialize response to know which extensions are available.
library/rpc/
├── server.go # Stdio read loop, JSON-RPC dispatch
├── handler.go # Method registration, param unmarshaling
├── methods_social.go # social.* method handlers
├── methods_pm.go # pm.* method handlers
├── methods_review.go # review.* method handlers
├── methods_release.go # release.* method handlers
├── methods_core.go # core.* + lifecycle method handlers
├── methods_search.go # top-level search method handler
└── types.go # Request/response param structs, subscription events
Each method handler is a function that unmarshals params, calls the existing extension API, and returns the result. No business logic lives in the RPC layer.