Skip to content

Conversations

Every resource you can read carries a threads/ folder: topics, nested comments, reactions, and a resolved state that collapses a finished thread.

AI-assisted, human-approvednovem uses AI to review and keep our documentation up to date.

Overview

A conversation is a topic (the thread's first message) with comments nested under it. Threads live in the threads/ folder of the resource they discuss, for example /v1/users/:user/vis/plots/:plot/threads for a plot, or /v1/users/:user/code/repos/:repo/threads for a repo. Topics and comments are addressed as @author~slug:

threads
└── @sam~axis-labels             => a topic started by sam
    ├── msg                      => the topic's text
    ├── audience                 => public | private
    ├── status                   => active | archived
    ├── reaction                 => your like / dislike
    ├── resolved                 => whether the thread is resolved
    └── comments
        └── @lee~fixed           => a reply by lee
            ├── msg
            ├── reaction
            └── comments         => replies to the reply

Anyone who can read the resource can read its public threads. A private topic is visible only to its author and the resource's owner.

Note: creating, editing or deleting topics, comments and reactions, and resolving threads, requires a paid subscription (basic and up). Reading is available on all plans. The owner can turn comments off with config/options/comments.

Topics and comments

VerbPathDescription
GETthreadsList the topics you can see
PUTthreads/:slugStart a topic as yourself. The body is plain text, or JSON {"message": "…", "audience": "public"}
GET / DELETEthreads/@author~slugList a topic's leaves, or delete it (its author or the resource's owner)
GET / POSTthreads/@author~slug/msgRead or edit the text (the author)
GET / POST / DELETEthreads/@author~slug/reactionYour reaction: like or dislike
PUTthreads/@author~slug/comments/:slugReply to the topic. Nest further with …/comments/@author~slug/comments/:slug

Messages are capped at 10,000 characters, and replies nest at most eight deep.

Resolving a thread

Resolving marks a thread as done. It hides nothing: the web app collapses a resolved thread to one line saying who resolved it, when, and how many comments it holds, and anyone who can read the thread can expand it again.

VerbPathDescription
GETthreads/@author~slug/resolvedThe thread's resolved state
POSTthreads/@author~slug/resolvedResolve the thread
DELETEthreads/@author~slug/resolvedReopen the thread
curl -X POST -H "Authorization: Bearer $NOVEM_TOKEN" \
  https://api.novem.io/v1/users/sam/vis/plots/sales/threads/@lee~axis-labels/resolved
{
  "resolved": true,
  "resolved_at": "Wed, 07 Oct 2026 12:00:00 UTC",
  "resolved_by": "sam"
}

The rules:

  • Who can resolve: anyone with write access to the resource the thread is attached to, the owner included. The thread's author gets no extra right, and read-only collaborators cannot resolve or reopen. A caller who can read the thread but not write the resource gets 403. A caller who cannot see the thread gets 404, as for any thread they cannot read.
  • One state per thread. It sits on the topic, and everyone who can read the thread sees the same state. Replies cannot be resolved separately.
  • Resolving again keeps the original resolver and time. Reopening clears both.
  • The resolver is named only to readers who can see that account. Others get resolved_by: null with the rest of the state.
  • Replies are still allowed on a resolved thread and do not reopen it.
  • No notifications are sent when a thread is resolved or reopened.

In GraphQL, the same state is on Topic: resolved_at, resolved_by (a User, or null) and can_resolve, which tells the caller whether they may change it.