skein_close
Close an issue: status → closed, locked_by cleared, closed_at + closed_reason recorded, issue.closed (+ issue.unclaimed when it was locked) emitted. reason is required (non-empty after trim) — free-form context for a human reader; progress counts use closeOutcome, never the reason. Caller must hold the lock OR pass force=true (force_unlock: project owner, space owner, instance admin); expectedVersion is required; pinned issues require force=true. Optionally attach the git commits that close the issue via commits[]. ANSWERS WITH AN ACKNOWLEDGEMENT by default — the id, the applied state and the new version, no issue card and no prose — so the expectedVersion cycle continues without a re-read; pass verbose for the full IssueDetail.
If a retried transaction aborts while the declared version still matches, serialization_retry means the close rolled back; retry unchanged.
closeOutcome is required when transitioning to closed; repeating a close without it preserves the previous outcome. Target and outcome edits: skein_get_instructions, "Close outcome".
Re-close is NOT idempotent: every call overwrites closed_reason / closed_at and bumps version. To add commit hashes to an already-closed issue without losing the original reason use skein_commits_attach.
Retiring a standing task is rejected with standing_has_open_children (+ childIds) while any child is not closed; force does not bypass it.
Close-time warnings ride on the response's TOP level in both modes, under the same names: warning (fires when the issue has open children, or when it is closed with no assignee — both reasons joined when both apply) and openChildList (the open children themselves). Do not confuse openChildList with the nested epic.openChildren counter — different things, deliberately different names.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"id": "<id>",
"expectedVersion": "<expectedVersion>",
"reason": "<reason>"
},
"name": "skein_close"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Full hierarchical issue id (e.g. "demo-42"). | |
| force | No | Bypass lock + version + pinned predicates. Needs force_unlock on the issue's project (project owner, space owner, instance admin); others get `force_unlock_forbidden`. Default: false. | |
| reason | Yes | Free-form reason annotation (non-empty after trim). Lands in events.reason and issues.closed_reason. | |
| commits | No | Commit-refs to link to this issue. Max 10. Each needs `hash`; identify the repo with `repoId` or `repoUrl` from the project's gitRepos[], or omit both when the project has exactly one repo. Re-sends dedup silently per (issue, repo, hash). See skein_get_instructions ("Commit refs"). | |
| verbose | No | Return the full IssueDetail, prose included. Default false = acknowledgement: `id`, `ok`, `version` plus the post-state stamps that apply (`status`, `assignee`, lock / claim / close stamps) — no issue card and no free text. The version is always there, so the expectedVersion cycle needs no extra read. Details: skein_get_instructions. If the write applied but its card could not be read back, the answer is the acknowledgement plus `cardUnavailable: true` — read the card with skein_show; do not repeat the write. | |
| closeTarget | No | The issue this one duplicates (duplicate) or that replaced it (superseded); creates that edge in the same transaction. | |
| closeOutcome | No | How the issue ENDED. Only done counts toward progress; the other three are excluded from scope. | |
| expectedVersion | Yes | The version the agent expects to see on the issue. The close only proceeds when the live version matches; otherwise returns version_conflict with the live version. |