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:
gsdl-verify-gates(Step 7) completed with all gates passing. If.planning/[project-name]/verify-report.mddoesn'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.gsdl-open-pr(Step 8) opened the PR and dispositioned any review-bot findings — unlessForge → 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 rootSPEC_PATH— relative path toSPEC.mdTASKS_PATH— relative path totasks.mdVERIFY_REPORT_PATH— relative path toverify-report.mdPR_URL— the pull request from Step 8 plus its findings table, orskipped
Step 1 — Gather Project Context
Read from disk:
[WORKSPACE_ROOT]/[SPEC_PATH]— goals, requirements, non-goals, verification plan[WORKSPACE_ROOT]/[TASKS_PATH]— the completed slices, each tagged with its tracker sub-item ID[WORKSPACE_ROOT]/[VERIFY_REPORT_PATH]— the Step 7 gate results (the evidence).planning/[PROJECT_NAME]/seed.md— the original source reference (## Source).planning/[PROJECT_NAME]/worklog.md— if the project runs without a tracker, this holds the per-slice completion record- The Step 8 PR —
gh pr view [PR_URL] --json title,url,state,commits,reviews,commentsfor the review record, including how each bot finding was dispositioned
Step 2 — Analyze Git History
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):
git show --stat [COMMIT_HASH]
Collect commit messages, bullet points, and files touched. Then:
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:
# [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.
- 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.
- Sub-item comments — confirm completion (or at minimum reference them all from the parent comment).
- Transition status — pass these as the
TARGET_STATEfor each item:- Sub-items → the configured
sub-item-done-state(defaultDone), ifgsdl-executedidn't already move them there. Sub-items are not individually reviewed. - Parent item → the configured
parent-review-state(defaultIn 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.
- Sub-items → the configured
- If
gsdl-tracker-syncreturns 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. - With no tracker, the same content is appended to
worklog.mdas 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-notewithtitle,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
- Never close the loop without a passing
verify-report.md— evidence is the point of this step - 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
- Never call a tracker API from this context — write the comments, delegate the calls to SMALL
via
gsdl-tracker-sync - Always save the markdown file first — even if the user skips tracker closure or publishing, the document must exist on disk
- Never overwrite an existing decisions file — if it exists, append a date suffix:
decisions-[PROJECT_NAME]-[YYYYMMDD].md - Focus on decisions and evidence, not implementation minutiae — this document is for future developers and reviewers, not a line-by-line code review
- Keep the tone factual — describe what was done and why; avoid editorial commentary
- If git history is ambiguous, note the uncertainty rather than guessing
- 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