documentation/RPC.md · main · 2026-10-13

GitSocial JSON-RPC Protocol

gitsocial rpc serves the library over JSON-RPC 2.0 on stdio, for editors and other clients.

Transport · Lifecycle · Error codes · Methods · Notifications · Types · Notes

1. Transport

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. A line over 1 MB ends the session with no error response.

1.1. Message Format

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}}

1.2. Batching

Clients may send JSON-RPC batch requests (an array of request objects). The server must send a batch response in the same order. An empty array returns a single -32600 error.

2. Lifecycle

2.1. Startup

The client starts gitsocial rpc as a subprocess. The server reads from stdin and writes to stdout, and must not write output before it receives initialize.

2.2. Initialize

The first request must be initialize; only ping, subscribe, unsubscribe and shutdown work before it. The server opens the cache, resolves the workspace, and returns server capabilities. A second initialize returns -32007 CONFLICT, and a missing workdir returns -32602.

Method: initialize

Params:

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": ""}
  }
}

2.3. Shutdown

Method: shutdown

Params: none

Result: "ok"

The server closes the cache and stops the read loop. Clients should send shutdown before they stop the process.

2.4. Ping

Method: ping

Params: none

Result: "pong"

Clients use ping for keepalive and health checks.

3. Error Codes

JSON-RPC 2.0 standard errors:

CodeMeaning
-32700Parse error
-32600Invalid request
-32601Method not found
-32602Invalid params
-32603Internal error

Application errors use the -32000 to -32099 range:

CodeApp CodeMeaning
-32000INTERNALUnexpected server error
-32001NOT_FOUNDItem not found
-32002NOT_A_REPOSITORYWorkdir is not a git repository
-32003NOT_INITIALIZEDExtension not initialized
-32004INVALID_ARGUMENTInvalid parameter value
-32007CONFLICTConcurrent modification conflict
-32010NOT_READYServer not yet initialized

An error built from a library Result[T] carries data.appCode and, when the library set one, data.details:

{"code":-32001,"message":"post not found","data":{"appCode":"NOT_FOUND"}}

data.details holds an error as its text, and a struct or a map as its JSON object.

The table above is not exhaustive. appCode is the code string from the library, without change, so a -32000 response can carry INVALID_SCOPE, LIST_NOT_FOUND, GIT_ERROR, NO_SBOM, NO_VERSION, SBOM_FAILED or READ_FAILED. Parameter validation (-32602) and the search methods return no data at all.

4. Methods

Methods are namespaced as namespace.method. All methods use the workdir from initialize, and no method accepts a workdir param.

4.1. Social

social.getPosts

Returns posts for a given scope.

Params:

Posts come back newest first. A param this list does not name is ignored. The timeline and list:<id> scopes also return action entries: a post with Action set. For a state change, EditOf is the item; a review is its own item.

Result: Post[]

social.createPost

Params:

Result: Post

social.editPost

Params:

Result: Post

social.retractPost

Params:

Result: true

social.createComment

Params:

Result: Post

social.createRepost

Params:

Result: Post

social.createQuote

Params:

Result: Post

social.getLists

Params: none

Result: List[]

social.getList

Params:

Result: List

social.createList

Params:

Result: List

social.deleteList

Params:

Result: {}

social.addToList

Params:

Result: string (the added repository URL)

social.removeFromList

Params:

Result: {}

social.getRepositories

Params:

Result: Repository[]

social.getLogs

Params:

Result: LogEntry[]

4.2. PM

pm.getIssues

Params:

Result: Issue[]

pm.getIssue

Params:

Result: Issue

pm.createIssue

Params:

Result: Issue

pm.updateIssue

Params:

Result: Issue

pm.closeIssue

Params:

Result: Issue

pm.reopenIssue

Params:

Result: Issue

pm.adoptIssue

Params:

Result: Issue, the workspace copy; an issue adopted before returns its copy

pm.retractIssue

Params:

Result: true

pm.getMilestones

Params:

Result: Milestone[]

pm.getMilestone

Params:

Result: Milestone

pm.createMilestone

Params:

Result: Milestone

pm.updateMilestone

Params:

Result: Milestone

pm.closeMilestone / pm.reopenMilestone / pm.cancelMilestone

Params:

Result: Milestone

pm.retractMilestone

Params:

Result: true

pm.getMilestoneIssues

Params:

Result: Issue[]

pm.getSprints

Params:

Result: Sprint[]

pm.getSprint

Params:

Result: Sprint

pm.createSprint

Params:

Result: Sprint

pm.updateSprint

Params:

Result: Sprint

pm.activateSprint / pm.completeSprint / pm.cancelSprint

Params:

Result: Sprint

pm.retractSprint

Params:

Result: true

pm.getSprintIssues

Params:

Result: Issue[]

pm.getBoardView

Params:

Result: BoardView

{
  "id": "default",
  "name": "Default Board",
  "columns": [
    {"name": "open", "label": "Open", "wip": null, "issues": [...]},
    {"name": "closed", "label": "Done", "wip": null, "issues": [...]}
  ]
}

pm.commentOnItem

Params:

Result: Post (social comment)

pm.getItemComments

Params:

Result: Post[]

Returns the link graph around an item: what it blocks, what blocks it, and what it relates to.

Params:

Result: {"blocks": Issue[], "blockedBy": Issue[], "related": Issue[]}

pm.isBlocked

Params:

Result: bool

4.3. Review

review.getPullRequests

Params:

Result: PullRequest[]

review.getPR

Params:

Result: PullRequest

review.createPR

Params:

Result: PullRequest

review.updatePR

Params:

Result: PullRequest

review.mergePR

Params:

Merges fast-forward. The other strategies the CLI offers are not reachable over RPC.

Result: PullRequest

review.markReady

Takes a draft pull request out of draft state.

Params:

Result: PullRequest

review.convertToDraft

Puts an open pull request back into draft state.

Params:

Result: PullRequest

review.closePR

Params:

Result: PullRequest

review.adoptPR

Params:

Result: PullRequest, the workspace copy; a pull request adopted before returns its copy

review.retractPR

Params:

Result: true

review.getFeedbackForPR

Params:

Result: Feedback[]

review.createFeedback

Params:

Result: Feedback

review.updateFeedback

Params:

Result: Feedback

review.retractFeedback

Params:

Result: true

review.applySuggestion

Params:

Result: string (applied file path)

review.getDiff

Returns the diff between the base and the head of a pull request.

Params:

Result: FileDiff[]

[{
  "OldPath": "a/theme.go",
  "NewPath": "b/theme.go",
  "Status": 1,
  "Binary": false,
  "Hunks": [{
    "OldStart": 10, "OldCount": 5,
    "NewStart": 10, "NewCount": 8,
    "Header": "@@ -10,5 +10,8 @@",
    "Lines": [
      {"Type": 0, "Content": "func init() {", "OldNum": 10, "NewNum": 10},
      {"Type": 2, "Content": "\told := theme()", "OldNum": 11, "NewNum": 0},
      {"Type": 1, "Content": "\tnewTheme := darkTheme()", "OldNum": 0, "NewNum": 11}
    ]
  }]
}]

Type is an integer: 0 context, 1 added, 2 removed.

review.getDiffStats

Params:

Result: DiffStats

{"Files": 5, "Added": 120, "Removed": 45}

review.getFileDiff

Params:

Result: FileDiff

review.getFileContent

Returns file content at a specific ref.

Params:

Result: string (file contents)

review.getPRComments

Params:

Result: Post[]

review.getForks

Returns the registered fork URLs. Each fork is at a ref under refs/gitmsg/core/forks/, and all extensions share the list.

Params: none

Result: string[] (fork URLs)

review.addFork

Registers a fork URL at a ref under refs/gitmsg/core/forks/.

Params:

Result: true

review.removeFork

Removes the ref of a registered fork URL. A URL that is not registered returns NOT_FOUND.

Params:

Result: true

review.updatePRTips

Records the base and head tips of the pull request again, from the current branches.

Params:

Result: PullRequest

review.syncPRBranch

Rebases or merges the head branch onto the base, then records the tips again.

Params:

Result: PullRequest

review.getPRVersions

Lists all versions of the pull request, oldest first.

Params:

Result: PRVersion[]

review.comparePRVersions

Returns the range-diff of two versions of the pull request.

Params:

Result: string (the range-diff)

review.getVersionAwareReviews

Returns the latest review of each reviewer, with the pull request version that it reviewed and the current version.

Params:

Result: VersionAwareReview[]

4.4. Release

release.getReleases

Params:

Result: Release[]

release.getRelease

Params:

Result: Release

release.createRelease

Params:

Result: Release

release.editRelease

Params:

Result: Release

release.retractRelease

Params:

Result: true

release.getReleaseComments

Params:

Result: Post[]

release.getSBOM

Returns the parsed SBOM summary of a release: format, package count, licenses and generator.

Params:

Result: SBOMSummary

release.getSBOMRaw

Returns the raw SBOM file content as a JSON string.

Params:

Result: string (raw SBOM JSON content)

4.5. Core

core.fetch

Fetches updates from the followed repositories and returns a fetch ID immediately. Server notifications report the progress and the completion.

Params:

Result:

{"fetchId": "f-1"}

The server sends fetch.progress and fetch.complete notifications for this fetchId (see Section 5).

core.push

Pushes local changes to every default push remote, the list gitsocial push resolves.

Params:

Result: for one remote, the object below; for more than one remote, an array of these objects in push order.

{
  "push": {"...": "per-branch push counts"},
  "site": {"published": true, "complete": true, "forkPullRequests": {"count": 2, "bytes": 1363149}},
  "emptyBoot": false
}

site.forkPullRequests is present when the forkPullRequests site key is on (STATIC-SITE.md).

core.status

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"},
    "review": {"initialized": false},
    "release": {"initialized": false}
  }
}

branch and unpushed are omitted when empty or zero. unpushed counts posts and lists on the extension's branch.

core.getConfig

Reads extension configuration.

Params:

Result: object (extension-specific config JSON)

core.setConfig

Writes extension configuration.

Params:

Result: true

core.initExtension

Initializes an extension in the workspace.

Params:

Result: true

core.getNotifications

Params:

Result: Notification[]

core.getUnreadCount

Params: none

Result: int

core.markAsRead

Params:

Result: true

core.markAllAsRead

Params: none

Result: true

core.getHistory

Returns the edit history of an item, for example a post, an issue, a pull request or a release.

Params:

Result: MessageVersion[]

[
  {"ID": "#commit:abc123456789@gitmsg/social", "CommitHash": "abc123456789",
   "Timestamp": "2025-01-06T10:00:00Z", "AuthorName": "Alice", "AuthorEmail": "[email protected]",
   "Extension": "social", "Type": "post", "Content": "v1", "EditOf": "", "IsRetracted": false}
]

core.getSettings

Params: none

Result: KeyValue[]

[
  {"key": "fetch.parallel", "value": "4", "description": "Concurrent fetch workers."},
  {"key": "log.level", "value": "info", "description": "Logging verbosity."}
]

description is the description of the key in the registry; the server omits it for a key that is not in the registry.

core.setSetting

Params:

Result: true

Searches all extensions: posts, issues, pull requests, releases and feedback.

Params:

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
}

5. Server Notifications

The server sends notifications (with no id field) to the client. A client opts in with subscribe, which works before initialize.

5.1. Subscribe

Method: subscribe

Params:

Result: true

5.2. Unsubscribe

Method: unsubscribe

Params:

Result: true

5.3. Fetch Events

fetch.progress

{"jsonrpc":"2.0","method":"fetch.progress","params":{
  "fetchId": "f-1",
  "repoURL": "https://github.com/user/repo",
  "processed": 3,
  "total": 10
}}

fetch.complete

{"jsonrpc":"2.0","method":"fetch.complete","params":{
  "fetchId": "f-1",
  "repositories": 10,
  "newCommits": 42,
  "errors": 0
}}

fetch.error

Sent once when the fetch as a whole fails, not per repository.

{"jsonrpc":"2.0","method":"fetch.error","params":{
  "fetchId": "f-1",
  "message": "network timeout"
}}

5.4. Notification Events

notifications.changed

Sent at the end of core.fetch. Mark-as-read and local commits send nothing; a client that changes the read state updates its own count.

{"jsonrpc":"2.0","method":"notifications.changed","params":{
  "unreadCount": 5
}}

5.5. Workspace Events

workspace.changed

Reserved. subscribe accepts "workspace", but the server has no emitter for this notification and sends none. A client should expect the payload shape below when an emitter exists.

{"jsonrpc":"2.0","method":"workspace.changed","params":{
  "branches": ["gitmsg/social", "gitmsg/pm"]
}}

6. Type Reference

The methods return the types below. Most are Go structs with no JSON tags, so their field names serialize as written in Go, with a capital first letter. Zero values are not omitted: an unset pointer is null, an unset time is "0001-01-01T00:00:00Z", an unset slice is null. The five tagged types, marked below, serialize under their tag names.

Times are RFC 3339 strings. Refs are strings in #commit:hash@branch or url#commit:hash@branch form. A library Result[T] maps to result or error.

Author, Actor

{"Name": "string", "Email": "string"}. pm.Label is {"Scope": "string", "Value": "string"}. IssueRef and review's Ref are {"RepoURL": "string", "Hash": "string", "Branch": "string"}.

Post

FieldTypeNote
IDstringref
Repository, Branchstring
AuthorAuthor
TimestampstringRFC 3339
Content, CleanContentstringraw message, and the message with the GitMsg header removed
Typestringpost, comment, repost, quote
Sourcestringwhere the post was read from
OriginalPostID, ParentCommentIDstringrefs, empty when absent
EditOf, EditorName, EditorEmailstringthe edit chain
EditRepoURL, EditHash, EditBranchstringthe latest edit commit
IsRetracted, IsEdited, HasProposedEditsbool
Depthintthread nesting
Interactionsobject{"Comments": 0, "Reposts": 0, "Quotes": 0}
Remotestring
IsVirtual, IsStale, IsWorkspacePostbool
Displayobjectrender hints: RepositoryName, CommitURL, IsVerified, Badge and siblings
OriginalExtension, OriginalTypestringthe referenced item's extension and type
HeaderExt, HeaderType, HeaderStatestringraw GitMsg header fields
Actionstringthe timeline action of the commit; empty for a content entry
ActionSubjectstringthe subject of the item that the action is on
Closesstring[]the issue refs that a merged action closes
Labelsstring[]
Originobjectimport provenance, null when the post is native
Rawobject{"Commit": {...}, "GitMsg": {...}}, the parsed commit and message

Issue

FieldTypeNote
ID, Repository, Branchstring
AuthorAuthor
TimestampstringRFC 3339
Subject, Bodystring
Statestringopen, closed, canceled
Assigneesstring[]emails
DuestringRFC 3339, null when unset
Milestone, Sprint, Parent, RootIssueRefnull when unset
Blocks, BlockedBy, RelatedIssueRef[]
LabelsLabel[]
IsEdited, HasProposedEdits, IsRetracted, IsUnpushedbool
Commentsint
Originobjectnull when native
Adoptsstringthe fork issue this copy adopts, empty when native
OriginalAuthorAuthorthe adopted issue's author, null when native
OriginalTimestringRFC 3339, the adopted issue's time

Milestone

ID, Repository, Branch, Author, Timestamp, Title, Body, State, Due, Labels (string[]), IsEdited, HasProposedEdits, IsRetracted, IsUnpushed, IssueCount, ClosedCount, Origin.

Sprint

The Milestone fields, with Start and End (RFC 3339) in place of Due, and State one of planned, active, completed, canceled.

PullRequest

FieldTypeNote
ID, Repository, Branchstring
AuthorAuthor
TimestampstringRFC 3339
Subject, Bodystring
Statestringopen, merged, closed
IsDraftbool
Base, BaseTip, Head, HeadTipstringrefs and the tips recorded at the latest version
DependsOn, Closes, Reviewers, Labelsstring[]
IsEdited, HasProposedEdits, IsRetracted, IsUnpushedbool
Commentsint
ReviewSummaryobject{"Approved": 0, "ChangesRequested": 0, "Pending": 0, "IsBlocked": false, "IsApproved": false}
MergeBase, MergeHeadstringrecorded before the merge
MergedBy, ClosedBy, OriginalAuthorAuthornull when unset
MergedAt, ClosedAt, OriginalTimestringRFC 3339; the zero time when unset
Originobjectnull when native
Adoptsstringthe fork pull request this copy adopts, empty when native

Feedback

ID, Repository, Branch, Author, Timestamp, Content, PullRequest (Ref), Commit, File, OldLine, NewLine, OldLineEnd, NewLineEnd, ReviewState (comment, approved, changes-requested), Suggestion, IsEdited, IsRetracted, Comments.

PRVersion

Tagged type.

{
  "number": 0,
  "label": "string",
  "commit_hash": "string",
  "repo_url": "string (URL)",
  "branch": "string",
  "author_name": "string",
  "author_email": "string",
  "timestamp": "string (RFC 3339)",
  "subject": "string (optional)",
  "body": "string (optional)",
  "base_tip": "string (optional)",
  "head_tip": "string (optional)",
  "state": "open | merged | closed",
  "is_retracted": false
}

VersionAwareReview

Tagged type.

{
  "reviewer_name": "string",
  "reviewer_email": "string",
  "state": "approved | changes-requested",
  "reviewed_at": "string (RFC 3339)",
  "reviewed_version": 0,
  "reviewed_label": "string",
  "current_version": 0,
  "current_label": "string",
  "head_changed": false,
  "code_changed": false,
  "stale": false
}

Release

ID, Repository, Branch, Author, Timestamp, Subject, Body, Version, Tag, Prerelease, Artifacts (string[]), ArtifactURL, Checksums, SignedBy, SBOM, Labels (string[]), IsEdited, HasProposedEdits, IsRetracted, IsUnpushed, Comments, Origin.

SBOMSummary

Tagged type. Every field is always present.

{
  "format": "spdx | cyclonedx | syft",
  "packages": 127,
  "generator": "string, e.g. syft-1.0.0",
  "licenses": {"MIT": 42, "Apache-2.0": 15},
  "generated": "string (the SBOM's own creation time)",
  "items": [
    {"name": "string", "version": "string", "license": "string"}
  ]
}

Notification

RepoURL, Hash, Branch, Type (NOTIFICATIONS.md), Source (social, pm, review, release, memo, core), Item (the extension's own notification object), Actor, ActorRepo, Timestamp, IsRead.

MessageVersion

ID, CommitHash, Branch, RepoURL, AuthorName, AuthorEmail, Timestamp, Extension, Type, Content, EditOf, IsRetracted, Labels (string[]), Fields (the parsed GitMsg header, key to value).

FileDiff, Hunk, DiffLine, DiffStats

TypeFields
FileDiffOldPath, NewPath, Status (int), Hunks, Binary
HunkOldStart, OldCount, NewStart, NewCount, Header, Lines
DiffLineType (int: 0 context, 1 added, 2 removed), Content, OldNum, NewNum
DiffStatsFiles, Added, Removed

search.Result

Tagged type. The search method shows the shape.

7. Implementation Notes