Marketplace / Docs / Discussions

Discussions

Per-package threads, replies, voting, and accepted answers for marketplace packages.

Jump to section

Per-package discussion threads — questions, bug reports, feature requests, and open conversation about marketplace packages.


Overview

Discussions are per-package community forums. Anyone authenticated on a package's marketplace listing can start a thread, post replies, and vote on contributions. Threads have a type that signals their intent — open conversation, a specific question, a feature suggestion, or a bug report — and one type (question) supports the publisher marking a reply as the accepted answer.

The Discussions system is fully implemented in the registry backend (packages/registry/src/singularity_registry/api/discussions.py, 10 endpoints).


UI Status

Note: The marketplace web UI does not yet render discussions on package detail pages or anywhere else. The REST API documented below is live today — threads and replies you create are stored and retrievable, but they will only become visible to other users once the web surface ships. The web UI for discussions is in development.

For now, treat this as the spec for an API integration. The shape will not change when the web UI lands.


Thread Types

A thread is created with one of four types (thread_type field), enforced by the registry:

  • discussion — open-ended conversation. The default.
  • question — a question expecting an answer. Supports accepting one reply as the canonical answer.
  • feature_request — a suggestion for the package author.
  • bug_report — a defect report.

Thread type is set at creation and influences how the (future) UI will badge, sort, and filter threads. The accepted-answer affordance is only available on question threads.


Creating a Thread

POST /api/v1/packages/{publisher_name}/{package_name}/discussions
Authorization: Bearer <token-or-api-key>
Content-Type: application/json

{
  "title": "How do I configure the retry interval?",
  "body": "The default of 30s is too aggressive for our use case. Is there a config flag, or do I need to fork?",
  "thread_type": "question"
}

Field rules:

  • title — required, 5-256 characters.
  • body — required, 10-10000 characters.
  • thread_type — required, one of discussion, question, feature_request, bug_report.

The response carries the new thread's ID, vote count (starting at 0), and metadata.


Listing Threads

GET /api/v1/packages/{publisher_name}/{package_name}/discussions
GET /api/v1/packages/{publisher_name}/{package_name}/discussions?type=question
GET /api/v1/packages/{publisher_name}/{package_name}/discussions?sort=newest&page=1&per_page=20

Query parameters:

  • type — filter by thread_type. Omit to return all types.
  • sortnewest (default), plus whatever other sort orders the discussion service exposes.
  • page — defaults to 1, min 1.
  • per_page — defaults to 20, capped at 100.

The response is paginated and includes thread metadata: author name + display name, vote count, reply count, pin/lock state, and timestamps.

To fetch a specific thread by ID:

GET /api/v1/discussions/{thread_id}

Replying

Once you have a thread ID, post a reply:

POST /api/v1/discussions/{thread_id}/replies
{
  "body": "There's an undocumented `RETRY_INTERVAL_MS` env var — try setting it to 60000."
}

Body is 1-10000 characters. List a thread's replies:

GET /api/v1/discussions/{thread_id}/replies?page=1&per_page=50

Replies are paginated, default per_page is 50 (capped at 100).


Voting

Both threads and individual replies are votable. Votes are +1 or -1:

POST /api/v1/discussions/{thread_id}/vote
{ "vote_type": 1 }

POST /api/v1/discussions/replies/{reply_id}/vote
{ "vote_type": -1 }

The API records one vote per publisher per target; re-voting overrides the previous vote rather than stacking. The aggregate score appears on the thread/reply object in list and detail responses.


Accepting an Answer

For question threads only, the thread author can mark one reply as the accepted answer:

POST /api/v1/discussions/replies/{reply_id}/accept

This flags the reply server-side. Authorization is enforced — only the original thread author (or, depending on discussion_service rules, the package publisher) can accept. Calling on a non-question thread or by an unauthorized user returns a 400.

Accepted answers are a useful Q&A pattern: they help future readers find the canonical solution without scanning every reply.


Editing and Deleting

Thread authors can update their own threads:

PATCH /api/v1/discussions/{thread_id}
{
  "title": "Updated title",
  "body": "Updated body",
  "is_pinned": true,
  "is_locked": false
}

All fields are optional. The is_pinned and is_locked flags exist for moderation use — non-author callers are restricted from setting them.

To delete a thread entirely:

DELETE /api/v1/discussions/{thread_id}

Deletes are author-only (or admin). Replies on a deleted thread are typically cascaded; consult the discussion_service for exact semantics.


Moderation

Two moderation affordances exist today on threads:

  • is_pinned — pinned threads sort to the top of their package's thread list.
  • is_locked — locked threads accept no new replies. Existing replies remain readable.

Both are set through the standard PATCH /api/v1/discussions/{thread_id} endpoint, with role-based authorization enforced server-side. A package publisher will typically have the privilege to pin or lock threads about their own package; rank-and-file commenters do not.

There is no public "report this thread" endpoint distinct from the review-flagging flow yet. If you need to report abuse in discussions, contact support or open an issue against the registry repository.