# Gsdl Close Loop

> Capture decisions, architecture changes, gate evidence, and PR review outcomes from a project into a structured document, then close the corresponding tracker item with that evidence attached and optionally publish the document to Slite, Notion, or Confluence. Use when the user wants to wrap up a project, document what was built, or close out a ticket. This is Step 9 (Close Loop with Evidence Captured) of the GSDL pipeline — the final checkpoint. Synthesis runs on the LARGE tier; the tracker writes are delegated to the SMALL tier via gsdl-tracker-sync.

- Skill: `nsantini/gsdl-close-loop` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nsantini/gsdl-close-loop`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nsantini/gsdl-close-loop/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: nsantini (https://skillmd.com/u/nsantini)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nsantini/gsdl-close-loop

---


# Close Loop

Analyzes what was built, captures decisions and architecture changes, pulls in the Step 7 gate
evidence and the Step 8 PR review outcome, saves it all to a markdown document, and closes the
tracker item referencing that evidence. This is **Step 9**, the final checkpoint:
`Pick up source → Brainstorm → SPEC.md → Slices → Review → Branch → Execute → Verify → PR + bot → Close loop`

**Prerequisites**:

1. `gsdl-verify-gates` (Step 7) completed with all gates passing. If
   `.planning/[project-name]/verify-report.md` doesn't exist, or shows a failing gate, stop and tell
   the user to run/fix verification first — closing the loop without evidence defeats the point of
   the checkpoint.
2. `gsdl-open-pr` (Step 8) opened the PR and dispositioned any review-bot findings — **unless
   `Forge → provider: none`**, in which case there is no PR and the document says so. If a forge *is*
   configured but no PR exists, say so and ask whether to run Step 8 first: moving the parent item to
   review is meaningless without something to review.

## Tier

**LARGE for the synthesis; SMALL for the tracker writes.**

The document is synthesis, not transcription: reading the spec, the slices, the git history, the gate
report, and the PR review together to name the decisions that were actually made, the architecture
that actually changed, and what a future reader needs to know. A summary that just restates the commit
log is the failure mode this step exists to avoid. That is LARGE work.

Posting the comments and moving the item states is not — hand it to a **SMALL subagent running
`gsdl-tracker-sync`** (Operation B) once you've written the comment bodies.

The `gsdl` orchestrator routes this step to LARGE either way: inline when the session is on a LARGE
model, otherwise a LARGE subagent with its Question Relay protocol. **Never run the synthesis on a
smaller tier**, and never ask the user to switch models themselves.

## Inputs

- `PROJECT_NAME` — the project name (kebab-case)
- `WORKSPACE_ROOT` — absolute path to workspace root
- `SPEC_PATH` — relative path to `SPEC.md`
- `TASKS_PATH` — relative path to `tasks.md`
- `VERIFY_REPORT_PATH` — relative path to `verify-report.md`
- `PR_URL` — the pull request from Step 8 plus its findings table, or `skipped`

---

## Step 1 — Gather Project Context

Read from disk:

1. `[WORKSPACE_ROOT]/[SPEC_PATH]` — goals, requirements, non-goals, verification plan
2. `[WORKSPACE_ROOT]/[TASKS_PATH]` — the completed slices, each tagged with its tracker sub-item ID
3. `[WORKSPACE_ROOT]/[VERIFY_REPORT_PATH]` — the Step 7 gate results (the evidence)
4. `.planning/[PROJECT_NAME]/seed.md` — the original source reference (`## Source`)
5. `.planning/[PROJECT_NAME]/worklog.md` — if the project runs without a tracker, this holds the
   per-slice completion record
6. The Step 8 PR — `gh pr view [PR_URL] --json title,url,state,commits,reviews,comments` for the
   review record, including how each bot finding was dispositioned

---

## Step 2 — Analyze Git History

```bash
git log --oneline --no-merges
```

For each commit belonging to this project (identified by the `[N.0]` prefix matching a parent slice
title in `tasks.md`):

```bash
git show --stat [COMMIT_HASH]
```

Collect commit messages, bullet points, and files touched. Then:

```bash
git diff HEAD~[N] HEAD --name-status
```

for the full file-change summary across the project (`N` = number of project commits).

---

## Step 3 — Extract Decisions and Changes

### Decisions
Look for: libraries/frameworks chosen and why, patterns adopted, trade-offs honored, things
explicitly not done, tasks modified/added/skipped during execution.

### Architecture Changes
Look for: new directories/modules, new dependencies (`package.json`, `requirements.txt`, `go.mod`,
`Cargo.toml`, …), new config files, significant refactors, new integration points.

---

## Step 4 — Generate the Document

Write to `[WORKSPACE_ROOT]/.planning/[PROJECT_NAME]/decisions-[PROJECT_NAME].md`:

```markdown
# [Project Name] — Decisions & Evidence

> Generated by GSDL on [YYYY-MM-DD]
> Source: [tracker item ID and URL, document URL, or "local idea" — from seed.md]
> Pull request: [PR URL, or "none — no forge configured"]
> SPEC: [SPEC.md path]
> Tasks: [tasks.md path]

## Summary

[2–4 sentences: what was built, the core approach, major constraints honored.]

## Key Decisions

### [Decision Title]
**What:** [What was decided]
**Why:** [Rationale, if evident from code/commits/SPEC]
**Impact:** [Files, modules, or behaviors affected]

[Repeat for 3–8 significant decisions]

## Architecture Changes

### New Structure
[New directories/modules/files with one-line descriptions]

### Dependencies Added
[New packages/libraries, with purpose]

### Integration Points
[New APIs, services, databases, or external integrations]

## What Was Not Built

[SPEC.md requirements or slices explicitly skipped/deferred, with reason if known]

## Evidence (Step 7 Gate Results)

[Pull the gate table directly from verify-report.md — do not re-run gates here, this section is a record of what already passed]

| Gate | Command | Result |
|------|---------|--------|
| ... | ... | ✅ Pass |

Full report: `[VERIFY_REPORT_PATH]`

## Automated Review (Step 8)

PR: [PR URL] — [branch] → [base]
Reviewer: [matched bot login, "no bot responded", "not configured on this repo", or "step skipped — no forge configured"]

| Finding | Disposition |
|---------|-------------|
| [one-line summary] | ✅ Fixed in `[sha]` / ⛔ Rejected — [reason] / 🙋 Resolved with [user] — [outcome] |

Rejected and deferred findings belong here too — a reviewer should be able to see what the bot raised and why it wasn't changed.

## Files Changed

| File | Change |
|------|--------|
| [path] | Created / Modified / Deleted |
```

Omit empty sections (e.g., "Dependencies Added" if none were added). **Never omit the Automated
Review section** — if Step 8 didn't run, say why.

---

## Step 5 — Show Document Preview

Adapt the prompt to the configured providers — don't offer a tracker or docs target that isn't
configured.

```
✅ Decisions & Evidence document saved to: .planning/[PROJECT_NAME]/decisions-[PROJECT_NAME].md

Ready to close the loop in [tracker]:
- Parent item: [ITEM-ID]
- Sub-items: [identifiers from tasks.md]
- Pull request: [PR URL, or "none"]

Type "close" to post the evidence, move the sub-items to "[sub-item-done-state]", and move the
parent to "[parent-review-state]", or tell me a different target status.

Also want to publish this doc to [docs provider]?
- Type "publish [URL or ID]" to publish it under that parent
- Type "no" or press Enter to skip
```

With `Tracker → provider: none`, replace the closure block with: "This project has no tracker — the
completion record is in `worklog.md`." With `Docs → provider: none`, drop the publish prompt.

---

## Step 6 — Close the Loop in the Tracker

On the user's "close" (or equivalent) confirmation, **write the comment bodies yourself**, then
dispatch the API calls to a **SMALL subagent** running `gsdl-tracker-sync` (Operation B). Never make
the tracker calls from this context.

1. **Parent item comment** — what was built, the **PR link**, a link to the decisions doc, the gate
   results table, and the list of sub-items completed.
2. **Sub-item comments** — confirm completion (or at minimum reference them all from the parent comment).
3. **Transition status** — pass these as the `TARGET_STATE` for each item:
   - **Sub-items** → the configured `sub-item-done-state` (default `Done`), if `gsdl-execute` didn't
     already move them there. Sub-items are not individually reviewed.
   - **Parent item** → the configured `parent-review-state` (default `In Review`) — the whole feature
     is complete, the PR is open, and it's ready for human code review. Do **not** move the parent to
     a terminal done state; that happens after review and merge, outside this pipeline.
4. **If `gsdl-tracker-sync` returns a BLOCKER** (no credentials, unresolvable state), give the user
   the exact text to paste into the tracker manually and tell them which status to set.
5. **With no tracker**, the same content is appended to `worklog.md` as the closing entry.

---

## Step 7 — Publish the Document (if requested)

Publish to whatever `Docs → provider` is configured, under the parent the user gave (or the
`Docs → parent` recorded in the config). Title the published document
`[Project Name] — Decisions & Evidence`.

### Slite

Extract the note ID from `https://slite.com/app/docs/{NOTE_ID}/{title}` (legacy) or
`https://{workspace}.slite.com/p/{NOTE_ID}/{title}`, or accept a bare ID.

- **MCP**: `create-note` with `title`, `parentNoteId`, `markdown`.
- **API**:

```
POST https://api.slite.com/v1/notes
Authorization: Bearer $SLITE_API_KEY
Content-Type: application/json

{ "title": "...", "parentNoteId": "[NOTE_ID]", "markdown": "[document content]" }
```

### Notion

Extract the 32-char page ID from the URL (with or without hyphens) or accept a bare ID.

- **MCP**: create a child page under the parent page with the document content.
- **API**:

```
POST https://api.notion.com/v1/pages
Authorization: Bearer $NOTION_TOKEN
Notion-Version: 2022-06-28

{ "parent": { "page_id": "[PARENT_PAGE_ID]" },
  "properties": { "title": { "title": [{ "text": { "content": "..." } }] } },
  "children": [ /* markdown converted to blocks */ ] }
```

Markdown → block mapping:

| Markdown | Notion block |
|----------|--------------|
| `# Heading` | `heading_1` |
| `## Heading` | `heading_2` |
| `### Heading` | `heading_3` |
| `> blockquote` | `quote` |
| `- bullet item` | `bulleted_list_item` |
| Regular paragraph | `paragraph` |
| `\| table \|` | `table` with `table_row` children |
| `**bold**` | `rich_text` with `bold: true` |

Keep each text block under 2000 characters (Notion's per-`rich_text` limit).

### Confluence

Accept a page ID or a space key + parent page.

```
POST $CONFLUENCE_BASE_URL/wiki/api/v2/pages
Authorization: Basic (email:token)

{ "spaceId": "[SPACE_ID]", "parentId": "[PARENT_PAGE_ID]", "title": "...",
  "body": { "representation": "storage", "value": "[HTML converted from the markdown]" } }
```

Convert the markdown to Confluence storage-format HTML — headings, lists, and tables map directly.

### On success / failure

Report the created document's URL. On failure, say exactly what failed and tell the user to copy the
markdown from `.planning/[PROJECT_NAME]/decisions-[PROJECT_NAME].md` manually — the file on disk is
always the source of truth.

---

## Rules

1. **Never close the loop without a passing `verify-report.md`** — evidence is the point of this step
2. **Record the PR and its review outcome** — the document must name the PR and how each bot finding
   was dispositioned, including the rejected ones. If Step 8 was skipped, record why
3. **Never call a tracker API from this context** — write the comments, delegate the calls to SMALL
   via `gsdl-tracker-sync`
4. **Always save the markdown file first** — even if the user skips tracker closure or publishing, the
   document must exist on disk
5. **Never overwrite an existing decisions file** — if it exists, append a date suffix:
   `decisions-[PROJECT_NAME]-[YYYYMMDD].md`
6. **Focus on decisions and evidence, not implementation minutiae** — this document is for future
   developers and reviewers, not a line-by-line code review
7. **Keep the tone factual** — describe what was done and why; avoid editorial commentary
8. **If git history is ambiguous**, note the uncertainty rather than guessing
9. **Parent item stops at the review state, never a terminal done state** — only sub-items reach done
   here. Transitions are visible to the whole team; confirm before applying

