diff --git a/.claude/skills/dld-snapshot/SKILL.md b/.claude/skills/dld-snapshot/SKILL.md
index 4db2c59..ecdc93c 100644
--- a/.claude/skills/dld-snapshot/SKILL.md
+++ b/.claude/skills/dld-snapshot/SKILL.md
@@ -23,6 +23,7 @@ Shared scripts (used indirectly via skill scripts):
Skill-specific scripts:
```
.claude/skills/dld-snapshot/scripts/collect-active-decisions.sh
+.claude/skills/dld-snapshot/scripts/collect-proposed-decisions.sh
.claude/skills/dld-snapshot/scripts/update-snapshot-state.sh
```
@@ -30,9 +31,9 @@ Skill-specific scripts:
Check that `dld.config.yaml` exists at the repo root. If not, tell the user to run `/dld-init` first and stop.
-There must be at least one `accepted` decision. If all decisions are `proposed`, tell the user there's nothing to snapshot yet and suggest `/dld-implement`.
+There must be at least one `accepted` or `proposed` decision. If all decisions are `superseded` or `deprecated`, tell the user there's nothing to snapshot yet and suggest `/dld-decide`.
-## Step 1: Collect active decisions
+## Step 1: Collect decisions
```bash
bash .claude/skills/dld-snapshot/scripts/collect-active-decisions.sh
@@ -40,6 +41,14 @@ bash .claude/skills/dld-snapshot/scripts/collect-active-decisions.sh
This outputs the full content of all `accepted` decisions, separated by `===DLD_DECISION_BOUNDARY===` markers. Parse the output to extract each decision's frontmatter and body. Use the project mode from `dld.config.yaml` (already checked in prerequisites) to determine the organization strategy.
+Also collect proposed decisions:
+
+```bash
+bash .claude/skills/dld-snapshot/scripts/collect-proposed-decisions.sh
+```
+
+This outputs the full content of all `proposed` decisions, separated by the same boundary markers. Keep proposed decisions separate from accepted decisions — they are used in later steps to generate clearly marked sections.
+
## Step 2: Generate SNAPSHOT.md
Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
@@ -53,6 +62,7 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
> Use `/dld-snapshot` to regenerate. Source of truth: individual decision records.
>
> **Active decisions:** N (DL-001 through DL-XXX, excluding superseded/deprecated)
+> **Proposed decisions:** M
---
@@ -71,6 +81,23 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
### DL-NNN:
...
+
+---
+
+## Proposed Decisions
+
+> These decisions are proposed but not yet accepted. They represent planned
+> direction, not current state. Use `/dld-implement` to accept and implement them.
+
+### (proposed)
+
+#### DL-NNN:
+
+
+
+**Rationale:** <1-3 sentence summary.>
+
+---
```
### Organization rules
@@ -81,8 +108,9 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
### Content rules
-- Only include `accepted` decisions
-- Skip `superseded`, `deprecated`, and `proposed` decisions entirely
+**Accepted decisions (main body):**
+- Include all `accepted` decisions in the main sections
+- Skip `superseded` and `deprecated` decisions entirely
- When a decision supersedes another (check the `supersedes` field in the YAML frontmatter), include a `*Supersedes: DL-XXX*` note
- The **Decision** section content should be copied directly or lightly condensed — this is the authoritative statement
- The **Rationale** should be condensed to 1-3 sentences — enough to understand *why*, not every detail
@@ -90,6 +118,13 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
- If a decision has no Rationale section, omit the Rationale line
- If a decision has no references, omit the Code line
+**Proposed decisions (bottom section):**
+- Include all `proposed` decisions in a separate "Proposed Decisions" section at the bottom
+- Use the same organization rules (by namespace or tag) within the proposed section
+- Use H3 (`###`) for group headings and H4 (`####`) for individual decisions within the proposed section, to visually distinguish from accepted decisions
+- Omit the Code line — proposed decisions typically don't have code references yet
+- If there are no proposed decisions, omit the "Proposed Decisions" section entirely
+
## Step 3: Generate OVERVIEW.md
Write `decisions/OVERVIEW.md` — the high-level narrative synthesis.
@@ -149,6 +184,17 @@ graph LR
+
+## Planned Direction
+
+> The following summarizes proposed decisions that have not yet been accepted.
+> This section describes intended future direction, not current system state.
+
+
```
### Narrative guidelines
@@ -164,6 +210,7 @@ belong to a single area. E.g., "PostgreSQL for primary data store (DL-001)",
- Don't force diagrams if the decisions are simple or unrelated
- **Keep it proportional.** A project with 5 decisions needs a short overview. A project with 50 needs more structure. Scale the document to the content.
- **Group by namespace (namespaced projects) or by domain theme (flat projects).** For flat projects, identify natural domain groupings from tags and decision content.
+- **Separate proposed from accepted.** Proposed decisions go in a "Planned Direction" section at the bottom, written in future tense. Never mix proposed decisions into the main narrative — the main sections describe what the system *does*, the planned section describes what it *will do*. If there are no proposed decisions, omit the section entirely.
### Diagram guidelines
@@ -225,11 +272,12 @@ bash .claude/skills/dld-snapshot/scripts/update-snapshot-state.sh
## Step 6: Suggest next steps
> Snapshot generated:
-> - `decisions/SNAPSHOT.md` — detailed reference (N active decisions)
+> - `decisions/SNAPSHOT.md` — detailed reference (N active decisions, M proposed)
> - `decisions/OVERVIEW.md` — narrative synthesis with diagrams
> - `decisions/.md` —
>
> Next steps:
> - Review the generated documents for accuracy
+> - `/dld-implement` — accept and implement proposed decisions
> - `/dld-decide` — record new decisions
> - `/dld-audit` — check for drift between decisions and code
diff --git a/.claude/skills/dld-snapshot/scripts/collect-proposed-decisions.sh b/.claude/skills/dld-snapshot/scripts/collect-proposed-decisions.sh
new file mode 100755
index 0000000..9958c62
--- /dev/null
+++ b/.claude/skills/dld-snapshot/scripts/collect-proposed-decisions.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# Collect all proposed decisions and output their content.
+# Output: each decision's full file content, separated by a marker line.
+# The marker format is: ===DLD_DECISION_BOUNDARY===
+# This allows the agent to split and process decisions individually.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "$SCRIPT_DIR/../../dld-common/scripts/common.sh"
+
+RECORDS_DIR="$(get_records_dir)"
+
+if [[ ! -d "$RECORDS_DIR" ]]; then
+ exit 0
+fi
+
+# Find all decision files, sorted by numeric ID ascending
+FILES=$(find "$RECORDS_DIR" -name 'DL-*.md' -type f \
+ | awk -F/ '{file=$0; basename=$NF; gsub(/^DL-/,"",basename); gsub(/\.md$/,"",basename); print basename "\t" file}' \
+ | sort -n \
+ | cut -f2)
+
+if [[ -z "$FILES" ]]; then
+ exit 0
+fi
+
+FIRST=true
+while IFS= read -r file; do
+ STATUS=$(sed -n '/^---$/,/^---$/p' "$file" \
+ | grep "^status:" \
+ | head -1 \
+ | sed 's/^status:[[:space:]]*//')
+
+ if [[ "$STATUS" == "proposed" ]]; then
+ if $FIRST; then
+ FIRST=false
+ else
+ echo "===DLD_DECISION_BOUNDARY==="
+ fi
+ cat "$file"
+ fi
+done <<< "$FILES"
diff --git a/skills/dld-snapshot/SKILL.md b/skills/dld-snapshot/SKILL.md
index 398d81e..3c3fa57 100644
--- a/skills/dld-snapshot/SKILL.md
+++ b/skills/dld-snapshot/SKILL.md
@@ -23,6 +23,7 @@ Shared scripts (used indirectly via skill scripts):
Skill-specific scripts:
```
scripts/collect-active-decisions.sh
+scripts/collect-proposed-decisions.sh
scripts/update-snapshot-state.sh
```
@@ -30,9 +31,9 @@ scripts/update-snapshot-state.sh
Check that `dld.config.yaml` exists at the repo root. If not, tell the user to run `/dld-init` first and stop.
-There must be at least one `accepted` decision. If all decisions are `proposed`, tell the user there's nothing to snapshot yet and suggest `/dld-implement`.
+There must be at least one `accepted` or `proposed` decision. If all decisions are `superseded` or `deprecated`, tell the user there's nothing to snapshot yet and suggest `/dld-decide`.
-## Step 1: Collect active decisions
+## Step 1: Collect decisions
```bash
bash scripts/collect-active-decisions.sh
@@ -40,6 +41,14 @@ bash scripts/collect-active-decisions.sh
This outputs the full content of all `accepted` decisions, separated by `===DLD_DECISION_BOUNDARY===` markers. Parse the output to extract each decision's frontmatter and body. Use the project mode from `dld.config.yaml` (already checked in prerequisites) to determine the organization strategy.
+Also collect proposed decisions:
+
+```bash
+bash scripts/collect-proposed-decisions.sh
+```
+
+This outputs the full content of all `proposed` decisions, separated by the same boundary markers. Keep proposed decisions separate from accepted decisions — they are used in later steps to generate clearly marked sections.
+
## Step 2: Generate SNAPSHOT.md
Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
@@ -53,6 +62,7 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
> Use `/dld-snapshot` to regenerate. Source of truth: individual decision records.
>
> **Active decisions:** N (DL-001 through DL-XXX, excluding superseded/deprecated)
+> **Proposed decisions:** M
---
@@ -71,6 +81,23 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
### DL-NNN:
...
+
+---
+
+## Proposed Decisions
+
+> These decisions are proposed but not yet accepted. They represent planned
+> direction, not current state. Use `/dld-implement` to accept and implement them.
+
+### (proposed)
+
+#### DL-NNN:
+
+
+
+**Rationale:** <1-3 sentence summary.>
+
+---
```
### Organization rules
@@ -81,8 +108,9 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
### Content rules
-- Only include `accepted` decisions
-- Skip `superseded`, `deprecated`, and `proposed` decisions entirely
+**Accepted decisions (main body):**
+- Include all `accepted` decisions in the main sections
+- Skip `superseded` and `deprecated` decisions entirely
- When a decision supersedes another (check the `supersedes` field in the YAML frontmatter), include a `*Supersedes: DL-XXX*` note
- The **Decision** section content should be copied directly or lightly condensed — this is the authoritative statement
- The **Rationale** should be condensed to 1-3 sentences — enough to understand *why*, not every detail
@@ -90,6 +118,13 @@ Write `decisions/SNAPSHOT.md` — the detailed per-decision reference.
- If a decision has no Rationale section, omit the Rationale line
- If a decision has no references, omit the Code line
+**Proposed decisions (bottom section):**
+- Include all `proposed` decisions in a separate "Proposed Decisions" section at the bottom
+- Use the same organization rules (by namespace or tag) within the proposed section
+- Use H3 (`###`) for group headings and H4 (`####`) for individual decisions within the proposed section, to visually distinguish from accepted decisions
+- Omit the Code line — proposed decisions typically don't have code references yet
+- If there are no proposed decisions, omit the "Proposed Decisions" section entirely
+
## Step 3: Generate OVERVIEW.md
Write `decisions/OVERVIEW.md` — the high-level narrative synthesis.
@@ -149,6 +184,17 @@ graph LR
+
+## Planned Direction
+
+> The following summarizes proposed decisions that have not yet been accepted.
+> This section describes intended future direction, not current system state.
+
+
```
### Narrative guidelines
@@ -164,6 +210,7 @@ belong to a single area. E.g., "PostgreSQL for primary data store (DL-001)",
- Don't force diagrams if the decisions are simple or unrelated
- **Keep it proportional.** A project with 5 decisions needs a short overview. A project with 50 needs more structure. Scale the document to the content.
- **Group by namespace (namespaced projects) or by domain theme (flat projects).** For flat projects, identify natural domain groupings from tags and decision content.
+- **Separate proposed from accepted.** Proposed decisions go in a "Planned Direction" section at the bottom, written in future tense. Never mix proposed decisions into the main narrative — the main sections describe what the system *does*, the planned section describes what it *will do*. If there are no proposed decisions, omit the section entirely.
### Diagram guidelines
@@ -225,11 +272,12 @@ bash scripts/update-snapshot-state.sh
## Step 6: Suggest next steps
> Snapshot generated:
-> - `decisions/SNAPSHOT.md` — detailed reference (N active decisions)
+> - `decisions/SNAPSHOT.md` — detailed reference (N active decisions, M proposed)
> - `decisions/OVERVIEW.md` — narrative synthesis with diagrams
> - `decisions/.md` —
>
> Next steps:
> - Review the generated documents for accuracy
+> - `/dld-implement` — accept and implement proposed decisions
> - `/dld-decide` — record new decisions
> - `/dld-audit` — check for drift between decisions and code
diff --git a/skills/dld-snapshot/scripts/collect-proposed-decisions.sh b/skills/dld-snapshot/scripts/collect-proposed-decisions.sh
new file mode 100755
index 0000000..9958c62
--- /dev/null
+++ b/skills/dld-snapshot/scripts/collect-proposed-decisions.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# Collect all proposed decisions and output their content.
+# Output: each decision's full file content, separated by a marker line.
+# The marker format is: ===DLD_DECISION_BOUNDARY===
+# This allows the agent to split and process decisions individually.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "$SCRIPT_DIR/../../dld-common/scripts/common.sh"
+
+RECORDS_DIR="$(get_records_dir)"
+
+if [[ ! -d "$RECORDS_DIR" ]]; then
+ exit 0
+fi
+
+# Find all decision files, sorted by numeric ID ascending
+FILES=$(find "$RECORDS_DIR" -name 'DL-*.md' -type f \
+ | awk -F/ '{file=$0; basename=$NF; gsub(/^DL-/,"",basename); gsub(/\.md$/,"",basename); print basename "\t" file}' \
+ | sort -n \
+ | cut -f2)
+
+if [[ -z "$FILES" ]]; then
+ exit 0
+fi
+
+FIRST=true
+while IFS= read -r file; do
+ STATUS=$(sed -n '/^---$/,/^---$/p' "$file" \
+ | grep "^status:" \
+ | head -1 \
+ | sed 's/^status:[[:space:]]*//')
+
+ if [[ "$STATUS" == "proposed" ]]; then
+ if $FIRST; then
+ FIRST=false
+ else
+ echo "===DLD_DECISION_BOUNDARY==="
+ fi
+ cat "$file"
+ fi
+done <<< "$FILES"
diff --git a/tests/test_collect_proposed_decisions.bats b/tests/test_collect_proposed_decisions.bats
new file mode 100644
index 0000000..7642ce9
--- /dev/null
+++ b/tests/test_collect_proposed_decisions.bats
@@ -0,0 +1,93 @@
+#!/usr/bin/env bats
+# Tests for dld-snapshot/scripts/collect-proposed-decisions.sh
+
+load 'test_helper/common'
+
+SCRIPT=""
+
+setup() {
+ setup_flat_project
+ SCRIPT="$SKILLS_DIR/dld-snapshot/scripts/collect-proposed-decisions.sh"
+}
+
+teardown() {
+ teardown_project
+}
+
+@test "collect-proposed-decisions outputs nothing with no decisions" {
+ run bash "$SCRIPT"
+ assert_success
+ assert_output ""
+}
+
+@test "collect-proposed-decisions returns only proposed decisions" {
+ create_decision "DL-001" "accepted"
+ create_decision "DL-002" "proposed"
+ create_decision "DL-003" "superseded"
+ create_decision "DL-004" "proposed"
+
+ run bash "$SCRIPT"
+ assert_success
+ assert_output --partial "id: DL-002"
+ assert_output --partial "id: DL-004"
+ refute_output --partial "id: DL-001"
+ refute_output --partial "id: DL-003"
+}
+
+@test "collect-proposed-decisions separates with boundary markers" {
+ create_decision "DL-001" "proposed"
+ create_decision "DL-002" "proposed"
+
+ run bash "$SCRIPT"
+ assert_success
+ assert_output --partial "===DLD_DECISION_BOUNDARY==="
+}
+
+@test "collect-proposed-decisions has no boundary before first decision" {
+ create_decision "DL-001" "proposed"
+ create_decision "DL-002" "proposed"
+
+ output="$(bash "$SCRIPT")"
+ first_line="$(echo "$output" | head -1)"
+ assert_equal "$first_line" "---"
+}
+
+@test "collect-proposed-decisions outputs in ascending ID order" {
+ create_decision "DL-003" "proposed"
+ create_decision "DL-001" "proposed"
+
+ output="$(bash "$SCRIPT")"
+ pos_001="$(echo "$output" | grep -n "id: DL-001" | head -1 | cut -d: -f1)"
+ pos_003="$(echo "$output" | grep -n "id: DL-003" | head -1 | cut -d: -f1)"
+ [[ "$pos_001" -lt "$pos_003" ]]
+}
+
+@test "collect-proposed-decisions exits cleanly when records dir missing" {
+ rmdir decisions/records
+ run bash "$SCRIPT"
+ assert_success
+ assert_output ""
+}
+
+@test "collect-proposed-decisions works with namespaced decisions" {
+ setup_namespaced_project
+ create_decision "DL-001" "proposed" "billing"
+ create_decision "DL-002" "accepted" "auth"
+ create_decision "DL-003" "proposed" "auth"
+
+ run bash "$SCRIPT"
+ assert_success
+ assert_output --partial "id: DL-001"
+ assert_output --partial "id: DL-003"
+ refute_output --partial "id: DL-002"
+}
+
+@test "collect-proposed-decisions includes full file content" {
+ create_decision "DL-001" "proposed"
+
+ run bash "$SCRIPT"
+ assert_success
+ assert_output --partial "## Context"
+ assert_output --partial "## Decision"
+ assert_output --partial "Test decision content for DL-001"
+}