LoopLoop

Issues

Create, list, update, and delete issues — Loop's atomic unit of work.

Issues

Issues are the atomic unit of work in Loop. Everything — signals, hypotheses, plans, tasks, and monitors — is an issue with a type. The loop.issues resource provides full CRUD operations plus auto-pagination.

import { LoopClient } from '@dork-labs/loop-sdk'

const loop = new LoopClient({ apiKey: 'loop_abc123' })

List issues

Retrieve a paginated list of issues with optional filters.

const result = await loop.issues.list({
  status: 'todo',
  type: 'task',
  projectId: 'clxyz1234567890abcdef',
  limit: 25,
  offset: 0,
})

console.log(result.data)   // Issue[]
console.log(result.total)  // total matching count
console.log(result.hasMore) // true if more pages exist

Filter parameters

ParameterTypeDescription
statusstringFilter by status: triage, backlog, todo, in_progress, done, canceled
typestringFilter by type: signal, hypothesis, plan, task, monitor
projectIdstringFilter by project ID
labelIdstringFilter by label ID
prioritynumberFilter by priority level
parentIdstringFilter by parent issue ID
limitnumberPage size (default varies by server)
offsetnumberNumber of items to skip

Return type

list() returns a PaginatedList<Issue> with three properties:

PropertyTypeDescription
dataIssue[]Array of issues for the current page
totalnumberTotal number of matching issues across pages
hasMorebooleanWhether additional pages exist

Auto-paginate with iter

The iter() method returns an async generator that automatically pages through all matching issues. It accepts the same filter parameters as list() except limit and offset, which are managed internally.

for await (const issue of loop.issues.iter({ status: 'todo' })) {
  console.log(`#${issue.number}: ${issue.title}`)
}

You can also collect all results into an array:

const allTasks: Issue[] = []
for await (const issue of loop.issues.iter({ type: 'task' })) {
  allTasks.push(issue)
}

iter() fetches pages of 50 items internally. Each page is a separate HTTP request, so iterating over thousands of issues will make multiple API calls.

Get an issue

Retrieve a single issue by ID. The response includes the full IssueDetail with parent, children, labels, and relations.

const issue = await loop.issues.get('clxyz1234567890abcdef')

console.log(issue.title)
console.log(issue.parent)     // Issue | null
console.log(issue.children)   // Issue[]
console.log(issue.labels)     // Label[]
console.log(issue.relations)  // IssueRelation[]

IssueDetail type

get() returns an IssueDetail, which extends Issue with related data:

PropertyTypeDescription
parentIssue | nullParent issue, if this is a sub-issue
childrenIssue[]Child issues
labelsLabel[]Attached labels
relationsIssueRelation[]Blocking and related issue links

Create an issue

Create a new issue. Only title and type are required.

const issue = await loop.issues.create({
  title: 'Investigate login page 500 errors',
  type: 'task',
  status: 'todo',
  priority: 2,
  projectId: 'clxyz1234567890abcdef',
  description: 'Users on mobile Safari are seeing 500 errors on the login page.',
})

console.log(issue.id)     // CUID2 ID
console.log(issue.number) // sequential issue number

Create parameters

ParameterTypeRequiredDescription
titlestringYesIssue title
typeIssueTypeYessignal, hypothesis, plan, task, or monitor
descriptionstringNoDetailed description
statusIssueStatusNoInitial status (defaults to triage)
prioritynumberNoPriority level
parentIdstringNoParent issue ID for sub-issues
projectIdstringNoAssign to a project
signalSourcestringNoOrigin of the signal (e.g. posthog)
signalPayloadSignalPayloadNoRaw signal data as JSON
hypothesisHypothesisDataNoStructured hypothesis with confidence
labelIdsstring[]NoLabels to attach on creation

Creating with a hypothesis

Issues of type hypothesis can include structured hypothesis data:

const issue = await loop.issues.create({
  title: 'OAuth redirect adds 1.5s blank screen causing drop-off',
  type: 'hypothesis',
  hypothesis: {
    statement: 'The OAuth redirect change in PR #847 adds a blank screen causing user abandonment.',
    confidence: 0.82,
    evidence: [
      'Conversion dropped 12% in 24h',
      'PR #847 merged 26h ago',
      'Error rate unchanged — not a crash',
    ],
    validationCriteria: 'Conversion returns above 3.4% within 48 hours of fix.',
  },
})

Update an issue

Update one or more fields on an existing issue. Only the fields you include will be changed.

const updated = await loop.issues.update('clxyz1234567890abcdef', {
  status: 'done',
  description: 'Added loading spinner to OAuth redirect page.',
})

console.log(updated.status)      // 'done'
console.log(updated.completedAt) // timestamp set automatically

Update parameters

ParameterTypeDescription
titlestringNew title
descriptionstringNew description
typeIssueTypeChange issue type
statusIssueStatusChange status
prioritynumberChange priority
parentIdstring | nullSet or remove parent
projectIdstring | nullSet or remove project
signalSourcestringUpdate signal source
signalPayloadSignalPayloadUpdate signal payload
hypothesisHypothesisData | nullSet or remove hypothesis data

Pass null for parentId, projectId, or hypothesis to explicitly clear the field.

Delete an issue

Soft-delete an issue. The issue is marked as deleted but remains in the database.

await loop.issues.delete('clxyz1234567890abcdef')

The method returns void. Soft-deleted issues are excluded from list() and iter() results.

Issue type reference

The full Issue type returned by list(), create(), and update():

FieldTypeDescription
idstringCUID2 unique identifier
numbernumberSequential issue number
titlestringIssue title
descriptionstring | nullDetailed description
typeIssueTypesignal, hypothesis, plan, task, monitor
statusIssueStatustriage, backlog, todo, in_progress, done, canceled
prioritynumberPriority level
parentIdstring | nullParent issue ID
projectIdstring | nullProject ID
signalSourcestring | nullSignal origin identifier
signalPayloadSignalPayload | nullRaw signal data
hypothesisHypothesisData | nullStructured hypothesis data
agentSessionIdstring | nullAgent session that worked on this
agentSummarystring | nullSummary of agent work
commitsCommitRef[] | nullLinked commits
pullRequestsPullRequestRef[] | nullLinked pull requests
completedAtstring | nullCompletion timestamp
createdAtstringCreation timestamp
updatedAtstringLast update timestamp
deletedAtstring | nullSoft-delete timestamp

Enums

IssueType

ValueDescription
signalRaw incoming data from an external source
hypothesisA proposed explanation for an observed signal
planA breakdown of work needed to validate a hypothesis
taskA concrete, agent-executable unit of work
monitorA post-execution check to verify outcomes

IssueStatus

ValueDescription
triageAwaiting initial review
backlogAccepted but not yet prioritized for work
todoReady to be picked up
in_progressCurrently being worked on
doneCompleted
canceledWill not be worked on