8.7 KiB
Non-Linear: AI Agent Integration
Overview
Non-Linear treats AI agents as first-class actors — not assistants bolted onto a human interface, but independent participants with their own accounts, roles, permissions, and graph navigation capabilities.
Two Agent Modes
Agent as User
The agent operates independently within the project graph. It has its own account, picks up tasks, reports status, and navigates the decomposition tree autonomously.
Primary use case: One-person team where an AI agent acts as a focused collaborator.
How the graph helps: The decomposition tree gives the agent rails:
- "What's the highest-priority unblocked leaf node in Backend?" → graph traversal query
- "What's the status of the Auth component?" → read subtree, aggregate child statuses
- "What should I work on next?" → find unblocked, assigned, in-progress leaves
Agent as Assistant
The agent helps human users by analyzing the graph and suggesting actions.
Primary use case: Teams where AI augments human decision-making.
Examples:
- "Break this component into tasks" → agent suggests child nodes, human approves
- "What's blocking the Auth epic?" → agent traverses subtree and lateral links
- "Summarize progress on Dashboard this week" → agent reads subtree statuses and recent comments
- "Suggest priority order for these tasks" → agent considers dependencies and blockers
Agent API (v0.1)
Governed by the same policy engine as human users. Agents authenticate with API tokens tied to their actor account.
Graph Traversal
GET /api/v1/nodes/{id} # Read single node
GET /api/v1/nodes/{id}/children # Direct children
GET /api/v1/nodes/{id}/subtree # Full subtree (depth-limited)
GET /api/v1/nodes/{id}/parent # Parent node
GET /api/v1/nodes/{id}/links # Outbound lateral links
GET /api/v1/nodes/{id}/backlinks # Inbound lateral links
GET /api/v1/nodes/{id}/path # Path from root to this node
GET /api/v1/nodes/{id}/history # Change history timeline
GET /api/v1/projects/{id}/root # Project root node
GET /api/v1/projects/{id}/inbox # Triage inbox (rootless nodes)
Queries
GET /api/v1/projects/{id}/nodes?status=in_progress&assignee=agent-123
GET /api/v1/projects/{id}/nodes?label=bug&status=backlog
GET /api/v1/projects/{id}/nodes?unblocked=true&status=todo
GET /api/v1/projects/{id}/nodes?cycle=current
Write Actions (v0.1)
POST /api/v1/nodes/{id}/comments # Add comment
PATCH /api/v1/nodes/{id}/status # Change status
PATCH /api/v1/nodes/{id}/parent # Triage: assign parent to inbox item
Deferred Actions (v0.2+)
POST /api/v1/nodes/{id}/children # Create child node
POST /api/v1/nodes/{id}/links # Create lateral link
DELETE /api/v1/nodes/{id}/links/{link_id} # Remove lateral link
PATCH /api/v1/nodes/{id} # Edit node details
Authentication
- Agents authenticate via API tokens (bearer tokens)
- Each token is tied to an actor (agent account)
- The actor has roles/policies assigned via the policy engine
- Token scoping: a token can optionally be restricted to a subset of the agent's permissions
Pagination
All list endpoints use cursor-based pagination. Responses include a cursor for the next page and a flag indicating whether more results exist.
Response envelope:
{
"items": [ ... ],
"next_cursor": "eyJpZCI6IjEyMyIsInRzIjoiMjAyNS0wMS0wMVQwMDowMDowMFoifQ==",
"has_more": true
}
Query parameters:
| Parameter | Default | Max | Description |
|---|---|---|---|
limit |
50 | 200 | Items per page |
cursor |
null | — | Opaque cursor from previous response |
max_depth |
3 | 10 | Subtree query depth limit (subtree endpoint only) |
- Subtree queries (
GET /nodes/{id}/subtree) acceptmax_depthto cap traversal depth. The graph visualization uses this to load progressively — fetch immediate children on expand, not the entire tree at once. - Children queries (
GET /nodes/{id}/children) are paginated but not depth-limited (they return a single level). - Search/filter queries (
GET /projects/{id}/nodes?...) are always paginated. - Cursor encoding is opaque to the client. Internally it encodes the sort key (e.g.,
created_at+id) for stable pagination under concurrent writes.
Response Format
All responses include effective permissions on the returned resource:
{
"node": {
"id": "uuid-123",
"short_id": "NL-42",
"title": "Login component",
"status": "in_progress",
"labels": ["frontend", "p1"],
"parent_id": "uuid-456",
"children_count": 3,
"backlinks": {
"blocked_by_count": 1,
"relates_to_count": 2
},
"links": [
{
"type": "blocked_by",
"target_id": "uuid-789",
"target_accessible": true,
"target_title": "SSO integration"
},
{
"type": "relates_to",
"target_id": "uuid-000",
"target_accessible": false,
"target_title": null
}
]
},
"permissions": {
"can_edit": false,
"can_change_status": true,
"can_comment": true,
"can_create_child": false
}
}
Agent Design Patterns
Focused Worker Agent
Loop:
1. Query subtree for unblocked, assigned, todo items
2. Pick highest priority
3. Change status to in_progress
4. Do work (external to tracker)
5. Post comment with results
6. Change status to done or in_review
Triage Agent
Loop:
1. Query inbox for unplaced nodes
2. For each, analyze title/description and match to existing subtrees
3. Assign parent (place in tree)
4. Post comment with rationale
Decomposition Agent (v0.2+)
Triggered when: a node has label "needs-decomposition"
1. Read node context (parent, siblings, description)
2. Propose child nodes via comment or plan-then-apply
3. Human reviews and approves
4. Agent creates children
Webhooks (v0.1)
Webhooks follow a GitLab-style hooks model — per-project registration with event filtering, signed payloads, and automatic retry.
Registration
Webhooks are registered per project via the API or settings UI:
POST /api/v1/projects/{id}/webhooks
{
"url": "https://agent.example.com/hooks/nonlinear",
"secret": "whsec_...",
"events": ["node.status_changed", "node.comment_added"],
"active": true
}
| Field | Type | Description |
|---|---|---|
url |
string | HTTPS endpoint to receive POST requests |
secret |
string | Shared secret for HMAC-SHA256 signature |
events |
string[] | Event types to subscribe to (empty = all) |
active |
bool | Enable/disable without deleting |
Event Catalog
| Event | Trigger |
|---|---|
node.created |
New node (component or issue) created |
node.status_changed |
Issue status transition |
node.comment_added |
Comment posted on a node |
node.link_created |
Lateral link created |
node.link_removed |
Lateral link removed |
node.reparented |
Node moved to a different parent |
node.cycle_added |
Issue added to a cycle |
node.deleted |
Node (and subtree) deleted |
repo.commit_associated |
Commit auto-associated with a component |
Payload Format
All webhook payloads share a common envelope:
{
"event": "node.status_changed",
"timestamp": "2025-06-15T14:30:00Z",
"project_id": "uuid-project",
"actor": {
"id": "uuid-actor",
"type": "user",
"name": "alice"
},
"data": {
"node_id": "uuid-123",
"short_id": "NL-42",
"previous_status": "in_progress",
"new_status": "in_review"
}
}
The data field varies by event type. Each event includes the affected node's node_id and short_id at minimum.
Signature Verification
Every webhook request includes an X-NonLinear-Signature header containing an HMAC-SHA256 hex digest of the raw request body, computed with the webhook's shared secret:
X-NonLinear-Signature: sha256=a1b2c3d4e5f6...
Receivers should verify the signature before processing to confirm authenticity.
Delivery & Retry
- Webhooks are delivered asynchronously via the Taskiq worker.
- Timeout: 10 seconds per delivery attempt.
- Retry: 3 attempts with exponential backoff (10s, 60s, 300s).
- Failure handling: After 3 failed attempts, the event is logged and dropped. After 50 consecutive failures across any events, the webhook is automatically deactivated and the project owner is notified.
- Ordering: Best-effort chronological. Not guaranteed under high concurrency.
MCP Compatibility (v0.2+)
Expose the Non-Linear API as an MCP server so AI agents built on LLM frameworks can connect natively.