Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions discovery-map/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Each phase is its own PR off the previous phase's branch (stacked PRs — see *B
6. **[Refinement Session](phase-06-refinement-session.md)** — re-entry path, map editing operations, safety-by-destructiveness. **Status:** Review (PR #271)
7. **[Self-Healing Re-point](phase-07-self-healing.md)** — research-analysis and gap-analysis re-point to map at continue-epic boot-up. **Status:** Review (PR #272)
8. **[Imports](phase-08-imports.md)** — `imports/` directory, manifest tracking, KB indexing, behaviour change for features. **Status:** Review (PR #273)
9. **[Topic Splitting and Elevation](phase-09-topic-splitting-elevation.md)** — write inception items alongside; name collision validation. **Status:** Not started
9. **[Topic Splitting and Elevation](phase-09-topic-splitting-elevation.md)** — write inception items alongside; name collision validation. **Status:** Review (PR #274)
10. **[Direct-Entry Auto-Add](phase-10-direct-entry-auto-add.md)** — `d`/`discuss` and `r`/`research` for unmapped topics auto-create map items. **Status:** Not started
11. **[Migration](phase-11-migration.md)** — seed inception items for existing in-progress epics. **Status:** Not started
12. **[Drop Explore Mode](phase-12-drop-explore-mode.md)** — remove research's `e`/`explore`; collapse start-epic's `route-first-phase`. **Status:** Not started
Expand Down Expand Up @@ -93,7 +93,7 @@ The merge sequence at the end of the initiative is **strictly bottom-to-top of t
| `idea/inception-pr-6-refinement` | Phase 5 branch | Phase 6 — Refinement Session | [#271](https://github.com/leeovery/agentic-workflows/pull/271) | Review |
| `idea/inception-pr-7-self-healing` | Phase 6 branch | Phase 7 — Self-Healing Re-point | [#272](https://github.com/leeovery/agentic-workflows/pull/272) | Review |
| `idea/inception-pr-8-imports` | Phase 7 branch | Phase 8 — Imports | [#273](https://github.com/leeovery/agentic-workflows/pull/273) | Review |
| `idea/inception-pr-9-split-elevation` | Phase 7 branch | Phase 9 — Topic Splitting and Elevation | | Not started |
| `idea/inception-pr-9-split-elevation` | Phase 7 branch | Phase 9 — Topic Splitting and Elevation | [#274](https://github.com/leeovery/agentic-workflows/pull/274) | Review |
| `idea/inception-pr-10-direct-entry` | Phase 7 branch | Phase 10 — Direct-Entry Auto-Add | — | Not started |
| `idea/inception-pr-11-migration` | Phase 5 branch | Phase 11 — Migration | — | Not started |
| `idea/inception-pr-12-drop-explore` | Phase 11 branch | Phase 12 — Drop Explore Mode | — | Not started |
Expand Down
2 changes: 1 addition & 1 deletion skills/workflow-discussion-process/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: workflow-discussion-process
user-invocable: false
allowed-tools: Bash(node .claude/skills/workflow-manifest/scripts/manifest.cjs), Bash(node .claude/skills/workflow-knowledge/scripts/knowledge.cjs)
allowed-tools: Bash(node .claude/skills/workflow-manifest/scripts/manifest.cjs), Bash(node .claude/skills/workflow-knowledge/scripts/knowledge.cjs), Bash(node .claude/skills/workflow-inception-process/scripts/discovery.cjs)
---

# Discussion Process
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,40 @@ During organic discussion, a subtopic may grow beyond the scope of the current t

#### If `elevate`

1. Create a seed discussion file at `.workflows/{work_unit}/discussion/{new-topic}.md` with:
1. Pick a kebab-case name reflecting the elevated concern. Surface it to the user for confirmation. Then validate:

→ Load **[topic-name-validation.md](../../workflow-shared/references/topic-name-validation.md)** with work_unit = `{work_unit}`, proposed_name = `{new-topic}`.

On `collision-active`, re-prompt for an alternative and re-validate — loop until `ok` or `matches-dismissed`, or the user cancels the elevation. On `matches-dismissed`, proceed (the dismissed entry is pulled in step 4). On `ok`, proceed.

2. Generate a one-sentence summary of the elevated concern (drawn from the context that triggered elevation). This becomes the inception item's `summary` field.

3. Create the seed discussion file at `.workflows/{work_unit}/discussion/{new-topic}.md` with:
- Context section capturing what prompted the topic and any initial thinking from the current discussion
- A Discussion Map with initial subtopics derived from what's been discussed so far
- No decisions — those happen in the new discussion
2. Register in manifest:

4. Write manifest items — discussion first, then inception. If validation returned `matches-dismissed`, pull from the dismissed list first:

```bash
node .claude/skills/workflow-manifest/scripts/manifest.cjs pull {work_unit}.inception dismissed "{new-topic}"
```

Then:

```bash
node .claude/skills/workflow-manifest/scripts/manifest.cjs init-phase {work_unit}.discussion.{new-topic}
node .claude/skills/workflow-manifest/scripts/manifest.cjs init-phase {work_unit}.inception.{new-topic}
node .claude/skills/workflow-manifest/scripts/manifest.cjs set {work_unit}.inception.{new-topic} routing discussion
node .claude/skills/workflow-manifest/scripts/manifest.cjs set {work_unit}.inception.{new-topic} summary "{one-line summary}"
node .claude/skills/workflow-manifest/scripts/manifest.cjs set {work_unit}.inception.{new-topic} source "discussion-elevation:{topic}"
```
3. Update the current Discussion Map: replace the subtopic with `→ Elevated: {new-topic}`
4. Commit: `discussion({work_unit}/{topic}): elevate {new-topic} to separate discussion`

`routing: discussion` because elevation fires inside a discussion session. `source: discussion-elevation:{parent_topic}` is historical provenance; no cascade.

5. Update the current Discussion Map — replace the subtopic with `→ Elevated: {new-topic}`.

6. Commit: `discussion({work_unit}/{topic}): elevate {new-topic} to separate discussion`

→ Return to **B. Session Loop**.

Expand Down
13 changes: 6 additions & 7 deletions skills/workflow-inception-process/references/map-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,15 @@ Render the rejection in a code block:
- `decided` — `discussion has concluded`
- `cancelled` — `it has phase work in cancelled state and stays on the map as historical record`

**Name collision gates** — for Add and Rename, check the new name against `discovery_map`'s topic names (case-sensitive). A match means an **active** map item already uses the name — reject:
**Name validation** — for each Add and Rename operation, validate the proposed name via the shared reference:

> *Output the next fenced block as a code block:*
→ Load **[topic-name-validation.md](../../workflow-shared/references/topic-name-validation.md)** with work_unit = `{work_unit}`, proposed_name = `{name}`.

```
"{name}" is already on the map. Pick a different name or use
edit-summary / change-routing on the existing item.
```
Branch on `result`:

For Add, a name appearing in `dismissed` is **allowed** — it counts as a re-add. The Add flow pulls the name from the dismissed list before creating the new item.
- `collision-active` — rejection already rendered by the reference. Remove the operation from its group.
- `matches-dismissed` — allowed. For Add, the **D. Add** flow pulls the name from `dismissed` before writing. For Rename, proceed without pulling (a Rename target that happens to match a dismissed name leaves the dismissed entry alone; the new active item simply exists alongside it as historical record).
- `ok` — proceed.

→ Proceed to **C. Apply**.

Expand Down
2 changes: 1 addition & 1 deletion skills/workflow-research-process/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: workflow-research-process
user-invocable: false
allowed-tools: Bash(node .claude/skills/workflow-manifest/scripts/manifest.cjs), Bash(node .claude/skills/workflow-knowledge/scripts/knowledge.cjs)
allowed-tools: Bash(node .claude/skills/workflow-manifest/scripts/manifest.cjs), Bash(node .claude/skills/workflow-knowledge/scripts/knowledge.cjs), Bash(node .claude/skills/workflow-inception-process/scripts/discovery.cjs)
---

# Research Process
Expand Down
40 changes: 34 additions & 6 deletions skills/workflow-research-process/references/topic-splitting.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,43 @@ Want to split these into separate research files?
#### If yes

For each split topic:
1. Create `.workflows/{work_unit}/research/{topic}.md` using **[template.md](template.md)**
2. Move content verbatim from the source file — reword only for flow and readability, no summarisation
3. Remove the extracted content from the source file
4. Init manifest item for the new topic:

1. Pick a kebab-case name from the thread's content (e.g. `image-moderation`, `kitchen-utensils`). Surface it to the user for confirmation. Then validate:

→ Load **[topic-name-validation.md](../../workflow-shared/references/topic-name-validation.md)** with work_unit = `{work_unit}`, proposed_name = `{new_topic}`.

On `collision-active`, re-prompt for an alternative and re-validate — loop until `ok` or `matches-dismissed`, or the user abandons this thread. On `matches-dismissed`, proceed (the dismissed entry is pulled in step 4). On `ok`, proceed.

2. Create `.workflows/{work_unit}/research/{new_topic}.md` using **[template.md](template.md)**. Move content verbatim from the source file — reword only for flow and readability, no summarisation. Remove the extracted content from the source file.

3. Generate a one-sentence summary of the extracted content (drawn from the thread itself). This becomes the inception item's `summary` field, used in map renders.

4. Write manifest items — research first, then inception. If the validation returned `matches-dismissed`, pull from the dismissed list first:

```bash
node .claude/skills/workflow-manifest/scripts/manifest.cjs init-phase {work_unit}.research.{topic}
node .claude/skills/workflow-manifest/scripts/manifest.cjs pull {work_unit}.inception dismissed "{new_topic}"
```

Commit after splitting.
Then:

```bash
node .claude/skills/workflow-manifest/scripts/manifest.cjs init-phase {work_unit}.research.{new_topic}
node .claude/skills/workflow-manifest/scripts/manifest.cjs init-phase {work_unit}.inception.{new_topic}
node .claude/skills/workflow-manifest/scripts/manifest.cjs set {work_unit}.inception.{new_topic} routing research
node .claude/skills/workflow-manifest/scripts/manifest.cjs set {work_unit}.inception.{new_topic} summary "{one-line summary}"
node .claude/skills/workflow-manifest/scripts/manifest.cjs set {work_unit}.inception.{new_topic} source "research-split:{parent_topic}"
```

`routing: research` because the split fires inside a research session — research is where the new topic enters the pipeline. `source: research-split:{parent_topic}` is historical provenance; the parent's later state changes don't cascade.

Once all accepted threads have been processed, single commit covering the manifest writes and the new research files:

```bash
git add -- .workflows/{work_unit}/manifest.json .workflows/{work_unit}/research/
git commit -m "research({work_unit}/{parent_topic}): split into {N} topic(s)"
```

Then offer the user a choice of which topic to continue with:

> *Output the next fenced block as markdown (not a code block):*

Expand Down
96 changes: 96 additions & 0 deletions skills/workflow-shared/references/topic-name-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Topic Name Validation

*Shared reference. Loaded by `workflow-inception-process`, `workflow-research-process`, `workflow-discussion-process`, and any flow that proposes a new topic name for the discovery map.*

---

Validates a proposed topic name. First step normalises to kebab-case silently (callers always have Claude pick the name, so a slip should self-correct rather than escalate). Then checks against active discovery-map items (collision rejects) and the dismissed list (informational — caller pulls before writing). Returns a `result` the caller branches on. The reference is read-only — it never mutates the manifest.

## Parameters

The caller provides these via context before loading:

- `work_unit` — the epic's work unit name. Always present.
- `proposed_name` — the topic name the user has proposed. Always present.

After return, the caller reads `result` from conversation memory. Possible values:

- `collision-active` — name matches an active discovery-map item. Rejection rendered.
- `matches-dismissed` — name matches an entry on the dismissed list. **Informational** — caller pulls before writing.
- `ok` — no conflict. Caller proceeds.

## A. Normalise to Kebab-Case

Callers always have Claude generate or extract the proposed name before invoking this reference, so a non-kebab-case `proposed_name` is a Claude-side slip — not a user-facing error. The fix is to self-correct silently, then carry on.

A kebab-case name is lowercase ASCII letters, digits, and `-`. No leading or trailing `-`, no consecutive `-`, no other characters. See **[casing-conventions.md](casing-conventions.md)** for the canonical rule.

Test `proposed_name` against this pattern: `^[a-z0-9]+(-[a-z0-9]+)*$`.

#### If the name matches

→ Proceed to **B. Read Map and Dismissed List**.

#### Otherwise

Re-derive a kebab-case form for `proposed_name` per casing-conventions.md (lowercase, split on spaces/underscores/punctuation, join with single hyphens, strip leading/trailing hyphens). Use the corrected value as `proposed_name` for all subsequent steps. Do not render a rejection or surface the correction to the user — the caller and the user only see the normalised name from this point onward.

→ Proceed to **B. Read Map and Dismissed List**.

## B. Read Map and Dismissed List

Re-run discovery to pick up state changes since the caller's last invocation (writes earlier in the session, prior splits in the same batch):

```bash
node .claude/skills/workflow-inception-process/scripts/discovery.cjs {work_unit}
```

Read:

- `discovery_map` — list of active topic items. The `name` field of each entry is the case-sensitive map name.
- `dismissed` — array of names previously removed via refinement.

→ Proceed to **C. Compare Against Active Map**.

## C. Compare Against Active Map

Check whether `proposed_name` matches any `name` in `discovery_map` (case-sensitive — kebab-case enforcement in **A** means this is effectively case-insensitive too).

#### If a match exists

Set `result = "collision-active"` and render the rejection:

> *Output the next fenced block as a code block:*

```
"{proposed_name}" is already on the map. Pick a different name
or use edit-summary / change-routing on the existing item.
```

→ Return to caller.

#### Otherwise

→ Proceed to **D. Compare Against Dismissed List**.

## D. Compare Against Dismissed List

Check whether `proposed_name` matches any entry in `dismissed` (case-sensitive).

A dismissed-list match is **not** a rejection. User-explicit spawns (split, elevation, refinement add, direct-entry) bypass the dismissed list — the list only blocks automatic re-adds by analyses. The caller pulls the name from `dismissed` before writing the new item.

#### If a match exists

Set `result = "matches-dismissed"`.

→ Return to caller.

#### Otherwise

→ Proceed to **E. Return OK**.

## E. Return OK

Set `result = "ok"`.

→ Return to caller.