# Comment (/entities/projects/comment)



Schema [#schema]

```typescript
import { Noun } from 'digital-objects'

export const Comment = Noun('Comment', {
  body: 'string!',
  author: '-> Contact',
  issue: '-> Issue.comments',
  resolve: 'Resolved',
})
```

Fields [#fields]

| Field    | Type       | Required | Description                       |
| -------- | ---------- | -------- | --------------------------------- |
| `body`   | string     | Yes      | Comment text (Markdown supported) |
| `author` | -> Contact | No       | Person who wrote the comment      |
| `issue`  | -> Issue   | No       | The issue this comment belongs to |

Relationships [#relationships]

| Field    | Direction | Target         | Description                           |
| -------- | --------- | -------------- | ------------------------------------- |
| `author` | ->        | Contact        | The person who wrote this comment     |
| `issue`  | ->        | Issue.comments | The issue this comment is attached to |

Verbs [#verbs]

| Verb      | Event      | Description                         |
| --------- | ---------- | ----------------------------------- |
| `create`  | `Created`  | Add a new comment to an issue       |
| `update`  | `Updated`  | Edit the comment body               |
| `delete`  | `Deleted`  | Soft-delete the comment             |
| `resolve` | `Resolved` | Mark the comment thread as resolved |

Verb Lifecycle [#verb-lifecycle]

```typescript
import { Comment } from '@headlessly/projects'

// BEFORE hook -- validate before resolution
Comment.resolving(comment => {
  if (!comment.author) {
    throw new Error('Only authored comments can be resolved')
  }
})

// Execute
await Comment.resolve('comment_mR4nVkTw')

// AFTER hook -- log the resolution
Comment.resolved((comment, $) => {
  $.Activity.create({
    subject: `Comment resolved on ${comment.issue}`,
    type: 'Task',
    contact: comment.author,
    status: 'Completed',
  })
})
```

Cross-Domain Patterns [#cross-domain-patterns]

Comment provides the discussion layer for project work:

* **CRM**: Comment authors are Contacts -- the same people tracked across the CRM graph.
* **Support**: When support tickets escalate to issues, the conversation continues as comments.
* **Analytics**: Comment activity feeds into engagement and velocity metrics.

```typescript
import { Comment } from '@headlessly/projects'

Comment.created((comment, $) => {
  $.Event.create({
    type: 'comment.created',
    properties: {
      issue: comment.issue,
      author: comment.author,
    },
  })
})
```

Query Examples [#query-examples]

SDK [#sdk]

```typescript
import { Comment } from '@headlessly/projects'

// Find all comments on an issue
const comments = await Comment.find({
  issue: 'issue_pQ8xNfKm',
})

// Get a specific comment
const comment = await Comment.get('comment_mR4nVkTw')

// Add a comment to an issue
await Comment.create({
  body: 'Fixed in commit abc123 -- deploying to staging now.',
  author: 'contact_fX9bL5nRd',
  issue: 'issue_pQ8xNfKm',
})

// Resolve a comment thread
await Comment.resolve('comment_mR4nVkTw')
```

MCP [#mcp]

```json title="headless.ly/mcp#search"
{
  "type": "Comment",
  "filter": { "issue": "issue_pQ8xNfKm" },
  "sort": { "$createdAt": "asc" }
}
```

```json title="headless.ly/mcp#fetch"
{ "type": "Comment", "id": "comment_mR4nVkTw" }
```

```ts title="headless.ly/mcp#do"
await $.Comment.create({
  body: 'Confirmed fixed in production.',
  author: 'contact_fX9bL5nRd',
  issue: 'issue_pQ8xNfKm',
})
```

REST [#rest]

```bash
