Documentation
MCP tool reference
The 29 tools currently exposed by Helen’s Foundry, generated from the same
registry clients receive through MCP. Each row shows the summary a client sees when it lists
the tools. Expand one for its full guidance and parameters.
Tool names are shown bare. Some clients add their own prefix, such as mcp__<server>__,
when they list them. Match on the bare name.
List recent workspace activity
activity_feed_list Returns the workspace-wide, newest-first stream of artifact history, proposed changes, and external events. It is the only history surface; for open detector findings use signals_list instead.
List recent workspace activity
activity_feed_list Returns the workspace-wide, newest-first stream of artifact history, proposed changes, and external events. It is the only history surface; for open detector findings use signals_list instead.
Read recorded workspace events, newest first. Returns immutable event snapshots in {items, meta}; continue with offset: meta.next_offset. Filter by subject kind, event type, artifact type, role tier, or occurrence time. Pending work is available through pending_actions_list.
Parameters
| Name | Type | Description |
|---|---|---|
since | string | null | Only items at or after this ISO-8601 timestamp |
until | string | null | Only items at or before this ISO-8601 timestamp |
kind | "artifact" | "comment" | "proposal" | "pull_request" | "issue" | null | Subject of the recorded event |
event_type | "artifact.created" | "artifact.updated" | "artifact.deleted" | "comment.created" | "comment.updated" | "comment.deleted" | "proposal.submitted" | "proposal.approved" | "proposal.declined" | "pull_request.opened" | "pull_request.closed" | "pull_request.merged" | "issue.opened" | "issue.closed" | "artifact.created" | "artifact.updated" | "artifact.deleted" | "comment.created" | "comment.updated" | "comment.deleted" | "proposal.submitted" | "proposal.approved" | "proposal.declined" | "pull_request.opened" | "pull_request.closed" | "pull_request.merged" | "issue.opened" | "issue.closed"[] | null | Recorded event types |
artifact_type | string | string[] | null | Narrow to one or more artifact types |
role_tier | "orient" | "directional" | "structural" | "execution" | null | Narrow to events on artifacts of one role tier |
limit | integer | null | Max items (default: 50, max: 200) |
offset | integer | null | Page start over the newest-first event log; continue from `meta.next_offset`. |
List artifact type catalog
artifact_types Lists the artifact type catalogue: each type's fields, allowed parent types, tier, and allowed states. Read it before artifacts_create to pick a valid type and a valid parent.
List artifact type catalog
artifact_types Lists the artifact type catalogue: each type's fields, allowed parent types, tier, and allowed states. Read it before artifacts_create to pick a valid type and a valid parent.
The artifact type catalogue: each type's fields, hierarchy, allowed parent types, tier, and allowedStates (pass one as state to artifacts_update; out-of-tier is rejected). Field authoring rules returned by this catalogue: Artifact narrative. Mission, vision, strategy, goal, persona, problem, project, and architecture descriptions support Markdown. Preserve explanatory prose and dated checkpoints here; use artifact links for relationships, spec_clauses for testable project or ticket requirements, and content only for declared structured fields. Scalar textarea strings render Markdown; use it when headings, lists, links, quotes, or fenced code improve readability, and use Markdown instead of raw HTML because raw HTML is escaped. For textarea fields with array: true, send one item per string[] element and keep Markdown inline within each item—do not include list markers. text, select, date, and number fields are plain values and should not contain Markdown. Unfiltered by default; scope it with these AND-combined filters — types (string array of type ids, e.g. ['story','ticket']), tier (one of orient/directional/structural/execution), and parent_type (a type id: keeps the types that may be created under it, i.e. those whose allowedParentTypes includes it — the "what can I put here" query). Unknown parameters and unknown filter values are rejected with validation_failed rather than silently ignored. The response carries types (the scoped, id-keyed catalogue) and meta.filters / meta.count / meta.total echoing what was applied. Also the resource hf://types (always unfiltered).
Parameters
| Name | Type | Description |
|---|---|---|
types | string[] | null | Keep only these artifact type ids (e.g. ['story','ticket']). Unknown ids return `validation_failed`. |
tier | string | null | Keep only types in this lifecycle tier — one of orient, directional, structural, execution. An unknown tier returns `validation_failed`. |
parent_type | string | null | Keep only types that may be created under this parent type id (its `allowedParentTypes` membership). An unknown id returns `validation_failed`. |
Create one artifact, or a batch
artifacts_create Creates one artifact from a type and title, or up to 50 at once through items. To change an artifact that already exists, use artifacts_update instead.
Create one artifact, or a batch
artifacts_create Creates one artifact from a type and title, or up to 50 at once through items. To change an artifact that already exists, use artifacts_update instead.
Create artifacts in ONE of two forms: pass the single-artifact fields (type and title, plus any of the optional fields below) to create one, or pass items to create up to 50 in a single call. The two forms are exclusive: sending items together with any single-artifact field returns validation_failed, and so does sending neither. Single form: use parent_id for one containment parent or parent_ids for up to 20; when both are supplied they are combined and de-duplicated. Every parent is type-validated before the atomic write, so one missing or wrong-type parent returns an error without creating the artifact or any edges. Singleton types (mission/vision/strategy/domain_model) replace their predecessor (_singleton_replaced sidecar). Agent credentials (API key / OAuth client) MUST attach a parent to a non-root type: a parentless create is REFUSED with validation_failed before anything is written, and its details carry rule_id: 'missing_parent', the expected_parent_types, ranked suggested_parents, and retry_with_parent_id pre-filled with the closest candidate — so the retry is one call. Pass allow_orphan: true to create it unparented on purpose. When an artifact does land without a parent (a web/system create, or allow_orphan), it carries _readiness_warnings whose missing_parent entry ranks the same candidates and pre-fills the top one into recommended_action.args.source_id, so attaching a parent is one links_add. Both surfaces carry a ranking block describing the candidate list's provenance, in the same vocabulary artifacts_suggest_parents uses: mode is semantic or unavailable, semantic_ranking says whether embedding ranking actually ran, returned is the candidate count, and an optional degraded (code, failure_stage, retryable, recovery) is present only when ranking could not be performed — so an empty suggested_parents means 'no candidate exists' ONLY when degraded is absent. degraded.recovery names the retry: artifacts_suggest_parents with the created artifact's id in args.orphan_ids, or artifacts_create itself for a refusal, since nothing was written. Ranking is one graph read; allow_orphan skips it, because a stated orphan needs no candidates. parent_tier_empty: true means the workspace holds no live artifact of any expected parent type at all: create that parent first instead of hunting for one. Elicitation-capable clients are additionally prompted to pick a suggested parent (or keep it root); pick one and the create links it for you. On a created result the artifact also carries a _signals sidecar: Reconcile findings (including drift findings and detected incompatibilities) on the new artifact and all parents. Returns {kind:'created'}, or {kind:'proposal',proposal_id,proposal_url} when the create requires human review — branch on kind. Put your reasoning, sources, and caveats for that reviewer in rationale, not in description: the description is saved as the artifact's text. Agent credentials (API key / OAuth client) creating a singleton type are ALWAYS routed to human review regardless of workspace policy (the predecessor replacement happens only when the proposal is applied). Applying that proposal creates the singleton in the requested state; for a committed state, the human chooses Create & ratify or Decline. Other ratification-gated agent creates land as draft. When their response includes proposal_url, give it to a human workspace editor to choose Ratify & promote or Keep as draft. Explicit draft creates do not file a promotion. Batch form (items): create up to 50 artifacts in one call (fan-out bounded to 8 in-flight globally and 3 per shared parent); each item runs through the single-create path independently, so partial failures don't sink the batch. items is exclusive with the single-create fields — send one form or the other, never both, or the call returns validation_failed. Items accept type, title, description, content, parent_id, priority, state, owner_id, allow_orphan, and rationale. Agent-created singleton items (mission/vision/strategy/domain_model) require human review before creation: their per-item result is { ok: true, kind: 'proposal', proposal_id, proposal_url }, counted in summary.proposed rather than succeeded. Returns { results, summary } with per-item ok/error so you can retry failures — UNLESS every item failed, in which case the call is a top-level error (isError) whose details.results carries the per-item errors, so a 0-succeeded batch is never reported as success. A non-root item with no parent_id from an agent credential FAILS that item with validation_failed / rule_id: 'missing_parent', carrying ranked suggested_parents and retry_with_parent_id so you can retry just that item with a parent; the rest of the batch still lands. Create-first/link-later flows must set allow_orphan: true on those items, which lets them land with a _readiness_warnings entry to resolve later with the pairs form of links_add. Candidate ranking runs on every parentless item, but an item that sets allow_orphan is not ranked at all, so a create-first batch pays nothing for candidates it would discard. For new artifacts that must reference each other's returned ids, use sequential single creates. A failed item's quality rejection carries only details.artifact_quality.{status, findings, suggestions?}; it has no error.message: each finding's rule id and reason are in findings, and suggestions holds up to three concrete fixes. Under the response cap, rows shed detail and _meta.degraded names what was dropped, but summary and each row's ok plus artifact id or error code always remain: read written items by id rather than retrying the batch. Emits notifications/progress when given a progress token.
Parameters
| Name | Type | Description |
|---|---|---|
mutation_id | string | null | Deprecated and ignored. Writes no longer take an idempotency key. |
type | "mission" | "vision" | "strategy" | "goal" | "domain_model" | "persona" | "problem" | "project" | "ticket" | null | Single form: artifact type. Required with `title`, and rejected alongside `items`. |
title | string | null | Single form: artifact title. Required with `type`, and rejected alongside `items`. |
items | object[] | null | Batch form: 1 to 50 create payloads (the array is named `items`, not `artifacts`), each accepting type, title, description, content, parent_id, priority, state, owner_id, and allow_orphan. Rejected alongside the single-artifact fields. |
description | string | null | Artifact narrative. Mission, vision, strategy, goal, persona, problem, project, and architecture descriptions support Markdown. Preserve explanatory prose and dated checkpoints here; use artifact links for relationships, spec_clauses for testable project or ticket requirements, and content only for declared structured fields. |
content | object | null | Type-specific structured fields. Call `artifact_types` first and use only its declared keys and value shapes. Scalar `textarea` strings render Markdown; use it when headings, lists, links, quotes, or fenced code improve readability, and use Markdown instead of raw HTML because raw HTML is escaped. For `textarea` fields with `array: true`, send one item per `string[]` element and keep Markdown inline within each item—do not include list markers. `text`, `select`, `date`, and `number` fields are plain values and should not contain Markdown. |
spec_clauses | string | object[] | null | Atomic, testable normative contract clauses for project or ticket artifacts (maximum 32 clauses). Accepts plain strings or objects with `{ statement, proposed_anchor_names }`. Each clause statement must be a single line containing exactly one canonical MUST or MUST NOT. Examples: ['The create handler MUST reject malformed identifiers', 'Closed artifacts MUST NOT accept new child links']. Pass proposed_anchor_names with the function or class names you plan to write or modify to link AST anchors. |
parent_id | string | null | Parent artifact UUID to link to |
parent_ids | string[] | null | One to 20 parent artifact UUIDs to link atomically. May be combined with parent_id; duplicates are ignored. |
priority | "critical" | "high" | "medium" | "low" | null | null | Priority — execution-tier types only; null/omitted = unset |
state | "draft" | "backlog" | "todo" | "in_progress" | "in_review" | "active" | "closed" | null | Initial lifecycle state. Omit for the default active create; pass draft only for explicit draft workflows. Agent credentials (API key / OAuth client) creating ratification-gated types (non-execution tiers plus project/architecture/requirement) always land as draft. The result's `_authority_policy` explains how a human ratifies and promotes the current premise. |
owner_id | string | null | null | UUID of the workspace member who owns this artifact. Must be a member of this workspace, else `validation_failed`. Null/omitted = unassigned. |
evaluate | boolean | null | Accepted for compatibility and has no effect on create. Semantic quality grading remains mandatory. |
allow_orphan | boolean | null | Create this artifact with no parent on purpose. Only agent credentials need it: a parentless non-root create from automation is refused, because an omitted parent is nearly always an oversight and the resulting orphan is invisible to the agent that made it. `true` records the decision and skips the refusal; the artifact still carries its `missing_parent` readiness warning. Ignored when a parent is supplied, and a no-op for web/system callers. |
rationale | string | null | Your note to the human reviewer: reasoning, sources, and caveats such as 'inferred from the pitch deck; no document states an adopted mission'. Shown beside the proposal when the create needs human review; never saved into the artifact. Keep `description` to the artifact's own text. |
Delete an artifact
artifacts_delete Soft-deletes an artifact through a two-phase confirmation. Reach for it only for genuine garbage; to retire real work, close or archive it with artifacts_update.
Delete an artifact
artifacts_delete Soft-deletes an artifact through a two-phase confirmation. Reach for it only for genuine garbage; to retire real work, close or archive it with artifacts_update.
Soft-delete an artifact (history/links/findings preserved, no public restore surface) — prefer artifacts_update({state:'closed'}) or {archived:true} unless it's genuine garbage. Two-phase: the first call returns {kind:'requires_confirmation', confirmation_token, preview}; call again with the token to execute. Branch on kind.
Parameters
| Name | Type | Description |
|---|---|---|
mutation_id | string | null | Deprecated and ignored. Writes no longer take an idempotency key. |
id required | string | Artifact UUID |
confirmation_token | string | null | Token from a prior requires_confirmation response. Omit on first call. |
Get one artifact by id
artifacts_get Returns one artifact by id with its content, lifecycle fields, and optional sidecars, archived ones included. When you do not have the id yet, use artifacts_search or artifacts_list.
Get one artifact by id
artifacts_get Returns one artifact by id with its content, lifecycle fields, and optional sidecars, archived ones included. When you do not have the id yet, use artifacts_search or artifacts_list.
Get one artifact by ID with saved quality level (low, moderate, or high; null when unassessed), full content, state, closure_reason, archived_at. Explicit ID retrieval includes archived artifacts for recovery and audit; default grounding reads exclude them. By default attaches three sidecars: up to 3 recent _external_references, a _signals sidecar of the reconcile signals on this artifact (findings on it + conflicts naming it) so you see them before acting, and _owner. Pass include: ['specifications'] (opt-in, never attached by default) to add _specifications: the effective specification view for this artifact, its own and inherited specification clauses, bounded, with meta reporting omitted clauses and state: 'unavailable' (with retryable) when the contract cannot be read; any other failure fails the call. Read it before implementing a ticket or project. These sidecars are large — bound the payload with include (attach only the named sidecars) or exclude (drop the named ones from the default set); pass include: [] for the core row alone, which also skips the graph reads entirely. Project the core row with fields (id/type/title always returned) — e.g. fields: ['state','closure_reason','archived_at'] for a lifecycle-only read or fields: ['owner_id'] for ownership, dropping the heavy content blob. The applied projection is echoed back in _projection. ArtifactReadNotFound carries details.recently_updated — the workspace's most-recently-updated artifacts as orientation, NOT a ranked match for the id you asked for (a UUID gives nothing to rank against).
Parameters
| Name | Type | Description |
|---|---|---|
id | string | null | Artifact UUID (canonical param — `artifact_id` is also accepted as an alias; provide exactly one) |
artifact_id | string | null | Alias for `id` — accepted for agent ergonomics; prefer `id` in new callers |
include | string[] | null | Attach ONLY these sidecars (subset selection). Allowed names: signals, external_references, owner, specifications. Omit for the first three (backward-compatible default); `specifications` is attached only when named here. `include: []` returns the core row with no sidecars and skips the graph reads. Mutually exclusive with `exclude`; unknown names return `validation_failed`. |
exclude | string[] | null | Drop these sidecars from the default full set (signals, external_references, owner) — e.g. `['external_references']` to skip the heaviest lookup. Mutually exclusive with `include`; unknown names return `validation_failed`. |
fields | string[] | null | Project the core row down to these fields; id/type/title/version_seq are always included. Allowed: quality, description, content, state, closure_reason, archived_at, priority, owner_id, created_at, updated_at. Omit for the full row. Drop `content` here when you only need metadata. Unknown names return `validation_failed`. |
List artifacts by attributes
artifacts_list Lists artifacts filtered by attributes such as type, state, and owner, newest first, with slim rows. To find artifacts by title or by meaning instead, use artifacts_search.
List artifacts by attributes
artifacts_list Lists artifacts filtered by attributes such as type, state, and owner, newest first, with slim rows. To find artifacts by title or by meaning instead, use artifacts_search.
List artifacts in the workspace, newest first; filters compose. Returns {items, meta} and pages with offset: meta.next_offset. Rows are slim by default (no content/drift, descriptions previewed at 280 chars, to stay under the response cap) — opt in via include (content, drift, description); meta.truncated_fields flags omitted fields. For content search use artifacts_search.
Parameters
| Name | Type | Description |
|---|---|---|
type | "mission" | "vision" | "strategy" | "goal" | "domain_model" | "persona" | "problem" | "requirement" | "project" | "architecture" | "story" | "ticket" | null | Filter by artifact type. Includes historical types, so you can list rows `artifacts_create` no longer admits. |
since | string | null | Only return artifacts with updated_at at or after this ISO-8601 timestamp |
text | string | null | Case-insensitive substring match against title and description only — not `content`. For semantic/content search use `artifacts_search`. |
state | "draft" | "backlog" | "todo" | "in_progress" | "in_review" | "active" | "closed" | "deprioritized" | null | Filter by unified lifecycle state — one of draft, backlog, todo, in_progress, in_review, active, closed, deprioritized. |
archived | boolean | null | Include archived artifacts in the result (default false; pass true to surface archived rows alongside non-archived). |
owner_id | string | null | null | Filter by owner. A UUID restricts to artifacts owned by that workspace member; `null` surfaces the unowned bucket; omit for no filter. Compose with state/type/text filters as usual. |
limit | integer | null | Max results (default: 50, max: 100) |
offset | integer | null | Page start over the filtered, newest-first result; continue from the previous response's `meta.next_offset`. |
include | "content" | "drift" | "description"[] | null | Optional fields to include in each row. Default omits all: rows are slim ({id, type, title, description (280-char preview; full length in `_field_stats.description_chars`), state, closure_reason, archived_at, role_tier, priority, owner_id, updated_at, version_seq (pass it to `artifacts_update` as `expected_version_seq`), quality (saved score summary or null), _field_stats, optional _owner}). Pass `['content']` to keep the full structured content JSON; `['drift']` to keep the `_drift_summary` sidecar; `['description']` for untruncated descriptions. Use sparingly — the slim default is what keeps large workspaces inside the response cap. |
Search artifacts by title and meaning
artifacts_search Finds artifacts by exact title and semantic similarity when you do not know the id. For attribute filters such as type or state use artifacts_list.
Search artifacts by title and meaning
artifacts_search Finds artifacts by exact title and semantic similarity when you do not know the id. For attribute filters such as type or state use artifacts_list.
Search workspace artifacts by exact title and semantic similarity. Exact-title matches rank first; meta reports ranking, degradation, and pagination, and meta.title_excluded lists exact-title matches left out (archived or a retired type) with the reason. Rows are slim by default ({id, type, state, title, description preview, similarity, matched}); pass include: ['content'] only when the structured artifact body is required. Continue from meta.next_offset. Archived artifacts are excluded, like every default grounding read; retrieve one by id with artifacts_get.
Parameters
| Name | Type | Description |
|---|---|---|
text | string | null | Search query (canonical param — `query` is also accepted as an alias; provide exactly one) |
query | string | null | Alias for `text` — accepted for agent ergonomics; prefer `text` in new callers |
limit | integer | null | Page size (default: 20, max: 50) |
offset | integer | null | Page start within the bounded ranked result set; continue from the previous response's `meta.next_offset`. |
include | "content" | "description"[] | null | Optional heavy fields to include in each row. Default omits all. Pass `['content']` for the full structured artifact body or `['description']` for untruncated descriptions. |
Update an artifact's parent
artifacts_set_parent Replaces an artifact's containment parent atomically, or clears it when parent_id is null. Prefer it over links_add, which appends a second parent edge rather than replacing the first.
Update an artifact's parent
artifacts_set_parent Replaces an artifact's containment parent atomically, or clears it when parent_id is null. Prefer it over links_add, which appends a second parent edge rather than replacing the first.
Set (or clear) an artifact's parent — the single-purpose re-parent intent with replace semantics: it atomically closes the child's existing active parent edge and opens the new one, enforcing a single parent. Pass parent_id: null to clear the parent (make the artifact a root). A wrong parent type returns the self-correcting invalid_parent_type envelope (as links_add / artifacts_create). Prefer this over links_add for re-parenting — links_add appends a parent edge (a child can accrue two), whereas this replaces. Returns { previousParentId, nextParentId } plus a _signals sidecar with Reconcile findings on the affected artifacts.
Parameters
| Name | Type | Description |
|---|---|---|
mutation_id | string | null | Deprecated and ignored. Writes no longer take an idempotency key. |
id | string | null | The child artifact UUID whose parent to set (canonical param — `artifact_id` is also accepted as an alias; provide exactly one) |
artifact_id | string | null | Alias for `id` — accepted for agent ergonomics; prefer `id` in new callers |
parent_id required | string | null | The new parent artifact UUID (replace semantics); pass `null` to clear the parent and make the artifact a root. Must be a valid parent type for the child, else `invalid_parent_type`. |
Rank candidate parents for orphans
artifacts_suggest_parents Ranks the type-valid parent candidates for the given orphaned artifacts by similarity. Attach the chosen parent with artifacts_set_parent or links_add.
Rank candidate parents for orphans
artifacts_suggest_parents Ranks the type-valid parent candidates for the given orphaned artifacts by similarity. Attach the chosen parent with artifacts_set_parent or links_add.
For each artifact in orphan_ids (up to 50), rank the live, type-valid parent candidates by exact cosine similarity to its stored embedding. Get orphan ids from workspace_audit (category orphans, each finding's artifact_id); the ids are not re-checked for orphan status, so any current artifact can be ranked. The whole batch is one graph read. Each row carries suggestions: [{ id, title, type, similarity }] (highest first) filtered to the type's valid parent tiers — link one with links_add or artifacts_set_parent. parent_tier_empty: true means the workspace holds no live artifact of any expected parent type: create that parent first. Every row also carries ranking, using the same vocabulary artifacts_search returns in meta: mode is semantic or unavailable, and ranking.degraded (code, failure_stage, retryable, recovery) is present only when the row could not be ranked because the artifact has no usable stored embedding yet (embedding stage). An empty suggestions list means the row needs manual placement ONLY when ranking.degraded is absent; otherwise retry later with the ids in recovery.args. An id that is not a current artifact in the workspace has no row. A graph failure fails the whole call with a retryable error. The candidate set, scoring, and ranking marker are shared with the create-time missing_parent nudge, so both surfaces stay consistent.
Parameters
| Name | Type | Description |
|---|---|---|
orphan_ids required | string[] | Artifacts to rank parents for (1 to 50), typically the orphan finding ids from workspace_audit. |
candidates_per_orphan | integer | null | Ranked candidates to return per artifact (default: 3, max: 10). |
Update one artifact, or a batch
artifacts_update Edits one existing artifact, or up to 50 through items: content, lifecycle state, archiving, ownership, and validation renewal. To make a new artifact use artifacts_create.
Update one artifact, or a batch
artifacts_update Edits one existing artifact, or up to 50 through items: content, lifecycle state, archiving, ownership, and validation renewal. To make a new artifact use artifacts_create.
The single tool for editing artifacts (only provided fields written): content, shelving (archived), lifecycle state, validation renewal (renew_validation), and a human-review audit event (flag_review). Call it in ONE of two forms: pass id plus the fields to change for one artifact, or pass items to update up to 50 in a single call. The two forms are exclusive: sending items together with any single-artifact field returns validation_failed, and so does sending neither. Single form: the response adds a _signals sidecar with the current findings naming this artifact, in the shape signals_list returns. Detection runs after the write commits, so findings this edit introduces appear on a later read. Scoped to this artifact only — _signals: [] is not a workspace all-clear; use Reconcile through signals_list for workspace findings. An agent-requested promotion of a strict-authority artifact whose premise has no human ratification is not applied directly: the call returns {kind:'proposal', proposal_id, proposal_url} (no fields written; a riding renew_validation/flag_review is skipped and listed in ignored_fields; repeat attempts return the same proposal) — hand the proposal_url to a human, who can Ratify & promote or Keep as draft. An agent edit to the title, description, or content of a ratified mission, vision, strategy, or domain model is also not applied directly: it returns the same {kind:'proposal'} shape, the live premise stays unchanged, and applying the proposal ratifies the new premise. Put your reasoning for the reviewer in rationale. The workspace singleton_write_policy set to yolo turns this review off. Version check: to avoid replacing an edit someone saved after your read, send expected_version_seq with the version_seq from artifacts_get or artifacts_list. If the artifact has a newer version, the call writes nothing and fails with ArtifactUpdateStaleBase; details.current_version_seq and details.current_updated_at name the newer version. Read the artifact again, merge your change into it, and retry with the new version_seq. The check covers changes that write a new version (title, description, content, priority, archived, state). owner_id, spec_clauses, renew_validation, and flag_review write no version, so a call that sends expected_version_seq with only those returns validation_failed. Without expected_version_seq, the last write wins. Batch form (items): update up to 50 artifacts in one call (fan-out bounded to 8 in-flight globally and 3 per shared non-null owner); each item is updated independently, so partial failures don't sink the batch. items is exclusive with the single-update fields — send one form or the other, never both, or the call returns validation_failed. Items may patch title, description, content, priority, owner_id, archived, and lifecycle state. Omitted priority is unchanged and null clears it. Each item may set its own expected_version_seq together with a change to title, description, content, priority, archived, or state (an item that changes only owner_id or spec_clauses fails with validation_failed, because those changes write no version): an item whose artifact has a newer version fails alone with ArtifactUpdateStaleBase and details.current_version_seq, and the other items still apply; read that artifact again and retry only that item. An agent-requested promotion of a strict-authority artifact whose premise has no human ratification, or an agent edit to the title, description, or content of a ratified mission, vision, strategy, or domain model, is not applied directly: that item returns {ok:true, proposal:{kind:'proposal', proposal_id, proposal_url}}, counted in summary.proposed rather than succeeded, and writes nothing; hand the proposal to a human reviewer, and put your reasoning in the item's rationale. Returns { results, summary } — UNLESS every item failed, in which case the call is a top-level error (isError) whose details.results carries the per-item errors, so a 0-succeeded batch is never reported as success. _signals are NOT computed per item — call signals_list after. A failed item's quality rejection carries only details.artifact_quality.{status, findings, suggestions?}; it has no error.message: each finding's rule id and reason are in findings, and suggestions holds up to three concrete fixes. Under the response cap, rows shed detail and _meta.degraded names what was dropped, but summary and each row's ok plus artifact id or error code always remain: read written items by id rather than retrying the batch. Emits notifications/progress when given a progress token.
Parameters
| Name | Type | Description |
|---|---|---|
mutation_id | string | null | Deprecated and ignored. Writes no longer take an idempotency key. |
id | string | null | Single form: artifact UUID (canonical param — `artifact_id` is also accepted as an alias; provide exactly one). Required there, and rejected alongside `items`. |
artifact_id | string | null | Alias for `id` — accepted for agent ergonomics; prefer `id` in new callers. |
expected_version_seq | integer | null | Optional. The `version_seq` you read with `artifacts_get` or `artifacts_list`. When set, the edit applies only if the artifact is still at that version. It needs a change to title, description, content, priority, archived, or state in the same update; owner_id and spec_clauses write no version, so a call that changes only them returns `validation_failed`. If someone saved a newer version, the edit writes nothing and fails with `ArtifactUpdateStaleBase`; its `details` carry `current_version_seq` and `current_updated_at`. Read the artifact again, merge your change, and retry with the new `version_seq`. Omit it to write without the check. |
items | object[] | null | Batch form: 1 to 50 update payloads, each carrying its own `id` and patched fields. Rejected alongside the single-artifact fields. |
title | string | null | New title |
description | string | null | Artifact narrative. Mission, vision, strategy, goal, persona, problem, project, and architecture descriptions support Markdown. Preserve explanatory prose and dated checkpoints here; use artifact links for relationships, spec_clauses for testable project or ticket requirements, and content only for declared structured fields. |
spec_clauses | string | object[] | null | Atomic, testable normative contract clauses for project or ticket artifacts (maximum 32 clauses). Accepts plain strings or objects with `{ statement, proposed_anchor_names }`. Each clause statement must be a single line containing exactly one canonical MUST or MUST NOT. Examples: ['The create handler MUST reject malformed identifiers', 'Closed artifacts MUST NOT accept new child links']. Pass proposed_anchor_names with the function or class names you plan to write or modify to link AST anchors. |
content | object | null | Type-specific structured fields. Call `artifact_types` first and use only its declared keys and value shapes. Scalar `textarea` strings render Markdown; use it when headings, lists, links, quotes, or fenced code improve readability, and use Markdown instead of raw HTML because raw HTML is escaped. For `textarea` fields with `array: true`, send one item per `string[]` element and keep Markdown inline within each item—do not include list markers. `text`, `select`, `date`, and `number` fields are plain values and should not contain Markdown. |
priority | "critical" | "high" | "medium" | "low" | null | null | Priority — pass null to clear; omit to leave unchanged |
owner_id | string | null | null | Re-assign the owner: a UUID re-owns to that workspace member (must be a member, else `validation_failed`); null clears ownership; omit to leave unchanged. Emits an `owner_changed` history event. |
archived | boolean | null | Shelve (`true`) or unshelve (`false`) the artifact — sets/clears `archived_at`, orthogonal to `state`. Omit to leave unchanged. Archived rows are hidden from default `artifacts_list` (pass `archived: true` there to see them). |
state | "draft" | "backlog" | "todo" | "in_progress" | "in_review" | "active" | "closed" | null | Move the artifact through its lifecycle — one of draft, backlog, todo, in_progress, in_review, active, closed. Per-tier scoped (a mission can't be `backlog`). Omit to leave unchanged. |
closure_reason | "completed" | "abandoned" | "obsolete" | "migrated" | "duplicate" | null | Why it closed (only valid with `state: 'closed'`; defaults to 'completed'). Cleared automatically on any non-closed state. |
closure_successor_id | string | null | The canonical artifact this one is being folded into, when closing as a duplicate or migrated artifact. Must be a real artifact in the workspace (not this one). The close records the fold onto the successor. Ignored on other closures. |
renew_validation | boolean | null | Pass `true` to renew validation of the current premise only. It requires an existing current ratification and updates the derived `last_reviewed_at` and `reviewed_by` fields; it never ratifies or changes authority. Use the explicit ratification action to Ratify or Re-ratify a premise. (Trigger-fired drift findings keep their own dismiss path.) |
mark_reviewed | boolean | null | Deprecated alias of `renew_validation`. Use `renew_validation`. |
review_note | string | null | Optional operator note recorded with the validation renewal (`renew_validation`). |
flag_review | boolean | null | Pass `true` to record a human-review request as an audit event. It stores no review state: the call emits a `drift_flagged` log line and returns the artifact unchanged, so no tool reads the request back and nothing has to clear it. Mutually exclusive with `renew_validation` on the same call. |
evaluate | boolean | null | Pass `false` to skip the background semantic quality recheck after a content change. Ignored where quality grading is mandatory. |
rationale | string | null | Your note to the human reviewer: why this edit is needed, its sources, and caveats. Shown beside the proposal when the edit needs human review, such as an edit to the premise of a ratified mission, vision, strategy, or domain model; never saved into the artifact. |
Get an artifact's ancestors and descendants
chain_get Returns one artifact's containment ancestors and descendants as a single tree, for grounding or subtree work. Non-containment edges are not traversed; list those with links_list.
Get an artifact's ancestors and descendants
chain_get Returns one artifact's containment ancestors and descendants as a single tree, for grounding or subtree work. Non-containment edges are not traversed; list those with links_list.
The full context chain for an artifact (ancestors ← current → descendants); each node carries state/closure_reason. Current chains exclude archived artifacts. Pass as_of only when you need the auditable historical chain. On launch-scale graphs, don't pull the whole tree: pass shape:'slim' (drops titles/state/drift/edges), and scope with direction (ancestors for grounding, descendants for subtree work), max_depth (1 = parents + direct children), and types. Every response carries meta with pre-filter totals (total_nodes/ancestors/descendants), matched, truncated, and next_offset — page with offset until next_offset is null. Safe pattern for big projects: {shape:'slim', direction:'descendants', max_depth:1} first, then drill into one child. Default page size 200, max 500. Pass as_of (ISO-8601) to reconstruct the chain as it stood at that instant from artifact version history; historical chains return undecorated nodes (no drift/edge sidecars).
Parameters
| Name | Type | Description |
|---|---|---|
id | string | null | Artifact UUID (canonical param — `artifact_id` is also accepted as an alias; provide exactly one) |
artifact_id | string | null | Alias for `id` — accepted for agent ergonomics; prefer `id` in new callers |
shape | "full" | "slim" | null | `full` (default) returns each node's full row plus drift sidecars and edges; `slim` returns only `{id, type_id, depth}` per node and skips drift/edge decoration entirely — the fast, cap-safe shape for deep chains. |
direction | "both" | "ancestors" | "descendants" | null | Walk direction relative to the artifact (default `both`). `ancestors` answers "what does this serve"; `descendants` answers "what's underneath". The artifact itself is always included. |
max_depth | integer | null | Keep only nodes within this distance (1 = parent + direct children). Combine with `direction:'descendants'` for a children summary. |
types | string[] | null | Keep only these artifact types (e.g. ['story','ticket']). The anchor artifact is always kept. |
limit | integer | null | Page size over the filtered chain (default 200). |
offset | integer | null | Page start; continue from the previous response's `meta.next_offset`. |
as_of | string | null | Reconstruct the chain as of this ISO-8601 instant from the artifact's version history (validity-window read). Historical chains return undecorated nodes — no drift summaries or edge alignment sidecars, since those describe current state. |
Get an artifact's demand context
demand_context_get Resolves the effective serves and addresses relationships for one artifact, inherited ones included. For containment ancestors and descendants use chain_get instead.
Get an artifact's demand context
demand_context_get Resolves the effective serves and addresses relationships for one artifact, inherited ones included. For containment ancestors and descendants use chain_get instead.
Resolve effective serves and addresses context for one artifact. For a project, requirement, or story, outgoing contains the active personas/problems it reaches directly or through containment ancestors. For a persona/problem, incoming contains the execution artifacts covered by each direct semantic relationship, including inherited descendants. Every item reports direct, declaredAt, and inheritedDepth so provenance is explicit. This does not alter chain_get: demand relationships remain non-containment.
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Artifact UUID whose effective demand context to resolve |
limit | integer | null | Maximum relationships to return (default 200, maximum 500) |
Get documentation, or list what is documented
docs_get Returns the canonical documentation for one check kind, metric, error code, or topic with its full text inline. Call it with no arguments for the index of everything documented.
Get documentation, or list what is documented
docs_get Returns the canonical documentation for one check kind, metric, error code, or topic with its full text inline. Call it with no arguments for the index of everything documented.
Fetch the canonical Helen’s Foundry documentation, in either of two forms. Pass exactly one of check (a reconcile check kind), metric (an Insights metric id), error (an MCP error code), or topic (an inline guide or reference) to get back { title, url, body } for that concept, with the full doc text inline in body (no fetch of url required). Call it with NO arguments to get the index instead: every documentable check, metric, error code, and topic, each with its title and canonical URL, so you can discover what to ask for. Passing more than one concept is rejected with validation_failed.
Parameters
| Name | Type | Description |
|---|---|---|
check | "artifact_quality" | "review_cadence_breach" | "stale_premise" | "semantic_contradiction" | "chain_contradiction" | "copy_paste_cascade" | "portfolio_distribution_anomaly" | "stale_draft" | "singleton_conflict" | "priority_vacuum" | "unowned_in_flight" | "lifecycle_contradiction" | "capability_presupposition" | "orphaned_metric" | "no_prime_goal" | "decomposition_gap" | "coverage_gap" | "plan_of_record_staleness" | "redundant_overlap" | "zombie_project" | "lifecycle_inconsistency" | "stranded_by_closure" | "accountable_owner_missing" | "horizontal_incoherence" | "execution_context_gap" | "coordination_collision" | "resource_misallocation" | null | A reconcile check kind; returns what trips it and what to do. |
metric | "alignment" | "delivery-flow" | "quality" | null | An Insights dashboard metric id; returns its definition. |
error | "validation_failed" | "artifact_not_found" | "invalid_parent_type" | "gateway_unavailable" | "internal_error" | "datastore_degraded" | "user_declined" | "workspace_membership_missing" | "response_too_large" | "rate_limited" | "stale_base" | "workspace_not_found" | "edge_side_effect_failed" | "capability_restricted" | "workspace_read_only" | null | An MCP error code; returns what it means and how to recover. |
topic | "getting-started" | "checks" | "reconcile" | "authoring" | "acceptance-criteria" | "edge-kinds" | null | An inline guide or reference. Start with `getting-started` on a workspace you have not worked in before: it is the sequence from a fresh connection to a ratified foundation. Others: `checks`, `reconcile`, `authoring`, `acceptance-criteria`, `edge-kinds`. |
List external references for artifact
external_references_list Lists the external entities, such as pull requests and issues, attached to one artifact. For the workspace-wide inbox of arrivals use workspace_external_references_list.
List external references for artifact
external_references_list Lists the external entities, such as pull requests and issues, attached to one artifact. For the workspace-wide inbox of arrivals use workspace_external_references_list.
See which external entities (PRs, GitHub/Linear issues) are attached to an artifact — "where else does this live?" before closing a ticket or triaging drift. Distinct from the context chain (chain_get); this returns artifact↔external edges, newest-first.
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Artifact UUID to look up |
source | string | null | Optional exact source filter (case-sensitive lowercase snake_case), e.g. `github_pr`, `linear_issue`, `sentry_issue`. |
Link artifacts, one pair or a batch
links_add Creates directed edges between artifacts, one pair or up to 50, choosing parent, references, supersedes, depends_on, serves, or addresses. To re-parent, use artifacts_set_parent.
Link artifacts, one pair or a batch
links_add Creates directed edges between artifacts, one pair or up to 50, choosing parent, references, supersedes, depends_on, serves, or addresses. To re-parent, use artifacts_set_parent.
Create directed edges between artifacts; kind selects the edge type. Call it in ONE of two forms: pass source_id + target_id for a single edge, or pass pairs for up to 50 edges in one call. Sending both forms, or neither, returns validation_failed. parent (default): containment parent to child, traversed by chain_get. Adding a parent link validates the child's allowedParentTypes; a wrong type returns the self-correcting invalid_parent_type envelope (as artifacts_create). references: non-containment typed reference, any artifact to any, ignored by chain_get. supersedes: non-containment, source replaces target, ignored by chain_get. Creating a supersedes edge also closes its target (closure_reason='obsolete', reported as _superseded_target_closed), idempotently and self-healingly: a retry completes a close a prior call left undone, and an already-closed target is never re-closed. depends_on: non-containment, source depends on target, ignored by chain_get. serves: non-containment project/requirement/story to persona relationship. addresses: non-containment project/requirement/story to problem relationship. Full rules for each kind: docs_get({ topic: 'edge-kinds' }). Idempotent for every kind: re-adding returns the existing edge with _already_existed: true and no new history. The single form returns the edge plus a _signals sidecar with Reconcile findings on both endpoints, in the signals_list shape; _signals: [] means none on these two artifacts, not a workspace all-clear. The pairs form bounds fan-out to 8 writes in flight globally and 1 per shared source or target, runs each pair through the same path independently (partial failures don't sink the batch), and applies kind (or per-pair kind) to each pair. It returns { results, summary } with per-item ok/error, where summary is { total, succeeded, failed, partial, unknown }: partial counts a persisted primary edge with a side-effect outstanding, and unknown counts a bounded readback that could not prove whether the edge landed, so neither is mislabeled as a hard failure. If every pair is a definite hard failure the call is a top-level error whose details retain all per-item results. Per-item _signals are NOT attached in the pairs form (it would be one signals_list query per item) — run signals_list after the batch to see the findings introduced. The pairs form emits notifications/progress when given a progress token. To re-parent an artifact (replace its current parent), use artifacts_set_parent — this tool with kind='parent' appends a parent edge, so a child can accrue more than one.
Parameters
| Name | Type | Description |
|---|---|---|
mutation_id | string | null | Deprecated and ignored. Writes no longer take an idempotency key. |
source_id | string | null | Single-edge form: source artifact UUID — the `source` endpoint. Required with `target_id`, and rejected alongside `pairs`. |
target_id | string | null | Single-edge form: target artifact UUID — the `target` endpoint. Required with `source_id`, and rejected alongside `pairs`. |
pairs | object[] | null | Batch form: 1 to 50 source/target UUID pairs, each optionally carrying its own `kind`. Rejected alongside `source_id`/`target_id`. |
kind | "parent" | "references" | "supersedes" | "depends_on" | "serves" | "addresses" | — |
List artifact links
links_list Lists directed edges of one kind with the type and title of both endpoints, including the non-containment kinds that chain_get never traverses.
List artifact links
links_list Lists directed edges of one kind with the type and title of both endpoints, including the non-containment kinds that chain_get never traverses.
List directed edges between artifacts, each row enriched with the type + title of both endpoints (no follow-up artifacts_get needed). kind selects which edge set; non-containment kinds are absent from chain_get by construction. Every edge points source to target; a parent edge points from the parent to the child, and there is no separate child kind. parent (default): containment parent to child, traversed by chain_get. references: non-containment typed reference, any artifact to any, ignored by chain_get. supersedes: non-containment, source replaces target, ignored by chain_get. depends_on: non-containment, source depends on target, ignored by chain_get. serves: non-containment project/requirement/story to persona relationship. addresses: non-containment project/requirement/story to problem relationship. Full rules for each kind: docs_get({ topic: 'edge-kinds' }). Pass artifact_id to scope to edges touching that artifact; omit it for the workspace-wide edge set. A scoped row adds direction (outgoing when the artifact is the source, incoming when it is the target) and other_id/other_type/other_title for the endpoint that is not the artifact; read those instead of target_*, which names the artifact itself on an incoming edge. direction:'outgoing' keeps only edges from the artifact (for parent: its children), direction:'incoming' only edges to it (for parent: its parent). Returns { links, kind, meta }. Paging: repeat the call with offset: meta.next_offset until it is null; that reads every edge exactly once. A page can end early, with meta.truncated: true, because of limit or because the response reached its byte cap (meta.truncated_reason), and can hold fewer rows than limit while edges remain: meta.skipped counts edges dropped in the window because an endpoint is no longer a current artifact. Only next_offset tells you whether more edges exist. shape:'slim' drops the endpoint titles (keeps ids + types) so pages hold more rows; re-fetch a title with artifacts_get when you need it.
Parameters
| Name | Type | Description |
|---|---|---|
artifact_id | string | null | Scope to edges where this artifact is the source OR the target. Omit for the full workspace edge set. |
direction | "both" | "outgoing" | "incoming" | null | Requires `artifact_id`. `outgoing`: edges whose source is the artifact (for `parent`: its children). `incoming`: edges whose target is the artifact (for `parent`: its parent). `both` (default): either side. |
kind | "parent" | "references" | "supersedes" | "depends_on" | "serves" | "addresses" | — |
limit | integer | null | Max edges to scan into one page (default 100, max 500). A page can return fewer rows; continue while `meta.next_offset` is not null. |
offset | integer | null | Page start over the `created_at`-ordered edge set. Pass the previous response's `meta.next_offset`; do not compute it from the row count. |
shape | "full" | "slim" | null | `full` (default) returns each edge with endpoint types AND titles; `slim` drops the titles ({source_id, target_id, source_type, target_type, created_at}) so a wide edge dump stays under the response cap. |
Unlink artifacts, one pair or a batch
links_remove Removes directed edges of one kind, one pair or up to 50, and is safe to repeat. To clear an artifact's parent without naming the exact edge, use artifacts_set_parent with a null parent.
Unlink artifacts, one pair or a batch
links_remove Removes directed edges of one kind, one pair or up to 50, and is safe to repeat. To clear an artifact's parent without naming the exact edge, use artifacts_set_parent with a null parent.
Remove directed edges (one direction each); kind must match the edges you created. Call it in ONE of two forms: pass source_id + target_id for a single edge, or pass pairs for up to 50 edges in one call. Sending both forms, or neither, returns validation_failed. Removing a supersedes edge does not re-open the superseded target — un-superseding a target's lifecycle is a separate, explicit state change (artifacts_update). parent (default): containment parent to child, traversed by chain_get. references: non-containment typed reference, any artifact to any, ignored by chain_get. supersedes: non-containment, source replaces target, ignored by chain_get. depends_on: non-containment, source depends on target, ignored by chain_get. serves: non-containment project/requirement/story to persona relationship. addresses: non-containment project/requirement/story to problem relationship. Full rules for each kind: docs_get({ topic: 'edge-kinds' }). Idempotent: removing a missing edge returns { deleted: 0, _already_absent: true }. The single form returns { deleted, _already_absent? } plus a _signals sidecar with Reconcile findings on both endpoints. The pairs form bounds fan-out to 8 writes in flight globally and 1 per shared source or target, runs each pair through the same path independently and idempotently, and applies kind to every pair. It returns { results, summary } with per-item ok/error, where summary is { total, succeeded, failed, unknown }: an _already_absent no-op counts as succeeded, and unknown means bounded exact readback could not prove the removal, so it is not mislabeled as a definite failure. Per-item _signals are NOT attached in the pairs form (run signals_list after), and that form emits notifications/progress when given a progress token. To clear an artifact's parent entirely (rather than a specific known edge), prefer artifacts_set_parent({ parent_id: null }).
Parameters
| Name | Type | Description |
|---|---|---|
mutation_id | string | null | Deprecated and ignored. Writes no longer take an idempotency key. |
source_id | string | null | Single-edge form: source artifact UUID — the `source` endpoint. Required with `target_id`, and rejected alongside `pairs`. |
target_id | string | null | Single-edge form: target artifact UUID — the `target` endpoint. Required with `source_id`, and rejected alongside `pairs`. |
pairs | object[] | null | Batch form: 1 to 50 source/target UUID pairs. Rejected alongside `source_id`/`target_id`. |
kind | "parent" | "references" | "supersedes" | "depends_on" | "serves" | "addresses" | — |
List workspace members
members_list Lists the workspace members with their ids and roles and marks the calling principal. Use an id from here as owner_id when calling artifacts_create or artifacts_update.
List workspace members
members_list Lists the workspace members with their ids and roles and marks the calling principal. Use an id from here as owner_id when calling artifacts_create or artifacts_update.
List the members of the caller's workspace as {id, display_name, role, is_current}[]. id is the member's user id — pass it as owner_id to artifacts_create / artifacts_update, or as the owner_id filter on artifacts_list. display_name is null when a member has no profile row yet (new auth user, race with profile insert). is_current marks the row that is the CALLING principal — the canonical id to self-assign ownership with. The envelope also carries current_user_id (the caller's canonical id) and, when two or more members share a display_name, duplicate_display_names: [{display_name, ids}] so a duplicate identity (a second :User created via Clerk email-linking / JIT) is explained rather than read as two distinct people — write to the is_current id. Stable ordering: named members alphabetical first, then unnamed.
Parameters
No parameters.
Propose a change
pending_actions_create Files a proposed change for human review without applying it, validating the payload now. Give the returned proposal link to a person, who applies or declines it in the app.
Propose a change
pending_actions_create Files a proposed change for human review without applying it, validating the payload now. Give the returned proposal link to a person, who applies or declines it in the app.
File a proposed change WITHOUT applying it. Only a person can apply or decline it, in the app; no agent credential can decide it. When a person applies it, the change replays under this principal's identity. The payload is validated now, not just at decide time. Returns the queued proposal for review in the activity feed; give its link to a person.
Parameters
| Name | Type | Description |
|---|---|---|
action_type required | "artifacts_create" | "artifacts_update" | "artifacts_set_status" | "links_add" | The proposed-change variant that will be replayed when applied |
payload required | object | The exact tool input that will be replayed when applied. Shape must match action_type (e.g. artifacts_update needs payload.id). |
scope | object | null | Originating-context metadata routed back to confirmations. Slack/Discord channel arms carry thread metadata; github carries PR routing. Extra keys allowed for future origins. Defaults to {} (no origin context). |
List proposed changes
pending_actions_list Lists proposed-change queue rows, newest first and pending by default, with the proposer and a preview of the effects. Only a person applies or declines a row, in the app.
List proposed changes
pending_actions_list Lists proposed-change queue rows, newest first and pending by default, with the proposer and a preview of the effects. Only a person applies or declines a row, in the app.
List proposed-change queue rows (newest first). Returns {items, meta}; page with offset: meta.next_offset until it is null. Defaults to status='pending'; pass status for another bucket. Each row carries the proposer's credential kind/id so reviewers can see who proposed it, and a preview of the predicted side effects when one was captured.
Parameters
| Name | Type | Description |
|---|---|---|
status | "pending" | "approved" | "declined" | "expired" | "executed" | "failed" | null | Lifecycle status to filter on (default: 'pending') |
since | string | null | Only items at or after this ISO-8601 timestamp |
action_type | "artifacts_create" | "artifacts_update" | "artifacts_set_status" | "links_add" | null | Narrow to one proposed-action variant |
limit | integer | null | Max items (default: 50, max: 200) |
offset | integer | null | Page start over newest-first proposed changes; continue from `meta.next_offset`. |
Get the stored PR evaluation report
pr_report_get Returns the stored evaluation report for one pull request as typed JSON, so an agent need not scrape the posted comment. For workspace detector findings use signals_list.
Get the stored PR evaluation report
pr_report_get Returns the stored evaluation report for one pull request as typed JSON, so an agent need not scrape the posted comment. For workspace detector findings use signals_list.
The exact evaluation Helen’s Foundry produced the last time it dispatched for a pull request, as typed JSON — the same versioned report model that renders the sticky GitHub comment and the hf.dev check report page. Reach for it when an agent needs that evaluation (Agent Helen code review, governance authority, reviewer health, drift) and would otherwise scrape the comment. The read is scoped to the caller's own workspace, which comes from the credential, not from an argument: a pull request evaluated only in some other workspace reads as absent, and no other tenant's report is reachable. Every outcome is a named status rather than an error. ready returns the full report in snapshot. legacy_version identifies a version-1 report that lacks a safe v2 decision migration. unsupported_version identifies a newer report and returns schema_version. malformed failed the stored-report contract. inaccessible means the store did not answer or the report object is gone. Only inaccessible can improve without a new dispatch. When the report names an unsatisfied link, link_guidance states the pull-request marker syntax that clears it, with an example. It is null in every other state. Staleness is explicit. snapshot_head_sha is the evaluated head. observed_head_sha is the newest dispatched head. stale: true means the commit or PR details changed after the report. Re-read after the next dispatch. Limits: this report is dispatch-time and read-only. It does not recompute current artifact state, gate work, or publish. Non-ready states carry a null snapshot and null heads. A report too large to return inline comes back as response_too_large with the check report URL.
Parameters
| Name | Type | Description |
|---|---|---|
owner required | string | GitHub owner (user or organization) of the repository, e.g. `acme` in `acme/widgets#938`. |
repo required | string | GitHub repository name without the owner prefix, e.g. `widgets` in `acme/widgets#938`. |
pr_number required | integer | Pull request number as GitHub shows it, e.g. `938` — a positive integer. |
Decide or rate findings, one or many
reconcile Dismisses, acknowledges, or rates detector findings, one or up to 50 at once. It is the write side of the findings workbench, and signals_list is the matching read.
Decide or rate findings, one or many
reconcile Dismisses, acknowledges, or rates detector findings, one or up to 50 at once. It is the write side of the findings workbench, and signals_list is the matching read.
Act on detector findings from signals_list. Call it in ONE of two forms. Single form: pass id plus at least one of disposition and rating. disposition:'dismiss' is terminal — the "not actionable" verdict, recording the optional reason and writing the dismissal suppression so the finding stops re-firing; disposition:'acknowledge' records that the finding was seen and leaves it open until the detector no longer finds the condition. Disposition is idempotent: re-disposing an already-terminal row returns it unchanged. rating is structured quality feedback (useful = surfaced a real problem; not_useful = technically correct but not actionable; wrong_evidence = the evidence misrepresents the situation, a detector bug) that feeds the per-kind precision report and the weighted evaluation corpus. Rating is append-only, so re-rating the same finding inserts a new history row rather than replacing one, and it does NOT by itself change the finding's lifecycle — the detector stays the source of truth. Sending both rates first and then disposes, and returns the disposition payload with the rating row on a _rating sidecar. Instead of an explicit disposition, a negative rating can carry dispose: true to dismiss through the same suppression path; that flag applies only when no disposition is given, and is ignored for useful. Batch form: pass items to dispose (and optionally rate) up to 50 findings in one call. Each item is { id, disposition, rating?, reason?, note?, idempotency_key? } and is handled independently, so partial failures don't sink the batch; every item reuses the single-finding paths, preserving idempotency and rating history. It returns { results, summary }: per-item { ok, id, ... } plus { total, succeeded, failed }, and emits notifications/progress when given a progress token. The two forms are exclusive: sending items alongside any single-finding field returns validation_failed, and so does sending neither. Set submission_mode:'replay' in either form when reproducing prior judgments rather than making new ones.
Parameters
| Name | Type | Description |
|---|---|---|
id | string | null | Single form: finding UUID (the `id` from a signals_list row). Required there, and rejected alongside `items`. |
disposition | "acknowledge" | "dismiss" | null | Single form: "acknowledge" = seen (flag); "dismiss" = terminal. Required unless `rating` is given, and rejected alongside `items`. |
rating | "useful" | "not_useful" | "wrong_evidence" | null | Single form: `useful` = the finding surfaced a real problem; `not_useful` = technically correct but not actionable; `wrong_evidence` = the evidence misrepresents the situation (detector bug). Required unless `disposition` is given, and rejected alongside `items`. |
reason | string | null | Single form: dismiss-only on-record explanation; ignored for acknowledge. Rejected alongside `items`. |
note | string | null | Single form: optional free-text note explaining the `rating`. Rejected alongside `items`. |
idempotency_key | string | null | Single form: caller-generated UUID for retrying one logical rating submission. Reuse it after a timeout to avoid a duplicate history row; generate a new UUID for a later intentional rating. Rejected alongside `items`. |
dispose | boolean | null | Single form: when true and the `rating` is negative, also dismiss the finding (writing the dismissal suppression so it stops re-firing). Ignored for `useful`, and ignored when an explicit `disposition` is given. Best-effort: the rating lands regardless; the result's `disposed` reports whether the dismiss happened. Rejected alongside `items`. |
submission_mode | "replay" | null | Set to `replay` only when the ratings reproduce prior judgments. Omit for a new judgment. |
items | object[] | null | Batch form: 1 to 50 disposition payloads. Rejected alongside the single-finding fields. |
Send product feedback
send_feedback Sends product feedback about this server and the product behind it, covering friction, bugs, and ideas. It is not a workspace write; artifacts still go through artifacts_create.
Send product feedback
send_feedback Sends product feedback about this server and the product behind it, covering friction, bugs, and ideas. It is not a workspace write; artifacts still go through artifacts_create.
Send product feedback capturing friction, bugs, or feature ideas relating to this MCP server and the underlying product. For dispatcher feedback, include relevant artifact, request, signal, check, or tool identifiers and compact structured fields.
Parameters
| Name | Type | Description |
|---|---|---|
body required | string | — |
category | "bug" | "feature_request" | "usability" | "documentation" | "praise" | "other" | null | Optional rough bucket. |
List canonical finding members
signal_members_list Pages the complete canonical member set of one query-backed finding. Use it when the bounded subject witnesses that signals_list shows on a row are not enough; it is read-only.
List canonical finding members
signal_members_list Pages the complete canonical member set of one query-backed finding. Use it when the bounded subject witnesses that signals_list shows on a row are not enough; it is read-only.
Page the current canonical members of a query-backed finding. ABOUT subjects in signals_list are bounded display witnesses, not this membership.
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Query-backed finding UUID |
after_id | string | null | Continue after this member id |
page_size | integer | null | Members per page; default 50 |
List Reconcile findings
signals_list Lists the current detector findings, newest first, each with a recommended action to address it. It is read-only: dismiss, acknowledge, or rate a row with reconcile.
List Reconcile findings
signals_list Lists the current detector findings, newest first, each with a recommended action to address it. It is read-only: dismiss, acknowledge, or rate a row with reconcile.
Reconcile is the workbench for current detector findings, newest-first. The returned source:'conflict' is a legacy wire value and does not mean every finding is a genuine incompatibility. Returns {items, meta}; limit is 1–50 (default 50) so a bare call stays under the response cap — page older findings with offset, and meta.matched can exceed meta.returned. Default shape:'slim' is the cap-safe routing shape: it drops evidence entirely and caps subjects at 5 per row, adding subjects_returned, subjects_omitted_at_least, subjects_truncated, and subjects_refetch (meta.subjects is bounded). The slim cap composes with kind-specific canonical bounds while preserving their total omitted count and refetch path; shape:'full' preserves the canonical bound. Explanation fields are kind-specific in both shapes: summary is currently always null; rationale and confidence are non-null only for LLM-adjudicated semantic and property kinds (for example orphaned_metric) and are null for deterministic kinds. presentation is also kind-specific: it is non-null only for portfolio_distribution_anomaly rows with recognized evidence and is null otherwise. Slim is insufficient for evidence-based review of deterministic findings; refetch with shape:'full' to inspect evidence. Full adds evidence but does not otherwise populate null explanation fields. meta.subjects reports whether every subject is present or a canonical bound remains. A non-null presentation provides group_key, group_label, and facet_label so clients can show related rows in one chassis without merging their ids or actions. Each row carries recommended_action: {tool, args, fill?, description} — the MCP verb that addresses that finding, with the subject artifact id pre-filled in args for direct verbs; a pending_actions_create action instead names the id in its description for the payload you fill; null for kinds without a safe deterministic verb (use reconcile to acknowledge, dismiss, or rate it). When fill is present the agent must ADD that key to args with a value of its choosing — the key is deliberately omitted so a verbatim call fails the tool's validation loudly instead of silently no-opping. Read-only — act on a row with reconcile (id plus a disposition and/or rating) or the recommended_action tool.
Parameters
| Name | Type | Description |
|---|---|---|
artifact_id | string | null | Restrict to findings touching this artifact |
limit | integer | null | Page size, newest findings kept (1–50, default 50). Page older findings with `offset`. |
offset | integer | null | Page start over newest-first findings; continue from `meta.next_offset`. |
shape | "slim" | "full" | null | `slim` (default) omits evidence and caps `subjects` at 5 per row, composing with canonical kind-specific bounds and preserving their omission metadata; `full` includes evidence and preserves the canonical bound. |
Audit workspace health
workspace_audit Reports severity-grouped workspace health findings such as orphans, duplicates, and lifecycle inconsistencies. For the detector findings on individual artifacts use signals_list.
Audit workspace health
workspace_audit Reports severity-grouped workspace health findings such as orphans, duplicates, and lifecycle inconsistencies. For the detector findings on individual artifacts use signals_list.
Use for "what's wrong with this workspace?" or after a bulk import. Returns severity-grouped findings for orphans, duplicates, lifecycle inconsistencies, unowned in-flight execution work, and stale strict-authority drafts, each with an optional recommended_action: {tool, args}. Every advertised category runs a real detector; findings are capped and severity-ordered. On large workspaces use grouped mode (group: true) — lifecycle findings batch by closed parent, orphans by expected parent type, and unowned or stale-draft findings into one group, with full counts + ≤3 representatives — and page with offset: meta.next_offset until it is null (summary.total can exceed meta.returned). After a response_too_large, retry with group: true, a narrower categories, a lower findings_limit, or include_sidecars: false (drops the _schema_drift / _detector_precision blobs). Schema drift is opt-in: pass categories: ['schema_drift'] to get the _schema_drift sidecar (compact rows grouped by artifact type + unknown key, with count, top 3 examples, and status: 'legacy_alias' | 'unknown'). Category-scoped audits that omit schema_drift never attach the sidecar, so legacy drift rows cannot dominate a targeted call. Partial results are explicit: summary.by_category is null for any category that did not run (not requested, or its detector failed) and a number only when the detector ran, so a 0 is a real all-clear; summary.category_status and meta.failed_categories name the categories that failed, and one failing detector never discards the categories that succeeded. In grouped mode the rows live in groups and findings carries only ungroupable rows — read meta.returned_collection with meta.returned_groups / meta.returned_findings to see what meta.returned counted.
Parameters
| Name | Type | Description |
|---|---|---|
scope_artifact_id | string | null | Narrow audit to this artifact (descendant filtering pending) |
categories | "orphans" | "duplicates" | "lifecycle_inconsistencies" | "unowned_execution_artifacts" | "stale_drafts" | "schema_drift"[] | null | Subset of categories to run; default all. Findings: orphans, duplicates, lifecycle_inconsistencies, unowned_execution_artifacts, stale_drafts. schema_drift is opt-in: populates the _schema_drift sidecar; omitted from targeted calls by default to prevent legacy drift rows from dominating a category-scoped response. |
stale_draft_days | integer | null | Age threshold for stale_drafts findings (default: 30 days). |
severity_floor | "info" | "warn" | "error" | null | Drop findings below this severity (default: warn) |
findings_limit | integer | null | Max findings to return (default: 200, max: 500). The pre-cap count stays available in `summary.total` so callers can see what was dropped. |
offset | integer | null | Page start over the sorted findings (or groups); continue from the previous response's `meta.next_offset`. |
group | boolean | null | Compact mode: batch lifecycle findings by closed parent, orphans by expected parent type, and unowned execution work into one ownership group — full counts, ≤3 representative children, recommended action stated once per group. The cap-safe shape for batch triage on large workspaces. |
include_sidecars | boolean | null | Pass false to skip the `_schema_drift` / `_detector_precision` sidecars (their bytes and their queries) — useful when paging findings or after a response_too_large. |
Get workspace external reference
workspace_external_reference_get Reads one workspace external reference by id, including the body that list reads omit. Find the id first with workspace_external_references_list.
Get workspace external reference
workspace_external_reference_get Reads one workspace external reference by id, including the body that list reads omit. Find the id first with workspace_external_references_list.
Read one authorized workspace external reference by ID, whichever source it came from: the source policy is resolved from the stored reference, not from a parameter. The active workspace comes only from the authenticated request context; callers cannot select another workspace, and a reference in another workspace reads as not found. A feedback-source reference returns its source-policy presentation with bounded body content and attachment IDs, never raw persistence fields. An imported GitHub issue returns the issue projection plus its stored body and a body_state that separates a body that loaded from one that was never stored and one that could not be read. This is the only read that resolves a body, which is why workspace_external_references_list omits it.
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | External reference UUID to read, from any workspace inbox source. |
List workspace external references
workspace_external_references_list Lists the workspace-wide external-reference inbox for one source, newest first, unattached rows included. For the references on a single artifact use external_references_list.
List workspace external references
workspace_external_references_list Lists the workspace-wide external-reference inbox for one source, newest first, unattached rows included. For the references on a single artifact use external_references_list.
List the authorized workspace-wide external-reference inbox for one source, newest first. This is distinct from external_references_list, which starts from one artifact. Returns safe presentation rows as {items, meta: {next_continuation}}; raw persistence fields are omitted. Repeat the same source and attachment with continuation: meta.next_continuation until it is null; a continuation is only valid against the source and attachment that produced it. source: 'github_issue' lists this workspace's imported GitHub issues, newest capture first, including issues with no artifact relationship, which every artifact-scoped read misses: a repository import records an issue whether or not its body carried an artifact URL, so use attachment: 'unattached' to triage what arrived unlinked. Bodies are omitted from every source here; read one with workspace_external_reference_get. Each source keeps its own row projection, so branch on source when reading items, and its own default page size (50 for feedback, 25 for GitHub issues).
Parameters
| Name | Type | Description |
|---|---|---|
source required | "mcp_send_feedback" | "github_issue" | Required inbox source. Use `github_issue` for imported GitHub issues; any other value selects that feedback source's inbox policy. |
attachment | "any" | "attached" | "unattached" | null | Attachment filter: any (default), attached to at least one artifact, or unattached. Attached and unattached never overlap. |
limit | integer | null | Max items. Defaults to 50 for a feedback source and 25 for `github_issue`; the ceiling is 100 for a feedback source and 100 for `github_issue`. |
continuation | string | null | Opaque page continuation from `meta.next_continuation`; repeat the same source and attachment. |
Get workspace summary stats
workspace_summary One-call session bootstrap: workspace metadata, current artifact counts by type and state, and the five most recently updated artifacts. Follow it with signals_list.
Get workspace summary stats
workspace_summary One-call session bootstrap: workspace metadata, current artifact counts by type and state, and the five most recently updated artifacts. Follow it with signals_list.
One-call session bootstrap: workspace meta, current unarchived artifact counts by type and state, and the 5 most recently updated current artifacts. Pair with signals_list and activity_feed_list.
Parameters
No parameters.