# Knowledge API

> Record, recall, search, confirm and archive knowledge entries, and read, edit, compact and restore the knowledge brief.

Knowledge is the shared memory agents keep for an organization: short entries (one finding each) and the knowledge brief, a compacted digest of older entries. These endpoints are the same ones the MCP Knowledge tools use (`recall_knowledge`, `record_knowledge`, `compact_knowledge` and the rest). See the [Knowledge guide](https://www.trackagoat.com/docs/guides/knowledge.md) for how agents and people use it.

> **Warning:**
>
> Entries and the brief are visible to everyone in the organization and every agent connected to it. Writes that look like they contain an API key, token, password, private key, email or phone number fail with `400 contains_sensitive_data`, and `meta.findings` names the field.

**Kinds:** `fact`, `how_to`, `decision`, `gotcha`, `event`. **Statuses:** `active`, `archived`, `superseded` (replaced by another entry), `compacted` (folded into the brief). **Link entity types:** the same as [notes](https://www.trackagoat.com/docs/api-reference/notes.md): `organization`, `project`, `campaign`, `creator`, `video`, `payout_method`, `payout_structure`, `payout_payment`, `member`. Links must point to things in the key's organization.

Every write needs the `write` scope, accepts `Idempotency-Key`, is limited to 60 Knowledge writes an hour per member, and is recorded in the API audit log with the key and, over MCP, the agent's client name.

## Entry fields

| Field | Description |
|-------|-------------|
| `id`, `kind`, `title`, `summary`, `tags`, `project_id` (null = org-wide) | The entry. |
| `body` | Markdown detail (full reads and writes only). `has_body` says whether there is one. |
| `status`, `pinned`, `valid_until` | See above. Entries past `valid_until` are archived daily and never recalled. |
| `stale` | `true` when nobody confirmed it for 90 days (or since it was added). Never archived automatically. |
| `added_by` | `member_id`, `member_name`, `via` (`ui`, `api` or `mcp`), `client_name` (e.g. `claude-code`), `is_agent` and a `label` such as "Added by an agent using claude-code for Sam". |
| `links` | `{ entity_type, entity_id, name }` for each linked entity. |
| `last_confirmed_at`, `confirm_count`, `use_count`, `version` | `version` is for `PATCH` (`expected_version`). |

## POST /api/v2/knowledge/recall

The entries most useful for a task. Needs only the `read` scope (it bumps each returned entry's `use_count`).

| Field | Type | Description |
|-------|------|-------------|
| `task` | string | What the agent is about to do, in plain words (required). |
| `project_id`, `campaign_id` | uuid | Scope. Entries linked to them, or in the project, rank higher. |
| `creator_ids` | uuid[] | Creators the task is about. |
| `entities` | `{ entity_type, entity_id }[]` | Any other entities. |
| `kinds`, `tags` | string[] | Filters. |
| `limit` | integer | 1 to 20, default 8. |

Returns `items` (summaries only, never bodies, each with `why` it matched, `score`, `stale`, `links` and `added_by`), `brief` (`version`, `created_at`), `compaction_suggested`, `compaction_reasons`, `settings` and `permissions`. Archived, superseded, compacted and expired entries are left out.

```bash
curl -X POST -H "Authorization: Bearer tga_<key>" -H "Content-Type: application/json" \
  -d '{"task":"Why do this creator'\''s Instagram carousels show zero views?","creator_ids":["3fa85f64-5717-4562-b3fc-2c963f66afa6"]}' \
  https://www.trackagoat.com/api/v2/knowledge/recall
```

**Ranking.** Full-text match of the task against the title, then the summary and tags, then the body; how closely the title matches; entries linked to the given entities; the same project (entries in other projects rank lower); pinned; recent; confirmed. Entries that are stale rank lower. An entry has to match the task's words or be linked to one of the given entities to come back.

## GET /api/v2/knowledge

Search and filter. Summaries only, paginated.

| Parameter | Description |
|-----------|-------------|
| `q` | Words that must appear (quotes for phrases, `-` to exclude). |
| `project_id`, `project_scope` | `project_scope` is `any`, `project`, `project_and_org` (default with `project_id`) or `org`. |
| `kinds`, `tags` | Comma-separated. |
| `status` | `active` (default), `archived`, `superseded`, `compacted` or `all`. |
| `added_by` | `any` (default), `agent` (API or MCP) or `person` (the app). |
| `entity_type`, `entity_id` | Only entries linked to this entity. |
| `limit`, `offset` | 1 to 100 (default 25). `meta.total` and `meta.next_offset`. |

## POST /api/v2/knowledge

Record one entry. Returns `201` and the full entry.

| Field | Description |
|-------|-------------|
| `kind`, `title` (3 to 90 characters), `summary` (10 to 280) | Required. |
| `body` | Markdown, up to 6,000 characters. |
| `tags` | Up to 8; normalised to lowercase kebab-case. |
| `links` | Up to 20 `{ entity_type, entity_id }`. |
| `project_id`, `valid_until` | `valid_until` is a date (end of that day, UTC) or timestamp in the future. |
| `allow_duplicate` | Save even when a similar entry exists. |

When an active entry says nearly the same thing (title and summary similarity of 0.5 or more), nothing is saved and the response is **409** `possible_duplicate` with `meta.candidates` (`id`, `title`, `summary`, `similarity`). Confirm or update one of them instead, or retry with `allow_duplicate: true`. Less similar entries come back in `meta.possibly_related`.

## GET, PATCH, DELETE /api/v2/knowledge/\{id\}

- **GET** returns the full entry; `meta` has `can_edit`, `can_archive`, `can_pin` and the org's settings.
- **PATCH** changes `kind`, `title`, `summary`, `body`, `tags`, `links` (replaces them), `project_id`, `valid_until` or `pinned`, or makes an archived entry active again with `"status": "active"`. Requires `expected_version`; a stale one gets **409** `knowledge_version_conflict` with `meta.current_version`.
- **DELETE** archives it. Body (or query string): `reason` (required) and optional `superseded_by`, the active entry that replaces it.

## POST /api/v2/knowledge/\{id\}/confirm

The entry is still true. Optional `note` (up to 280 characters). Bumps `confirm_count` and `last_confirmed_at`.

## GET /api/v2/knowledge/brief

The current org brief, or `?project_id=` for a project's, or `?version=` for an earlier one. `data` is `null` when there is none. `meta` has `current_version`, `stats` (`active_count`, `active_summary_chars`, `stale_count`, `new_since_brief` and more), `compaction_suggested`, `compaction_reasons`, `settings` and `permissions`.

## PUT /api/v2/knowledge/brief

Write a new version directly: `body` (Markdown, up to 4,000 characters), `expected_brief_version` (0 when there is none), optional `project_id` and `note`. A stale version gets **409** `knowledge_brief_conflict`.

## GET /api/v2/knowledge/brief/versions

Every version, newest first, with a preview, `source` (`compaction`, `edit` or `restore`), `folded_entry_count`, `note` and `created_by`.

## GET /api/v2/knowledge/compaction

Candidates for compaction: the current `brief`, `expected_brief_version`, the `budget`, `candidates` (summaries and bodies trimmed to 500 characters, each with `reasons`: `stale`, `expired`, `older_than_30_days`, `unconfirmed`, `low_use`, `replaces_older_entries`, `overlaps`), `groups` of overlapping entries, `compaction_suggested` and `how_to_compact`.

## POST /api/v2/knowledge/compaction

Commit a compaction in one transaction.

| Field | Description |
|-------|-------------|
| `expected_brief_version` | The version you read (0 when there is none). |
| `brief` | The complete new brief, up to 4,000 characters. |
| `folded_entry_ids` | Entries whose point is now in the brief. They become `compacted`. |
| `merged_entries` | Up to 20 new consolidated entries (`kind`, `title`, `summary`, optional `body`, `tags`, `links`, `project_id`) each with `replaces`: the entries it replaces become `superseded`, and their links carry over. |
| `include_pinned_ids` | Pinned entries you agreed to fold. Any other pinned entry fails with **409** `knowledge_pinned_entries`. |
| `project_id`, `note` | A project brief (only its entries), and a note for the version history. |

Entries that are not active in scope fail with **409** `knowledge_invalid_entries`. Every org admin gets a notification naming the member and the agent.

## POST /api/v2/knowledge/brief/restore

`version` to bring back (optional `expected_brief_version`, `project_id`, `note`). It becomes a new version; entries folded or superseded by later compactions become active again, and the entries those compactions created are archived.

## Settings

Three org settings decide who may compact, edit or restore the brief; pin entries; and archive entries someone else added. Each is `admins` (the default) or `members`; org admins always may, and anyone may archive their own entries. They are returned in `settings` and the connection's `permissions` (`can_compact`, `can_pin`, `can_archive_others`, and more). A refused call gets **403** `knowledge_compaction_admins_only`, `knowledge_pin_admins_only` or `knowledge_archive_admins_only`. The settings can only be changed in the app, by an org admin.

---
Source: https://www.trackagoat.com/docs/api-reference/knowledge
