# Tasker API Audit

Last updated: 2026-05-14.

## Summary

Current Tasker / Plane fork is partially ready for the Codex Agent API use case through existing REST endpoints and NODE.DC structured blocks. It is not ready as a direct external API for agents because it has broad routes, session-oriented permissions, delete/archive endpoints, and no MCP layer.

The correct approach is to add a narrow internal Tasker adapter for Agent Gateway instead of exposing raw Plane API to local Codex.

## Existing useful API surface

### Issues

Routes exist for issue list/create/update/retrieve:

```text
GET  /api/workspaces/:slug/projects/:project_id/issues/
POST /api/workspaces/:slug/projects/:project_id/issues/
GET  /api/workspaces/:slug/projects/:project_id/issues/:issue_id/
PATCH /api/workspaces/:slug/projects/:project_id/issues/:issue_id/
```

The same route also supports `DELETE`, but Agent Gateway must never expose it.

Existing serializers already support:

- name;
- state;
- priority;
- dates;
- labels;
- assignees;
- parent issue;
- description HTML;
- `detail_layout`.

Validation already checks:

- assignees are active project members with sufficient role;
- labels belong to project;
- state belongs to project;
- parent belongs to workspace/project;
- description HTML is sanitized.

### Structured blocks

NODE.DC structured task content lives in:

```text
Issue.detail_layout["nodedc_structured_blocks"]
```

Known block types:

```text
text
checker
```

This is the right storage layer for:

- current architecture;
- planned architecture;
- stages;
- checkers;
- implementation notes.

Tasker already computes checker progress from this structure.

### Comments

Routes exist:

```text
GET  /api/workspaces/:slug/projects/:project_id/issues/:issue_id/comments/
POST /api/workspaces/:slug/projects/:project_id/issues/:issue_id/comments/
PATCH /api/workspaces/:slug/projects/:project_id/issues/:issue_id/comments/:comment_id/
DELETE /api/workspaces/:slug/projects/:project_id/issues/:issue_id/comments/:comment_id/
```

Agent Gateway should expose comment creation and possibly own-comment edit later, but not comment deletion.

### Labels

Routes exist:

```text
GET  /api/workspaces/:slug/projects/:project_id/issue-labels/
POST /api/workspaces/:slug/projects/:project_id/issue-labels/
PATCH /api/workspaces/:slug/projects/:project_id/issue-labels/:label_id/
DELETE /api/workspaces/:slug/projects/:project_id/issue-labels/:label_id/
```

MVP should let agents apply existing labels. Creating labels can be added later under an explicit admin scope.

### States

Routes exist:

```text
GET /api/workspaces/:slug/projects/:project_id/states/
PATCH /api/workspaces/:slug/projects/:project_id/states/:state_id/
```

Agent Gateway should allow moving issues to existing states. It should not allow state creation/deletion in MVP.

### Project members

Routes exist:

```text
GET  /api/workspaces/:slug/projects/:project_id/members/
POST /api/workspaces/:slug/projects/:project_id/members/
PATCH /api/workspaces/:slug/projects/:project_id/members/:member_id/
DELETE /api/workspaces/:slug/projects/:project_id/members/:member_id/
```

Current code checks workspace membership and blocks launcher-managed workspace self-management.

Agent Gateway may expose `add_existing_project_member` only with an explicit scope and only for existing workspace members.

## Missing MCP layer

No dedicated MCP server exists in Tasker today. References to MCP are documentation/guideline-oriented, not an operational API server.

Required new layer:

```text
Agent Gateway MCP tools -> Agent Gateway service -> Tasker internal adapter
```

Tasker should not become the MCP host. Keeping MCP in Agent Gateway preserves standalone Tasker and keeps the external agent surface outside Plane.

## Required Tasker adapter additions

Add internal endpoints under a namespace such as:

```text
/api/internal/nodedc/agent/...
```

Current implemented adapter routes:

```text
POST /api/internal/nodedc/agent/projects/resolve
POST /api/internal/nodedc/agent/projects
GET  /api/internal/nodedc/agent/projects/:project_id/context
GET  /api/internal/nodedc/agent/issues?project_id=...
POST /api/internal/nodedc/agent/issues
GET  /api/internal/nodedc/agent/issues/:issue_id
PATCH /api/internal/nodedc/agent/issues/:issue_id
POST /api/internal/nodedc/agent/issues/:issue_id/attachments
POST /api/internal/nodedc/agent/issues/:issue_id/move
POST /api/internal/nodedc/agent/issues/:issue_id/comments
PUT  /api/internal/nodedc/agent/issues/:issue_id/labels
PUT  /api/internal/nodedc/agent/issues/:issue_id/assignees
```

The implemented adapter uses NODE.DC internal bearer auth and receives normalized agent metadata in headers:

```text
X-NODEDC-Agent-Id
X-NODEDC-Agent-Owner-User-Id
X-NODEDC-Agent-Token-Id
```

The current adapter creates or reuses a dedicated bot actor with email `agent+<agent_id>@agents.nodedc.local` and `bot_type=nodedc_codex_agent`.

Issue detail returns full comment bodies plus attachment metadata. Project
creation is workspace-admin gated and idempotent by agent external id.
Attachment upload uses Plane's existing FileAsset, S3/MinIO, quota, MIME, and
deduplication implementation; it accepts no server path or remote URL.

These endpoints must use `NODEDC_INTERNAL_ACCESS_TOKEN` / `PLANE_NODEDC_ACCESS_TOKEN` style auth and must be callable only from Agent Gateway.

Suggested adapter endpoints:

```text
POST /api/internal/nodedc/agent/context/
POST /api/internal/nodedc/agent/issues/search/
POST /api/internal/nodedc/agent/issues/
PATCH /api/internal/nodedc/agent/issues/:issue_id/
POST /api/internal/nodedc/agent/issues/:issue_id/comments/
POST /api/internal/nodedc/agent/issues/:issue_id/structured-blocks/
POST /api/internal/nodedc/agent/projects/:project_id/members/add-existing/
```

The adapter should receive normalized Agent Gateway metadata:

```text
agent_id
owner_user_id
owner_email
workspace_slug
project_id
scopes
idempotency_key
```

The adapter should validate Tasker domain rules and return stable errors rather than leaking raw Plane serializer details.

## Why raw Plane API is not enough

Raw Plane API is too broad for external agents:

- it includes delete/archive routes;
- it assumes a session user, not an external agent identity;
- it has more fields than agents should control;
- it does not know Launcher module entitlements;
- it does not have agent idempotency;
- it does not produce agent-specific audit by default;
- it is not MCP-native.

## Compatibility note

Tasker must remain standalone-capable. All agent-specific behavior should be disabled when NODE.DC Agent Gateway env vars are absent.
