From c8f340fc1afd1e7ee368e046d885510ef6f94aaf Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 08:18:48 -0800 Subject: [PATCH 01/10] feat(US-001): Define .hq/ directory structure for distributed tracking Add structure.md documenting: - .hq/ directory layout with prd.json, claims.json, sync-log.json - JSON schemas for all three files - .gitignore recommendations Co-Authored-By: Claude Opus 4.5 --- knowledge/distributed-tracking/structure.md | 253 ++++++++++++++++++++ projects/distributed-tracking/prd.json | 157 ++++++++++++ 2 files changed, 410 insertions(+) create mode 100644 knowledge/distributed-tracking/structure.md create mode 100644 projects/distributed-tracking/prd.json diff --git a/knowledge/distributed-tracking/structure.md b/knowledge/distributed-tracking/structure.md new file mode 100644 index 0000000..090fd55 --- /dev/null +++ b/knowledge/distributed-tracking/structure.md @@ -0,0 +1,253 @@ +# Distributed Tracking Directory Structure + +The `.hq/` directory enables distributed teams to share PRD and task status via git. + +## Directory Location + +``` +{target_repo}/ +├── .hq/ +│ ├── prd.json # Project requirements and task status +│ ├── claims.json # Active task claims +│ └── sync-log.json # Sync history +├── src/ +└── ... +``` + +## File Schemas + +### prd.json + +Synced copy of project PRD with tracking metadata. + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": ["project", "goal", "features", "sync_metadata"], + "properties": { + "project": { + "type": "string", + "description": "Project identifier" + }, + "goal": { + "type": "string", + "description": "High-level project goal" + }, + "success_criteria": { + "type": "string", + "description": "How success is measured" + }, + "has_ui": { + "type": "boolean", + "description": "Whether project has UI components requiring Playwright testing" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "title", "passes"], + "properties": { + "id": { + "type": "string", + "description": "Unique task identifier (e.g., US-001)" + }, + "title": { + "type": "string", + "description": "Task title" + }, + "description": { + "type": "string", + "description": "Detailed task description" + }, + "acceptance_criteria": { + "type": "array", + "items": { "type": "string" }, + "description": "Verifiable completion criteria" + }, + "files": { + "type": "array", + "items": { "type": "string" }, + "description": "Files to create or modify" + }, + "dependsOn": { + "type": "array", + "items": { "type": "string" }, + "description": "Task IDs that must complete first" + }, + "passes": { + "type": ["boolean", "null"], + "description": "Task completion status" + }, + "notes": { + "type": "string", + "description": "Implementation notes, failure details" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last modification timestamp" + } + } + } + }, + "sync_metadata": { + "type": "object", + "required": ["synced_at", "synced_from"], + "properties": { + "synced_at": { + "type": "string", + "format": "date-time", + "description": "When this sync occurred" + }, + "synced_from": { + "type": "string", + "description": "Source HQ path (e.g., C:/my-hq/projects/distributed-tracking)" + }, + "synced_by": { + "type": "string", + "description": "User or agent who performed sync" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "created_at": { "type": "string", "format": "date-time" }, + "created_by": { "type": "string" }, + "purpose": { "type": "string" } + } + } + } +} +``` + +### claims.json + +Tracks which tasks are claimed by which contributor to prevent duplicate work. + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": ["claims"], + "properties": { + "claims": { + "type": "array", + "items": { + "type": "object", + "required": ["task_id", "claimed_by", "claimed_at", "expires_at"], + "properties": { + "task_id": { + "type": "string", + "description": "Task ID being claimed (e.g., US-001)" + }, + "claimed_by": { + "type": "string", + "description": "Identifier of claimer (user, agent, or machine)" + }, + "claimed_at": { + "type": "string", + "format": "date-time", + "description": "When claim was made" + }, + "expires_at": { + "type": "string", + "format": "date-time", + "description": "When claim expires (default: 24h from claimed_at)" + }, + "notes": { + "type": "string", + "description": "Optional context about the claim" + } + } + } + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last modification to claims file" + } + } +} +``` + +### sync-log.json + +Audit trail of all sync operations for debugging and history. + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": ["entries"], + "properties": { + "entries": { + "type": "array", + "items": { + "type": "object", + "required": ["timestamp", "action", "source"], + "properties": { + "timestamp": { + "type": "string", + "format": "date-time", + "description": "When operation occurred" + }, + "action": { + "type": "string", + "enum": ["push", "pull", "claim", "release", "merge"], + "description": "Type of sync operation" + }, + "source": { + "type": "string", + "description": "Origin of the operation" + }, + "target": { + "type": "string", + "description": "Destination of the operation" + }, + "tasks_affected": { + "type": "array", + "items": { "type": "string" }, + "description": "Task IDs involved in this operation" + }, + "details": { + "type": "string", + "description": "Additional context or error info" + }, + "actor": { + "type": "string", + "description": "User or agent who performed operation" + } + } + } + } + } +} +``` + +## .gitignore Recommendations + +Add to the target repository's `.gitignore`: + +```gitignore +# Distributed tracking - DO NOT ignore +# .hq/ + +# Local-only files (if needed) +.hq/*.local.json +.hq/scratch/ +``` + +**Important:** The `.hq/` directory should be committed to git. This is intentional - the whole point is sharing status via git. Only ignore: + +- `*.local.json` - Local overrides not meant for sharing +- `scratch/` - Temporary working files + +## Usage + +1. **First sync:** Creates `.hq/` directory with initial prd.json +2. **Subsequent syncs:** Updates prd.json, manages claims +3. **Contributors:** Pull repo, check `.hq/prd.json` for available tasks +4. **Claim before work:** Update claims.json to prevent conflicts +5. **After completion:** Push updated status, release claim diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json new file mode 100644 index 0000000..5d723b1 --- /dev/null +++ b/projects/distributed-tracking/prd.json @@ -0,0 +1,157 @@ +{ + "project": "distributed-tracking", + "goal": "Sync PRD/task status to target repos so distributed teams have visibility and don't duplicate work", + "success_criteria": "Contributors can see planned work, claim tasks, and status updates propagate via git", + "target_repo": "C:/my-hq", + "has_ui": false, + "features": [ + { + "id": "US-001", + "title": "Define .hq/ directory structure", + "description": "Document standard location in repos for distributed tracking files", + "acceptance_criteria": [ + "knowledge/distributed-tracking/structure.md exists", + "Documents .hq/ directory with: prd.json, claims.json, sync-log.json", + "Each file has JSON schema defined", + "Documents .gitignore recommendations" + ], + "files": ["knowledge/distributed-tracking/structure.md"], + "passes": true, + "notes": "Created structure.md with JSON schemas for prd.json, claims.json, sync-log.json. Includes .gitignore recommendations." + }, + { + "id": "US-002", + "title": "Add push-to-repo function", + "description": "Push PRD/task status to target repo's .hq/ directory", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes push_to_repo instructions", + "Copies PRD data to {target_repo}/.hq/prd.json", + "Includes: full PRD, task status, worker assignments, notes", + "Adds synced_at timestamp and synced_from field", + "Creates .hq/ directory if missing", + "Commits with message: sync: update distributed tracking" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-001"], + "passes": false, + "notes": "" + }, + { + "id": "US-003", + "title": "Add pull-from-repo function", + "description": "Pull latest status from repo before starting work", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes pull_from_repo instructions", + "Reads {target_repo}/.hq/prd.json if exists", + "Compares with local projects/{name}/prd.json", + "Returns diff summary (tasks added, changed, removed)", + "Does NOT auto-overwrite local" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-001"], + "passes": false, + "notes": "" + }, + { + "id": "US-004", + "title": "Add conflict detection and merge", + "description": "Detect conflicts between local and repo PRD, merge intelligently", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes conflict resolution instructions", + "When local and repo differ: show task-level diff", + "Merge strategy: per-task, newer updated_at wins", + "User prompted to confirm merge", + "Merged result written to both local and repo" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-003"], + "passes": false, + "notes": "" + }, + { + "id": "US-005", + "title": "Add duplicate work detection", + "description": "Warn when planning work that already exists in repo", + "acceptance_criteria": [ + ".claude/commands/prd.md includes duplicate check step", + "On PRD creation: check if .hq/prd.json exists in target repo", + "If exists: show existing tasks, ask add or create separate", + "Fuzzy match task titles to catch near-duplicates", + "Warning shown before PRD is saved" + ], + "files": [".claude/commands/prd.md"], + "dependsOn": ["US-001"], + "passes": false, + "notes": "" + }, + { + "id": "US-006", + "title": "Add task claim mechanism", + "description": "Claim tasks before starting to prevent conflicts", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes claim instructions", + "claims.json schema: task_id, claimed_by, claimed_at, expires_at", + "Before task: check if claimed by someone else", + "If claimed: show warning with claimer info and timestamp", + "Claims expire after 24h by default", + "On task complete: release claim" + ], + "files": ["prompts/pure-ralph-base.md", "knowledge/distributed-tracking/structure.md"], + "dependsOn": ["US-001"], + "passes": false, + "notes": "" + }, + { + "id": "US-007", + "title": "Integrate with pure-ralph loop", + "description": "Automatic sync during pure-ralph execution", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md updated with sync workflow", + "On loop start: pull from repo, warn on conflicts", + "Before each task: check claim, claim if available", + "After each task: push status to repo", + "On loop complete: push final, release claims" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-002", "US-003", "US-006"], + "passes": false, + "notes": "" + }, + { + "id": "US-008", + "title": "Add /sync-tasks slash command", + "description": "Manual sync command for ad-hoc status checks", + "acceptance_criteria": [ + ".claude/commands/sync-tasks.md exists", + "/sync-tasks {project} pulls and shows status diff", + "/sync-tasks {project} --push pushes local to repo", + "/sync-tasks {project} --claim {task-id} claims specific task", + "Shows clear summary of sync result" + ], + "files": [".claude/commands/sync-tasks.md"], + "dependsOn": ["US-002", "US-003", "US-006"], + "passes": false, + "notes": "" + }, + { + "id": "US-009", + "title": "Document distributed workflow", + "description": "Comprehensive documentation for contributors", + "acceptance_criteria": [ + "knowledge/distributed-tracking/workflow.md exists", + "Documents full sync lifecycle", + "Includes troubleshooting for common conflicts", + "Includes examples of claim/release flow" + ], + "files": ["knowledge/distributed-tracking/workflow.md"], + "dependsOn": ["US-007"], + "passes": false, + "notes": "" + } + ], + "metadata": { + "created_at": "2026-01-27T12:00:00Z", + "created_by": "stefan", + "purpose": "Enable distributed teams to share PRD/task status via git" + } +} From e3309eb38602fe0e8f43759292ce68243204815a Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 08:27:11 -0800 Subject: [PATCH 02/10] feat(US-002): Add push-to-repo function for distributed tracking Co-Authored-By: Claude Opus 4.5 --- projects/distributed-tracking/prd.json | 4 +- prompts/pure-ralph-base.md | 84 ++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index 5d723b1..70938c3 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -33,8 +33,8 @@ ], "files": ["prompts/pure-ralph-base.md"], "dependsOn": ["US-001"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Added 'Distributed Tracking - Push to Repo' section to pure-ralph-base.md. Documents push_to_repo function with: mkdir for .hq dir, sync_metadata with synced_at/synced_from/synced_by, what gets synced (full PRD, features, status, notes), example, and commit strategy options." }, { "id": "US-003", diff --git a/prompts/pure-ralph-base.md b/prompts/pure-ralph-base.md index 8c52978..86e04f5 100644 --- a/prompts/pure-ralph-base.md +++ b/prompts/pure-ralph-base.md @@ -404,6 +404,90 @@ Beyond the required worker audit info, notes can include: --- +## Distributed Tracking - Push to Repo + +After completing a task and updating the PRD, push the status to the target repo's `.hq/` directory so distributed teams have visibility. + +### push_to_repo Function + +Execute this after each successful task completion (after PRD update, before or as part of commit): + +``` +PUSH_TO_REPO: + 1. Create .hq/ directory in target repo if missing: + mkdir -p {target_repo}/.hq + + 2. Read the local PRD from {{PRD_PATH}} + + 3. Add sync_metadata to create the distributed copy: + { + ...full PRD contents..., + "sync_metadata": { + "synced_at": "", + "synced_from": "{{PRD_PATH}}", + "synced_by": "pure-ralph" + } + } + + 4. Write to {target_repo}/.hq/prd.json + + 5. Commit with message: "sync: update distributed tracking" +``` + +### What Gets Synced + +The `.hq/prd.json` includes: +- **Full PRD:** project, goal, success_criteria, has_ui +- **All features:** with id, title, description, acceptance_criteria +- **Task status:** passes (true/false/null), notes, updated_at +- **Dependencies:** dependsOn arrays +- **Files:** list of files each task touches +- **Metadata:** original created_at, created_by, purpose +- **Sync metadata:** synced_at, synced_from, synced_by + +### Example + +Given local PRD at `C:/my-hq/projects/my-project/prd.json` and target repo at `C:/repos/my-project`: + +```bash +# Ensure directory exists +mkdir -p C:/repos/my-project/.hq + +# The prd.json written to C:/repos/my-project/.hq/prd.json: +{ + "project": "my-project", + "goal": "...", + "features": [...], + "metadata": {...}, + "sync_metadata": { + "synced_at": "2026-01-27T15:30:00Z", + "synced_from": "C:/my-hq/projects/my-project/prd.json", + "synced_by": "pure-ralph" + } +} +``` + +### Commit Strategy + +You have two options: + +1. **Combined commit** (recommended): Include the `.hq/prd.json` update in your task commit + ``` + git add {target_repo}/.hq/prd.json + git commit -m "feat(TASK-ID): Brief description" + ``` + +2. **Separate commit**: Commit task first, then sync + ``` + git commit -m "feat(TASK-ID): Brief description" + git add {target_repo}/.hq/prd.json + git commit -m "sync: update distributed tracking" + ``` + +The combined approach is preferred as it keeps task completion and status in atomic sync. + +--- + ## Self-Improvement This prompt can evolve. If you learn something valuable: From 7fd2fa136c8a7be43e123a830b8d39d3085ed644 Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 08:43:48 -0800 Subject: [PATCH 03/10] feat(US-003): Add pull-from-repo function for distributed tracking - Added 'Distributed Tracking - Pull from Repo' section to pure-ralph-base.md - Documents pull_from_repo function with: check if exists, read both files, compare by task ID, generate diff summary - Includes diff detection logic and field comparison table - Explicit no-auto-overwrite policy to prevent data loss - Added .hq/prd.json for distributed tracking sync Co-Authored-By: Claude Opus 4.5 --- .hq/prd.json | 162 +++++++++++++++++++++++++ projects/distributed-tracking/prd.json | 4 +- prompts/pure-ralph-base.md | 108 +++++++++++++++++ 3 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 .hq/prd.json diff --git a/.hq/prd.json b/.hq/prd.json new file mode 100644 index 0000000..6656def --- /dev/null +++ b/.hq/prd.json @@ -0,0 +1,162 @@ +{ + "project": "distributed-tracking", + "goal": "Sync PRD/task status to target repos so distributed teams have visibility and don't duplicate work", + "success_criteria": "Contributors can see planned work, claim tasks, and status updates propagate via git", + "target_repo": "C:/my-hq", + "has_ui": false, + "features": [ + { + "id": "US-001", + "title": "Define .hq/ directory structure", + "description": "Document standard location in repos for distributed tracking files", + "acceptance_criteria": [ + "knowledge/distributed-tracking/structure.md exists", + "Documents .hq/ directory with: prd.json, claims.json, sync-log.json", + "Each file has JSON schema defined", + "Documents .gitignore recommendations" + ], + "files": ["knowledge/distributed-tracking/structure.md"], + "passes": true, + "notes": "Created structure.md with JSON schemas for prd.json, claims.json, sync-log.json. Includes .gitignore recommendations." + }, + { + "id": "US-002", + "title": "Add push-to-repo function", + "description": "Push PRD/task status to target repo's .hq/ directory", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes push_to_repo instructions", + "Copies PRD data to {target_repo}/.hq/prd.json", + "Includes: full PRD, task status, worker assignments, notes", + "Adds synced_at timestamp and synced_from field", + "Creates .hq/ directory if missing", + "Commits with message: sync: update distributed tracking" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-001"], + "passes": true, + "notes": "Added 'Distributed Tracking - Push to Repo' section to pure-ralph-base.md. Documents push_to_repo function with: mkdir for .hq dir, sync_metadata with synced_at/synced_from/synced_by, what gets synced (full PRD, features, status, notes), example, and commit strategy options." + }, + { + "id": "US-003", + "title": "Add pull-from-repo function", + "description": "Pull latest status from repo before starting work", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes pull_from_repo instructions", + "Reads {target_repo}/.hq/prd.json if exists", + "Compares with local projects/{name}/prd.json", + "Returns diff summary (tasks added, changed, removed)", + "Does NOT auto-overwrite local" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-001"], + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation task adding instructions to prompt file. Added 'Distributed Tracking - Pull from Repo' section with: pull_from_repo function steps, diff detection logic comparing by task ID, comparison table for fields, example output format, and explicit no-auto-overwrite policy." + }, + { + "id": "US-004", + "title": "Add conflict detection and merge", + "description": "Detect conflicts between local and repo PRD, merge intelligently", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes conflict resolution instructions", + "When local and repo differ: show task-level diff", + "Merge strategy: per-task, newer updated_at wins", + "User prompted to confirm merge", + "Merged result written to both local and repo" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-003"], + "passes": false, + "notes": "" + }, + { + "id": "US-005", + "title": "Add duplicate work detection", + "description": "Warn when planning work that already exists in repo", + "acceptance_criteria": [ + ".claude/commands/prd.md includes duplicate check step", + "On PRD creation: check if .hq/prd.json exists in target repo", + "If exists: show existing tasks, ask add or create separate", + "Fuzzy match task titles to catch near-duplicates", + "Warning shown before PRD is saved" + ], + "files": [".claude/commands/prd.md"], + "dependsOn": ["US-001"], + "passes": false, + "notes": "" + }, + { + "id": "US-006", + "title": "Add task claim mechanism", + "description": "Claim tasks before starting to prevent conflicts", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md includes claim instructions", + "claims.json schema: task_id, claimed_by, claimed_at, expires_at", + "Before task: check if claimed by someone else", + "If claimed: show warning with claimer info and timestamp", + "Claims expire after 24h by default", + "On task complete: release claim" + ], + "files": ["prompts/pure-ralph-base.md", "knowledge/distributed-tracking/structure.md"], + "dependsOn": ["US-001"], + "passes": false, + "notes": "" + }, + { + "id": "US-007", + "title": "Integrate with pure-ralph loop", + "description": "Automatic sync during pure-ralph execution", + "acceptance_criteria": [ + "prompts/pure-ralph-base.md updated with sync workflow", + "On loop start: pull from repo, warn on conflicts", + "Before each task: check claim, claim if available", + "After each task: push status to repo", + "On loop complete: push final, release claims" + ], + "files": ["prompts/pure-ralph-base.md"], + "dependsOn": ["US-002", "US-003", "US-006"], + "passes": false, + "notes": "" + }, + { + "id": "US-008", + "title": "Add /sync-tasks slash command", + "description": "Manual sync command for ad-hoc status checks", + "acceptance_criteria": [ + ".claude/commands/sync-tasks.md exists", + "/sync-tasks {project} pulls and shows status diff", + "/sync-tasks {project} --push pushes local to repo", + "/sync-tasks {project} --claim {task-id} claims specific task", + "Shows clear summary of sync result" + ], + "files": [".claude/commands/sync-tasks.md"], + "dependsOn": ["US-002", "US-003", "US-006"], + "passes": false, + "notes": "" + }, + { + "id": "US-009", + "title": "Document distributed workflow", + "description": "Comprehensive documentation for contributors", + "acceptance_criteria": [ + "knowledge/distributed-tracking/workflow.md exists", + "Documents full sync lifecycle", + "Includes troubleshooting for common conflicts", + "Includes examples of claim/release flow" + ], + "files": ["knowledge/distributed-tracking/workflow.md"], + "dependsOn": ["US-007"], + "passes": false, + "notes": "" + } + ], + "metadata": { + "created_at": "2026-01-27T12:00:00Z", + "created_by": "stefan", + "purpose": "Enable distributed teams to share PRD/task status via git" + }, + "sync_metadata": { + "synced_at": "2026-01-27T08:42:58-08:00", + "synced_from": "C:/my-hq/projects/distributed-tracking/prd.json", + "synced_by": "pure-ralph" + } +} diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index 70938c3..508d801 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -49,8 +49,8 @@ ], "files": ["prompts/pure-ralph-base.md"], "dependsOn": ["US-001"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation task adding instructions to prompt file. Added 'Distributed Tracking - Pull from Repo' section with: pull_from_repo function steps, diff detection logic comparing by task ID, comparison table for fields, example output format, and explicit no-auto-overwrite policy." }, { "id": "US-004", diff --git a/prompts/pure-ralph-base.md b/prompts/pure-ralph-base.md index 86e04f5..4e9e616 100644 --- a/prompts/pure-ralph-base.md +++ b/prompts/pure-ralph-base.md @@ -488,6 +488,114 @@ The combined approach is preferred as it keeps task completion and status in ato --- +## Distributed Tracking - Pull from Repo + +Before starting work, check if the target repo has distributed tracking data that may contain updates from other contributors. + +### pull_from_repo Function + +Execute this at the start of each Pure Ralph session (after branch verification, before task selection): + +``` +PULL_FROM_REPO: + 1. Check if distributed tracking file exists: + if [ -f "{target_repo}/.hq/prd.json" ]; then + echo "Distributed tracking found" + else + echo "No distributed tracking - skip pull" + # Continue with local PRD only + fi + + 2. If exists, read both files: + - Remote: {target_repo}/.hq/prd.json + - Local: {{PRD_PATH}} + + 3. Compare features arrays by task ID: + For each task, check: + - passes: local vs remote (has status changed?) + - notes: local vs remote (has implementation detail changed?) + - acceptance_criteria: local vs remote (has scope changed?) + + 4. Generate diff summary (DO NOT auto-overwrite): + DIFF SUMMARY: + - Tasks added in repo: [list task IDs not in local] + - Tasks removed in repo: [list task IDs not in repo] + - Tasks with different status: [list task IDs where passes differs] + - Tasks with updated notes: [list task IDs where notes differs] + + 5. If differences found, WARN but continue: + "WARNING: Local and repo PRDs differ. Review before proceeding." + "Use /sync-tasks {project} to merge changes." +``` + +### Diff Detection Logic + +Compare tasks by ID and report differences: + +``` +For each task in LOCAL PRD: + If task.id NOT in REPO → "Task {id} exists locally but not in repo" + If task.passes != repo_task.passes → "Task {id} status differs (local: {x}, repo: {y})" + If task.notes != repo_task.notes → "Task {id} notes differ" + +For each task in REPO PRD: + If task.id NOT in LOCAL → "Task {id} exists in repo but not locally" +``` + +### What Gets Compared + +| Field | Compare? | Why | +|-------|----------|-----| +| `id` | Key | Used to match tasks across PRDs | +| `passes` | Yes | Status changes indicate work done | +| `notes` | Yes | Implementation details may have changed | +| `acceptance_criteria` | Yes | Scope changes need attention | +| `title` | No | Minor wording changes don't matter | +| `description` | No | Details don't affect task matching | +| `dependsOn` | Yes | Dependency changes affect execution order | + +### Example Output + +``` +PULL_FROM_REPO: Checking {target_repo}/.hq/prd.json... + +DIFF SUMMARY: +┌─────────────────────────────────────────────────────────┐ +│ Tasks with different status: │ +│ - US-003: local=false, repo=true │ +│ - US-005: local=false, repo=true │ +│ │ +│ Tasks with updated notes: │ +│ - US-003: "Worker: backend-dev. Implemented..." │ +│ │ +│ Tasks added in repo (not in local): │ +│ - US-010: "Add retry logic for sync failures" │ +└─────────────────────────────────────────────────────────┘ + +WARNING: Local and repo PRDs differ. +- 2 tasks completed in repo but not locally +- 1 new task exists in repo + +Recommendation: Run conflict resolution before continuing. +``` + +### Important: No Auto-Overwrite + +The pull_from_repo function: +- **READS** the repo PRD +- **COMPARES** with local PRD +- **REPORTS** differences +- **DOES NOT** automatically overwrite either file + +This is intentional - automatic overwrites could: +- Lose local work in progress +- Create confusing state if tasks were worked on in parallel +- Make debugging harder when things go wrong + +Conflict resolution (US-004) handles the merge decision. + +--- + ## Self-Improvement This prompt can evolve. If you learn something valuable: From 3622a6d1dc4f5ee5f8584e299ca74739e0838a71 Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 09:00:26 -0800 Subject: [PATCH 04/10] feat(US-004): Add conflict detection and merge instructions Added 'Distributed Tracking - Conflict Resolution' section to pure-ralph-base.md: - Task-level diff display format - Merge strategy: per-task, newer updated_at wins - User confirmation prompt with y/n/manual options - Manual resolution flow for ambiguous conflicts - Write-to-both-locations process - Conflict states table Co-Authored-By: Claude Opus 4.5 --- projects/distributed-tracking/prd.json | 4 +- prompts/pure-ralph-base.md | 186 ++++++++++++++++++++++++- 2 files changed, 187 insertions(+), 3 deletions(-) diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index 508d801..ac874bf 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -65,8 +65,8 @@ ], "files": ["prompts/pure-ralph-base.md"], "dependsOn": ["US-003"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation task adding instructions to prompt file. Added 'Distributed Tracking - Conflict Resolution' section with: task-level diff display format, merge strategy (per-task, newer updated_at wins), updated_at requirement documentation, user confirmation prompt with y/n/manual options, manual resolution flow, write-to-both-locations process, example merge flow, and conflict states table." }, { "id": "US-005", diff --git a/prompts/pure-ralph-base.md b/prompts/pure-ralph-base.md index 4e9e616..ed055aa 100644 --- a/prompts/pure-ralph-base.md +++ b/prompts/pure-ralph-base.md @@ -592,7 +592,191 @@ This is intentional - automatic overwrites could: - Create confusing state if tasks were worked on in parallel - Make debugging harder when things go wrong -Conflict resolution (US-004) handles the merge decision. +Conflict resolution (below) handles the merge decision. + +--- + +## Distributed Tracking - Conflict Resolution + +When local and repo PRDs differ, use this process to resolve conflicts and merge changes. + +### When to Use + +Run conflict resolution when: +- `pull_from_repo` reports differences +- You're about to start work and suspect others have been working on the same project +- Manual sync via `/sync-tasks` detects conflicts + +### Task-Level Diff Display + +For each task with differences, show a detailed comparison: + +``` +CONFLICT: Task {task_id} - {title} +┌─────────────────────────────────────────────────────────────┐ +│ Field │ Local │ Repo │ +├────────────────┼──────────────────────┼─────────────────────┤ +│ passes │ false │ true │ +│ notes │ (empty) │ "Worker: backend..."│ +│ updated_at │ 2026-01-26T10:00:00Z │ 2026-01-27T14:30:00Z│ +└─────────────────────────────────────────────────────────────┘ + +Repo is newer (2026-01-27T14:30:00Z vs 2026-01-26T10:00:00Z) +Recommendation: Accept repo version +``` + +### Merge Strategy: Per-Task, Newer Wins + +The merge strategy operates at the **task level**, not the PRD level: + +``` +MERGE_STRATEGY: + For each task in either PRD: + 1. If task exists only in LOCAL → keep in merged result + 2. If task exists only in REPO → add to merged result + 3. If task exists in BOTH with differences: + a. Compare updated_at timestamps + b. If repo.updated_at > local.updated_at → use repo version + c. If local.updated_at > repo.updated_at → use local version + d. If timestamps equal or missing → prompt user +``` + +### updated_at Requirement + +For conflict resolution to work automatically, tasks should include `updated_at`: + +```json +{ + "id": "US-003", + "title": "Add pull-from-repo function", + "passes": true, + "notes": "Worker: backend-dev...", + "updated_at": "2026-01-27T14:30:00Z" +} +``` + +**Important:** When updating a task's `passes` or `notes`, always update `updated_at` to current timestamp. + +If `updated_at` is missing from both versions, fall back to manual resolution. + +### User Confirmation Prompt + +Before applying any merge, prompt the user: + +``` +MERGE PREVIEW: +┌─────────────────────────────────────────────────────────────┐ +│ Changes to apply: │ +│ │ +│ ACCEPT FROM REPO (newer): │ +│ - US-003: passes false → true │ +│ - US-003: notes updated with implementation details │ +│ │ +│ KEEP LOCAL (newer): │ +│ - US-007: acceptance_criteria refined │ +│ │ +│ ADD FROM REPO (new tasks): │ +│ - US-010: "Add retry logic for sync failures" │ +│ │ +│ REQUIRES MANUAL DECISION (no timestamp or equal): │ +│ - US-005: Both modified, cannot auto-resolve │ +└─────────────────────────────────────────────────────────────┘ + +Proceed with merge? [y/n/manual] +- y: Apply automatic resolution for timestamped tasks, skip manual ones +- n: Cancel merge, keep local unchanged +- manual: Review each conflict individually +``` + +### Manual Resolution (Interactive) + +When user selects `manual` or for tasks without timestamps: + +``` +CONFLICT: US-005 - Add duplicate work detection +No clear winner (timestamps missing or equal) + +LOCAL version: + passes: false + notes: "Started implementation, WIP" + +REPO version: + passes: false + notes: "Blocked on US-001 clarification" + +Choose: + [L] Use LOCAL version + [R] Use REPO version + [M] Merge manually (edit notes) + [S] Skip (leave in conflict state) + +Selection: _ +``` + +### Writing Merged Result + +After user confirms, write to BOTH locations: + +``` +APPLY_MERGE: + 1. Construct merged PRD: + - Start with local PRD as base + - Apply resolved changes per task + - Update sync_metadata.merged_at = now() + - Add sync_metadata.merge_source = "conflict_resolution" + + 2. Write to local PRD: + {{PRD_PATH}} + + 3. Write to repo distributed tracking: + {target_repo}/.hq/prd.json + + 4. Report success: + "Merge complete. Written to both local and repo." +``` + +### Example Merge Flow + +``` +$ Starting Pure Ralph session... + +PULL_FROM_REPO: Checking C:/my-repo/.hq/prd.json... +Found differences - initiating conflict resolution. + +CONFLICT: US-003 - Add pull-from-repo function +┌─────────────────────────────────────────────────────────────┐ +│ Field │ Local │ Repo │ +├────────────────┼──────────────────────┼─────────────────────┤ +│ passes │ false │ true │ +│ notes │ (empty) │ "Worker: backend..."│ +│ updated_at │ - │ 2026-01-27T14:30:00Z│ +└─────────────────────────────────────────────────────────────┘ +Repo has timestamp, local doesn't → Accept repo version + +MERGE PREVIEW: + ACCEPT FROM REPO: US-003 (completed by another contributor) + +Proceed with merge? [y/n/manual]: y + +Applying merge... +✓ Updated local PRD: C:/my-hq/projects/my-project/prd.json +✓ Updated repo PRD: C:/my-repo/.hq/prd.json + +Merge complete. Continuing with task selection... +``` + +### Conflict States + +Tasks can be in these conflict states: + +| State | Meaning | Resolution | +|-------|---------|------------| +| `no_conflict` | Local and repo match | No action needed | +| `repo_newer` | Repo has newer updated_at | Auto-accept repo | +| `local_newer` | Local has newer updated_at | Auto-keep local | +| `manual_required` | No timestamps or equal | User decides | +| `new_in_repo` | Task only in repo | Auto-add to local | +| `new_in_local` | Task only in local | Auto-add to repo | --- From 9937b77a51e9a0e82e19216aefe81a354882906b Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 09:03:35 -0800 Subject: [PATCH 05/10] feat(US-005): Add duplicate work detection to /prd command - Add Step 2.5 to check for existing .hq/prd.json in target repo - Show existing tasks table when distributed tracking found - Fuzzy match user's description against existing task titles - Prompt user: add to existing, create separate, or cancel Co-Authored-By: Claude Opus 4.5 --- .claude/commands/prd.md | 46 ++++++++++++++++++++++++++ projects/distributed-tracking/prd.json | 4 +-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/.claude/commands/prd.md b/.claude/commands/prd.md index 794fbf8..50af39b 100644 --- a/.claude/commands/prd.md +++ b/.claude/commands/prd.md @@ -51,6 +51,52 @@ Ask for project slug. Check if `projects/{name}` exists: - If exists: "Project exists. Continue editing or choose different name?" - If new: proceed +## Step 2.5: Check for Duplicate Work (Distributed Tracking) + +Before starting discovery, check if work already exists in the target repo: + +```bash +# Check if distributed tracking exists in target repo +TARGET_REPO="${TARGET_REPO:-$(pwd)}" +if [ -f "$TARGET_REPO/.hq/prd.json" ]; then + cat "$TARGET_REPO/.hq/prd.json" +fi +``` + +**If `.hq/prd.json` exists:** + +1. Parse and show existing tasks: + ``` + Found existing distributed work in this repo: + + | ID | Title | Status | + |----|-------|--------| + | US-001 | Example task | ✓ complete | + | US-002 | Another task | pending | + ``` + +2. Fuzzy match user's description against existing task titles: + - Normalize: lowercase, remove punctuation + - Check for: exact match, contains match, word overlap > 50% + - If match found: + ``` + ⚠️ Potential duplicate detected: + Your request: "add user authentication" + Existing task: "US-003: Add user auth flow" (pending) + + Similarity: 78% word overlap + ``` + +3. Ask user before proceeding: + ``` + Options: + A. Add to existing project (extend .hq/prd.json) + B. Create separate project (new projects/{name}/) + C. Cancel and review existing work first + ``` + +**If no `.hq/prd.json` exists:** Proceed to Step 3. + ## Step 3: Discovery Interview Ask questions in batches. Format: diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index ac874bf..cd54de0 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -81,8 +81,8 @@ ], "files": [".claude/commands/prd.md"], "dependsOn": ["US-001"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Added Step 2.5 'Check for Duplicate Work (Distributed Tracking)' to prd.md. Includes: bash script to check for .hq/prd.json, task table display, fuzzy matching logic (normalize, exact/contains/word overlap >50%), and A/B/C prompt before proceeding." }, { "id": "US-006", From e5fa3db41e1808bf2c059047f7eaa881803b5f24 Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 09:25:15 -0800 Subject: [PATCH 06/10] feat(US-006): Add task claim mechanism to distributed tracking Add claim instructions to pure-ralph-base.md including: - check_claim function for verifying task availability - claim_task function with 24h expiration default - release_claim function for task completion - Warning display format for claimed tasks - Integration with task selection flow Co-Authored-By: Claude Opus 4.5 --- projects/distributed-tracking/prd.json | 27 ++- prompts/pure-ralph-base.md | 247 +++++++++++++++++++------ 2 files changed, 220 insertions(+), 54 deletions(-) diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index cd54de0..a8d5d83 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -98,8 +98,8 @@ ], "files": ["prompts/pure-ralph-base.md", "knowledge/distributed-tracking/structure.md"], "dependsOn": ["US-001"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation task adding instructions to prompt file. Added 'Distributed Tracking - Task Claims' section with: check_claim function (reads claims.json, checks expiration, shows warning), claim_task function (generates claim record, 24h expiration), release_claim function (removes claim on completion), claim identifier formats, warning display format, and integration with task selection flow. claims.json schema was already defined in structure.md." }, { "id": "US-007", @@ -147,6 +147,29 @@ "dependsOn": ["US-007"], "passes": false, "notes": "" + }, + { + "id": "US-010", + "title": "Add prompt templating to .hq/ directory", + "description": "Move Ralph prompt into target repo so it can evolve with the project. PRD path is no longer injected - prompt reads from .hq/prd.json directly.", + "acceptance_criteria": [ + "knowledge/distributed-tracking/structure.md updated to include prompt.md in .hq/ directory", + ".claude/scripts/pure-ralph-loop.ps1 checks for .hq/prompt.md in target repo", + "If .hq/prompt.md missing: copy from HQ/prompts/pure-ralph-base.md to target repo", + "Script uses .hq/prompt.md instead of HQ prompt", + "Prompt references .hq/prd.json directly (no {{PRD_PATH}} substitution needed)", + ".claude/scripts/pure-ralph-loop.sh has same behavior", + "prompts/pure-ralph-base.md updated to use .hq/prd.json path instead of {{PRD_PATH}}" + ], + "files": [ + "knowledge/distributed-tracking/structure.md", + ".claude/scripts/pure-ralph-loop.ps1", + ".claude/scripts/pure-ralph-loop.sh", + "prompts/pure-ralph-base.md" + ], + "dependsOn": ["US-001"], + "passes": false, + "notes": "" } ], "metadata": { diff --git a/prompts/pure-ralph-base.md b/prompts/pure-ralph-base.md index ed055aa..f3f4971 100644 --- a/prompts/pure-ralph-base.md +++ b/prompts/pure-ralph-base.md @@ -31,54 +31,6 @@ Extract the project name from the PRD path (e.g., `projects/my-feature/prd.json` --- -## Conflict Awareness - -Pure Ralph sessions may run concurrently. A lock file prevents conflicts. - -### Lock File Location - -``` -{target_repo}/.pure-ralph.lock -``` - -### On Session Start: Check for Lock File - -After switching to the feature branch, check if a lock file exists: - -```bash -LOCK_FILE="{{TARGET_REPO}}/.pure-ralph.lock" -if [ -f "$LOCK_FILE" ]; then - echo "WARNING: Lock file detected" - cat "$LOCK_FILE" -fi -``` - -### If Lock File Found - -1. **Read the lock file** to see which project owns it: - ```json - {"project": "other-project", "pid": 12345, "started_at": "2026-01-26T..."} - ``` - -2. **Check if the process is still running:** - - **Process running:** Another Pure Ralph is active. You should WAIT or inform the user. - - **Process NOT running:** This is a **stale lock**. Safe to remove and continue. - -3. **Removing a stale lock:** - ```bash - # Only if process is NOT running - rm "{{TARGET_REPO}}/.pure-ralph.lock" - ``` - -### Important Notes - -- The orchestrator script creates/removes lock files automatically -- Claude sessions don't create lock files - they only CHECK for them -- If you see a lock from your OWN project (same project name), it's expected - the orchestrator is managing it -- Only worry about locks from DIFFERENT projects on the same repo - ---- - ## Commit Safety **HARD BLOCK: Never commit to main/master** @@ -780,6 +732,201 @@ Tasks can be in these conflict states: --- +## Distributed Tracking - Task Claims + +Before starting any task, check if it's claimed by another contributor. This prevents duplicate work in distributed teams. + +### Claim Lifecycle + +1. **Before task:** Check if claimed by someone else +2. **If available:** Claim the task +3. **Work on task:** Implement and complete +4. **After task:** Release the claim + +### check_claim Function + +Execute before starting any task: + +``` +CHECK_CLAIM: + 1. Read claims file (create if missing): + claims_path = {target_repo}/.hq/claims.json + if [ ! -f "$claims_path" ]; then + echo '{"claims": [], "updated_at": null}' > "$claims_path" + fi + + 2. Parse claims and find matching task: + For claim in claims.claims: + if claim.task_id == selected_task.id: + Check if expired (claim.expires_at < now) + If NOT expired → CLAIMED by someone else + If expired → Available (stale claim) + + 3. If claimed by someone else (not expired): + ┌─────────────────────────────────────────────────────────────┐ + │ WARNING: Task {task_id} is claimed │ + │ │ + │ Claimed by: {claimed_by} │ + │ Claimed at: {claimed_at} │ + │ Expires at: {expires_at} │ + │ │ + │ Options: │ + │ [S] Skip - pick a different task │ + │ [W] Wait - task may be released soon │ + │ [O] Override - claim anyway (use with caution) │ + └─────────────────────────────────────────────────────────────┘ + + 4. If available (no claim or expired): + Proceed to claim_task +``` + +### claim_task Function + +Claim a task before starting work: + +``` +CLAIM_TASK: + 1. Generate claim record: + { + "task_id": "{selected_task.id}", + "claimed_by": "{identifier}", // e.g., "pure-ralph-{hostname}" or username + "claimed_at": "{ISO 8601 now}", + "expires_at": "{ISO 8601 now + 24 hours}", + "notes": "Working on: {task_title}" + } + + 2. Read current claims.json + + 3. Remove any existing claim for this task_id (expired or otherwise) + + 4. Add new claim to claims array + + 5. Update claims.updated_at to now + + 6. Write updated claims.json to {target_repo}/.hq/claims.json + + 7. Commit: + git add {target_repo}/.hq/claims.json + git commit -m "claim: {task_id} by {claimed_by}" +``` + +### Claim Expiration + +Claims expire after **24 hours** by default. This prevents indefinite blocking if: +- A contributor abandons work +- A session crashes without releasing +- Someone forgets to release + +``` +EXPIRATION_RULES: + - Default: 24 hours from claimed_at + - Expired claims: Automatically considered "available" + - Override: Can claim even if not expired (with warning) + - Refresh: Re-claiming extends expiration +``` + +To calculate expires_at: +``` +expires_at = claimed_at + 24 hours +// Example: claimed_at 2026-01-27T10:00:00Z → expires_at 2026-01-28T10:00:00Z +``` + +### release_claim Function + +Release a claim after task completion: + +``` +RELEASE_CLAIM: + 1. Read claims.json from {target_repo}/.hq/claims.json + + 2. Remove claim matching task_id: + claims.claims = claims.claims.filter(c => c.task_id != completed_task.id) + + 3. Update claims.updated_at to now + + 4. Write updated claims.json + + 5. Include in task completion commit: + git add {target_repo}/.hq/claims.json + // Include with feat(TASK-ID) commit, no separate commit needed +``` + +### Claim Identifier + +The `claimed_by` field should uniquely identify the claimer: + +| Context | Format | Example | +|---------|--------|---------| +| Pure Ralph | `pure-ralph-{hostname}` | `pure-ralph-DESKTOP-ABC` | +| User session | `{username}` | `stefan` | +| CI/CD | `ci-{pipeline-id}` | `ci-12345` | +| Unknown | `anonymous-{timestamp}` | `anonymous-1706360000` | + +### Warning Display + +When a task is claimed, show a prominent warning: + +``` +╔═══════════════════════════════════════════════════════════════╗ +║ ⚠️ TASK CLAIMED ║ +╠═══════════════════════════════════════════════════════════════╣ +║ ║ +║ Task: US-006 - Add task claim mechanism ║ +║ Claimed by: pure-ralph-WORKSTATION ║ +║ Since: 2026-01-27T14:30:00Z (2 hours ago) ║ +║ Expires: 2026-01-28T14:30:00Z (in 22 hours) ║ +║ ║ +║ This task is being worked on by another contributor. ║ +║ Claiming it may result in duplicate work. ║ +║ ║ +╚═══════════════════════════════════════════════════════════════╝ + +Select action: [S]kip / [W]ait / [O]verride: _ +``` + +### Integration with Task Selection + +The claim check integrates into the task selection flow: + +``` +TASK_SELECTION_WITH_CLAIMS: + 1. Find eligible tasks (passes=false, dependencies met) + 2. For each eligible task: + a. check_claim(task.id) + b. If claimed by others (not expired): mark as "claimed" + c. If available: mark as "available" + 3. Prefer "available" tasks over "claimed" tasks + 4. If only claimed tasks remain: show warning, offer options + 5. On task selection: claim_task(selected_task.id) + 6. After task completion: release_claim(task.id) +``` + +### Example claims.json + +```json +{ + "claims": [ + { + "task_id": "US-006", + "claimed_by": "pure-ralph-WORKSTATION", + "claimed_at": "2026-01-27T14:30:00Z", + "expires_at": "2026-01-28T14:30:00Z", + "notes": "Working on: Add task claim mechanism" + }, + { + "task_id": "US-010", + "claimed_by": "stefan", + "claimed_at": "2026-01-27T12:00:00Z", + "expires_at": "2026-01-28T12:00:00Z", + "notes": "Manual claim for prompt templating work" + } + ], + "updated_at": "2026-01-27T14:30:00Z" +} +``` + +--- + ## Self-Improvement This prompt can evolve. If you learn something valuable: @@ -817,10 +964,6 @@ Only add patterns that: **Pattern:** Check `git branch --show-current` immediately before committing; abort if on main/master **Why:** Hard block prevents accidental commits to main; recovery after commit is harder than prevention -### [Conflict] Stale Lock Detection -**Pattern:** If lock file exists but PID is not running, remove the stale lock and continue -**Why:** Stale locks from crashed sessions shouldn't block future execution; checking process status distinguishes active vs stale locks - --- ## PR Creation (When All Tasks Complete) From ee63f14597ee49958f85c0b63efeb07e0d92adb4 Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 09:28:51 -0800 Subject: [PATCH 07/10] feat(US-007): Integrate distributed tracking with pure-ralph loop Add comprehensive workflow section that ties together pull, push, claim, and conflict resolution functions into the Pure Ralph session lifecycle. Updates "Your Job" checklist with sync, claim, push, and release steps. Co-Authored-By: Claude Opus 4.5 --- projects/distributed-tracking/prd.json | 5 +- prompts/pure-ralph-base.md | 189 +++++++++++++++++++++++-- 2 files changed, 184 insertions(+), 10 deletions(-) diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index a8d5d83..fe86d21 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -114,8 +114,9 @@ ], "files": ["prompts/pure-ralph-base.md"], "dependsOn": ["US-002", "US-003", "US-006"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation task adding workflow instructions to prompt file. Added 'Distributed Tracking - Integrated Workflow' section with: session lifecycle diagram, LOOP_START (pull + conflicts), BEFORE_TASK (check claims, display status, claim), AFTER_TASK (push + release), LOOP_COMPLETE (final push, verify claims, create PR), error recovery table, and quick reference table. Updated 'Your Job (Every Session)' section to include sync, claim, push, and release steps.", + "updated_at": "2026-01-27T19:30:00Z" }, { "id": "US-008", diff --git a/prompts/pure-ralph-base.md b/prompts/pure-ralph-base.md index f3f4971..5be37ea 100644 --- a/prompts/pure-ralph-base.md +++ b/prompts/pure-ralph-base.md @@ -61,14 +61,17 @@ This is a **HARD BLOCK**, not a warning. Committing to main is NEVER acceptable ## Your Job (Every Session) 1. **BRANCH** - Ensure you're on `feature/{{PROJECT_NAME}}` (create if needed) -2. **READ** the PRD at {{PRD_PATH}} -3. **PICK** the highest priority incomplete task (where `passes` is false/null and dependencies are met) -4. **IMPLEMENT** that ONE task -5. **UPDATE** the PRD: set `passes: true` and fill in `notes` with what you did -6. **COMMIT** with message: `feat(TASK-ID): Brief description` -7. **CHECK** if all tasks complete: - - **If more tasks remain:** EXIT - the loop will spawn a fresh session - - **If all tasks complete:** CREATE PR (see "PR Creation" section below), then EXIT +2. **SYNC** - Pull from repo, resolve any conflicts (see "Distributed Tracking - Integrated Workflow") +3. **READ** the PRD at {{PRD_PATH}} +4. **PICK** the highest priority incomplete task (check claims, prefer unclaimed tasks) +5. **CLAIM** the selected task before starting work +6. **IMPLEMENT** that ONE task +7. **UPDATE** the PRD: set `passes: true`, fill in `notes`, add `updated_at` timestamp +8. **PUSH** - Push status to repo, release claim +9. **COMMIT** with message: `feat(TASK-ID): Brief description` (include `.hq/` files) +10. **CHECK** if all tasks complete: + - **If more tasks remain:** EXIT - the loop will spawn a fresh session + - **If all tasks complete:** Final push, CREATE PR (see "PR Creation" section below), then EXIT --- @@ -927,6 +930,176 @@ TASK_SELECTION_WITH_CLAIMS: --- +## Distributed Tracking - Integrated Workflow + +This section ties together all distributed tracking functions into the Pure Ralph loop lifecycle. Follow this workflow every session. + +### Session Lifecycle with Distributed Tracking + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ PURE RALPH SESSION │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. BRANCH VERIFICATION │ +│ └── Ensure on feature/{project-name} │ +│ │ +│ 2. DISTRIBUTED SYNC (start of session) ← NEW │ +│ ├── pull_from_repo() │ +│ ├── If conflicts → run conflict resolution │ +│ └── Continue with synced PRD │ +│ │ +│ 3. TASK SELECTION │ +│ ├── Find eligible tasks (passes=false, deps met) │ +│ ├── check_claim() for each candidate ← NEW │ +│ ├── Prefer unclaimed tasks │ +│ └── claim_task() on selected task ← NEW │ +│ │ +│ 4. IMPLEMENTATION │ +│ └── Complete the task │ +│ │ +│ 5. PRD UPDATE │ +│ ├── Set passes: true, add notes │ +│ └── Add updated_at timestamp ← NEW │ +│ │ +│ 6. POST-TASK SYNC ← NEW │ +│ ├── push_to_repo() │ +│ └── release_claim() │ +│ │ +│ 7. COMMIT │ +│ └── Include .hq/ files in commit │ +│ │ +│ 8. LOOP CHECK │ +│ ├── If more tasks → EXIT (new session) │ +│ └── If all complete → push final, create PR │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### On Loop Start (After Branch Verification) + +Execute before reading the PRD: + +``` +LOOP_START: + 1. pull_from_repo() + - Check if {target_repo}/.hq/prd.json exists + - Compare with local {{PRD_PATH}} + - Generate diff summary + + 2. If differences found: + - Show diff summary + - Run conflict resolution (see Conflict Resolution section) + - Apply merge if user approves + - Continue with merged PRD + + 3. If no differences or no .hq/prd.json: + - Continue with local PRD +``` + +### Before Each Task (During Task Selection) + +Execute after identifying eligible tasks, before selecting one: + +``` +BEFORE_TASK: + 1. List all eligible tasks (passes=false, dependencies met) + + 2. For each eligible task: + check_claim(task.id) + - If claimed (not expired): mark as "claimed by {x}" + - If available (no claim or expired): mark as "available" + + 3. Display task list with claim status: + ┌──────────────────────────────────────────────────────────┐ + │ Eligible Tasks: │ + │ US-007 [AVAILABLE] - Integrate with pure-ralph loop │ + │ US-008 [CLAIMED by stefan, 2h ago] - Add /sync-tasks │ + │ US-010 [AVAILABLE] - Add prompt templating │ + └──────────────────────────────────────────────────────────┘ + + 4. Select an AVAILABLE task (prefer available over claimed) + + 5. claim_task(selected_task.id) + - Write claim to {target_repo}/.hq/claims.json + - Claim expires in 24 hours +``` + +### After Each Task (Before Commit) + +Execute after updating PRD, before committing: + +``` +AFTER_TASK: + 1. Ensure PRD has updated_at on the completed task: + { + "id": "{task_id}", + "passes": true, + "notes": "...", + "updated_at": "{ISO 8601 now}" ← Required for conflict resolution + } + + 2. push_to_repo() + - Write updated PRD to {target_repo}/.hq/prd.json + - Include sync_metadata + + 3. release_claim(task.id) + - Remove claim from {target_repo}/.hq/claims.json + + 4. Stage distributed tracking files with task files: + git add {task_files} {target_repo}/.hq/prd.json {target_repo}/.hq/claims.json +``` + +### On Loop Complete (All Tasks Done) + +Execute when all tasks have passes=true: + +``` +LOOP_COMPLETE: + 1. Final push_to_repo() + - Ensure .hq/prd.json reflects all completed tasks + + 2. Verify no orphaned claims: + - Read claims.json + - Remove any claims for this session (should already be released) + - Commit if changes made + + 3. Create PR (see PR Creation section) + - Include .hq/ directory in PR + - PR enables distributed visibility of completed work +``` + +### Error Recovery + +If a session crashes or exits unexpectedly: + +| Situation | Recovery | +|-----------|----------| +| Task claimed but not completed | Claim expires in 24h; next session can claim | +| PRD updated locally but not pushed | Next session will push; conflict resolution handles | +| Claim not released after completion | Claim expires automatically; no manual action needed | +| Merge conflict on .hq/claims.json | Use git merge strategy; newer timestamps win | + +### Quick Reference: Session Steps + +Updated session workflow with distributed tracking: + +| Step | Action | Distributed Tracking | +|------|--------|---------------------| +| 1 | Verify branch | - | +| 2 | **Sync** | pull_from_repo, resolve conflicts | +| 3 | Read PRD | - | +| 4 | Pick task | check_claim for each, prefer unclaimed | +| 5 | **Claim** | claim_task before starting | +| 6 | Implement | - | +| 7 | Update PRD | Include updated_at | +| 8 | **Push** | push_to_repo | +| 9 | **Release** | release_claim | +| 10 | Commit | Include .hq/ files | +| 11 | Check complete | If all done: final push, create PR | + +--- + ## Self-Improvement This prompt can evolve. If you learn something valuable: From c801d4a2836302ae7642d91d6d267a17dd25dd1b Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 09:32:36 -0800 Subject: [PATCH 08/10] feat(US-008): Add /sync-tasks slash command Manual sync command for distributed tracking: - Default mode: pull and show status diff table - --push: push local PRD to repo's .hq/ - --claim {id}: claim a specific task - --release {id}: release a claim Co-Authored-By: Claude Opus 4.5 --- .claude/commands/sync-tasks.md | 254 +++++++++++++++++++++++++ projects/distributed-tracking/prd.json | 5 +- 2 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 .claude/commands/sync-tasks.md diff --git a/.claude/commands/sync-tasks.md b/.claude/commands/sync-tasks.md new file mode 100644 index 0000000..39e7c91 --- /dev/null +++ b/.claude/commands/sync-tasks.md @@ -0,0 +1,254 @@ +# /sync-tasks - Manual Distributed Tracking Sync + +Manual sync command for checking task status, pushing updates, and claiming tasks in distributed projects. + +## Usage + +``` +/sync-tasks {project} # Pull and show status diff +/sync-tasks {project} --push # Push local PRD to repo +/sync-tasks {project} --claim {id} # Claim a specific task +/sync-tasks {project} --release {id} # Release a claim +``` + +## Arguments + +| Argument | Required | Description | +|----------|----------|-------------| +| `{project}` | Yes | Project name (folder name in `projects/`) | +| `--push` | No | Push local PRD to target repo's `.hq/` | +| `--claim {id}` | No | Claim a specific task ID | +| `--release {id}` | No | Release a claim on a task ID | + +## Steps + +### Default: Pull and Show Status Diff + +1. **Read local PRD:** + ``` + projects/{project}/prd.json + ``` + +2. **Get target repo from PRD:** + Extract `target_repo` field from the PRD. + +3. **Check for distributed tracking:** + ```bash + if [ -f "{target_repo}/.hq/prd.json" ]; then + echo "Distributed tracking found" + else + echo "No distributed tracking in target repo" + echo "Use --push to initialize" + exit 0 + fi + ``` + +4. **Compare PRDs and show diff:** + ``` + SYNC STATUS: {project} + ┌─────────────────────────────────────────────────────────────┐ + │ Local PRD: projects/{project}/prd.json │ + │ Repo PRD: {target_repo}/.hq/prd.json │ + │ Last sync: {sync_metadata.synced_at} │ + ├─────────────────────────────────────────────────────────────┤ + │ TASK STATUS COMPARISON │ + │ │ + │ ID │ Title │ Local │ Repo │ │ + │ ────────┼──────────────────────────┼────────┼────────┼───── │ + │ US-001 │ Define .hq/ structure │ PASS │ PASS │ = │ + │ US-002 │ Add push-to-repo │ PASS │ PASS │ = │ + │ US-003 │ Add pull-from-repo │ FAIL │ PASS │ ← │ + │ US-008 │ Add /sync-tasks │ - │ FAIL │ NEW │ + │ │ + │ Legend: = same, ← repo newer, → local newer, NEW = only one │ + ├─────────────────────────────────────────────────────────────┤ + │ CLAIMS │ + │ │ + │ US-006: claimed by pure-ralph-WORK (expires in 22h) │ + │ US-010: claimed by stefan (expires in 2h) │ + ├─────────────────────────────────────────────────────────────┤ + │ SUMMARY │ + │ Local: 5/10 tasks complete │ + │ Repo: 7/10 tasks complete │ + │ Diff: 2 tasks differ, 0 conflicts │ + └─────────────────────────────────────────────────────────────┘ + ``` + +5. **If differences found, suggest actions:** + ``` + Suggested actions: + - /sync-tasks {project} --push # Push local changes to repo + - /sync-tasks {project} --claim US-008 # Claim a task before starting + ``` + +### With `--push`: Push Local to Repo + +1. **Read local PRD** from `projects/{project}/prd.json` + +2. **Create .hq/ directory if missing:** + ```bash + mkdir -p {target_repo}/.hq + ``` + +3. **Add sync metadata:** + ```json + { + ...full PRD..., + "sync_metadata": { + "synced_at": "{ISO 8601 now}", + "synced_from": "projects/{project}/prd.json", + "synced_by": "sync-tasks-command" + } + } + ``` + +4. **Write to repo:** + ``` + {target_repo}/.hq/prd.json + ``` + +5. **Report result:** + ``` + PUSH COMPLETE + ┌─────────────────────────────────────────────────────────────┐ + │ Pushed: projects/{project}/prd.json │ + │ To: {target_repo}/.hq/prd.json │ + │ At: {synced_at} │ + │ │ + │ Tasks synced: 10 │ + │ Complete: 7, Remaining: 3 │ + └─────────────────────────────────────────────────────────────┘ + + Note: Changes not committed. Run: + git add {target_repo}/.hq/prd.json + git commit -m "sync: update distributed tracking" + ``` + +### With `--claim {task-id}`: Claim a Task + +1. **Verify task exists** in local PRD + +2. **Read or create claims.json:** + ```bash + claims_path="{target_repo}/.hq/claims.json" + if [ ! -f "$claims_path" ]; then + echo '{"claims": [], "updated_at": null}' > "$claims_path" + fi + ``` + +3. **Check if already claimed:** + - If claimed by someone else (not expired): show warning, ask to proceed + - If expired or unclaimed: proceed + +4. **Add claim:** + ```json + { + "task_id": "{task-id}", + "claimed_by": "{username or identifier}", + "claimed_at": "{ISO 8601 now}", + "expires_at": "{ISO 8601 now + 24 hours}", + "notes": "Claimed via /sync-tasks command" + } + ``` + +5. **Write updated claims.json** + +6. **Report result:** + ``` + CLAIM RECORDED + ┌─────────────────────────────────────────────────────────────┐ + │ Task: {task-id} - {task title} │ + │ Claimed: {claimed_at} │ + │ Expires: {expires_at} │ + │ By: {claimed_by} │ + └─────────────────────────────────────────────────────────────┘ + + Note: Commit the claim: + git add {target_repo}/.hq/claims.json + git commit -m "claim: {task-id}" + ``` + +### With `--release {task-id}`: Release a Claim + +1. **Read claims.json** + +2. **Find and remove the claim** for the specified task ID + +3. **Write updated claims.json** + +4. **Report result:** + ``` + CLAIM RELEASED + ┌─────────────────────────────────────────────────────────────┐ + │ Task: {task-id} - {task title} │ + │ Released: {ISO 8601 now} │ + └─────────────────────────────────────────────────────────────┘ + ``` + +## Comparison Logic + +When comparing local and repo PRDs: + +| Field | Compare? | Notes | +|-------|----------|-------| +| `id` | Key | Match tasks by ID | +| `passes` | Yes | Status changes are important | +| `notes` | Yes | Implementation details | +| `updated_at` | Yes | Determines which is newer | +| `title` | No | Minor wording doesn't matter | +| `description` | No | Details don't affect matching | + +### Diff Symbols + +| Symbol | Meaning | +|--------|---------| +| `=` | Same in both | +| `←` | Repo is newer (has updates) | +| `→` | Local is newer | +| `NEW` | Only exists in one | +| `!` | Conflict (both modified) | + +## Error Handling + +| Error | Response | +|-------|----------| +| Project not found | "Project '{project}' not found in projects/" | +| No target_repo in PRD | "PRD missing target_repo field" | +| Task ID not found | "Task '{id}' not found in PRD" | +| Already claimed | Show claim info, ask to override | + +## Examples + +**Check sync status:** +``` +> /sync-tasks distributed-tracking + +SYNC STATUS: distributed-tracking +...shows diff table... +``` + +**Push local changes:** +``` +> /sync-tasks distributed-tracking --push + +PUSH COMPLETE +Pushed 10 tasks to C:/my-hq/.hq/prd.json +``` + +**Claim a task:** +``` +> /sync-tasks distributed-tracking --claim US-008 + +CLAIM RECORDED +Task: US-008 - Add /sync-tasks slash command +Claimed by: stefan +Expires: 2026-01-28T15:30:00Z +``` + +**Release a claim:** +``` +> /sync-tasks distributed-tracking --release US-008 + +CLAIM RELEASED +Task: US-008 - Add /sync-tasks slash command +``` diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index fe86d21..3e4d211 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -131,8 +131,9 @@ ], "files": [".claude/commands/sync-tasks.md"], "dependsOn": ["US-002", "US-003", "US-006"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation/command file creation task. Created sync-tasks.md with: default pull-and-diff mode showing task status comparison table, --push flag for pushing local to repo with sync_metadata, --claim and --release flags for task claim management, clear summary output format, comparison logic documentation, and error handling.", + "updated_at": "2026-01-27T20:00:00Z" }, { "id": "US-009", From b1fcd0598bae3ccc7d7d4e1a98db8ae0ddd151d3 Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 09:35:55 -0800 Subject: [PATCH 09/10] feat(US-009): Document distributed workflow Created comprehensive workflow.md with: - Full sync lifecycle documentation - Claim/release flow examples - Troubleshooting guide for 7 common conflicts - Best practices for distributed teams Co-Authored-By: Claude Opus 4.5 --- knowledge/distributed-tracking/workflow.md | 383 +++++++++++++++++++++ projects/distributed-tracking/prd.json | 5 +- 2 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 knowledge/distributed-tracking/workflow.md diff --git a/knowledge/distributed-tracking/workflow.md b/knowledge/distributed-tracking/workflow.md new file mode 100644 index 0000000..e17db27 --- /dev/null +++ b/knowledge/distributed-tracking/workflow.md @@ -0,0 +1,383 @@ +# Distributed Tracking Workflow Guide + +Comprehensive guide for contributors using distributed tracking to collaborate on projects via git. + +## Overview + +Distributed tracking enables multiple contributors (human or AI) to work on the same project without duplicating work. It uses the `.hq/` directory in target repos to share: +- **PRD status** - Which tasks are done, in progress, or available +- **Claims** - Who is working on what +- **Sync history** - Audit trail of all sync operations + +## Full Sync Lifecycle + +### Session Start + +``` +1. BRANCH VERIFICATION + ├── Check current branch: git branch --show-current + ├── Expected: feature/{project-name} + └── If wrong: checkout or create feature branch + +2. PULL FROM REPO + ├── Check if {target_repo}/.hq/prd.json exists + ├── Compare with local projects/{project}/prd.json + ├── Generate diff summary + └── If conflicts → resolve before continuing + +3. READ PRD + └── Load local PRD (now synced with repo) +``` + +### Task Selection + +``` +4. FIND ELIGIBLE TASKS + ├── Filter: passes=false or null + ├── Filter: all dependsOn tasks have passes=true + └── Result: list of tasks ready for work + +5. CHECK CLAIMS + ├── For each eligible task: + │ └── Read {target_repo}/.hq/claims.json + │ ├── If claimed (not expired) → mark "claimed by X" + │ └── If available → mark "available" + └── Display task list with claim status + +6. SELECT AND CLAIM + ├── Prefer unclaimed tasks + ├── Select one task + └── Write claim to claims.json (expires in 24h) +``` + +### Implementation + +``` +7. DO THE WORK + ├── Implement the task + ├── Follow acceptance criteria + └── Test your changes + +8. UPDATE PRD + ├── Set passes: true + ├── Add notes with worker info and summary + └── Add updated_at timestamp (ISO 8601) +``` + +### Session End + +``` +9. PUSH TO REPO + ├── Write updated PRD to {target_repo}/.hq/prd.json + └── Include sync_metadata + +10. RELEASE CLAIM + └── Remove your claim from claims.json + +11. COMMIT + ├── Stage task files + ├── Stage .hq/prd.json and .hq/claims.json + └── Commit: "feat({task-id}): Brief description" + +12. CHECK COMPLETION + ├── If more tasks remain → EXIT (loop continues) + └── If all complete → final push, create PR +``` + +## Quick Reference: Commands + +| Phase | Action | Command/File | +|-------|--------|--------------| +| Start | Check branch | `git branch --show-current` | +| Start | Pull status | `/sync-tasks {project}` | +| Select | View claims | Check `.hq/claims.json` | +| Select | Claim task | `/sync-tasks {project} --claim {id}` | +| End | Push status | `/sync-tasks {project} --push` | +| End | Release claim | `/sync-tasks {project} --release {id}` | + +## Claim/Release Flow + +### Claiming a Task + +Before starting any task, claim it to prevent others from working on it simultaneously. + +**Step 1: Check if task is claimed** +``` +Read {target_repo}/.hq/claims.json +Find claim where task_id matches your selected task +Check if expires_at > now (still valid) +``` + +**Step 2: If claimed by someone else** +``` +WARNING: Task US-006 is claimed + +Claimed by: pure-ralph-WORKSTATION +Claimed at: 2026-01-27T14:30:00Z (2 hours ago) +Expires at: 2026-01-28T14:30:00Z (in 22 hours) + +Options: + [S] Skip - pick a different task + [W] Wait - task may be released soon + [O] Override - claim anyway (use with caution) +``` + +**Step 3: If available, create claim** +```json +{ + "task_id": "US-006", + "claimed_by": "pure-ralph-LAPTOP-ABC", + "claimed_at": "2026-01-27T16:00:00Z", + "expires_at": "2026-01-28T16:00:00Z", + "notes": "Working on: Add task claim mechanism" +} +``` + +**Step 4: Write claim and commit** +```bash +# Write updated claims.json +# Then commit: +git add {target_repo}/.hq/claims.json +git commit -m "claim: US-006 by pure-ralph-LAPTOP-ABC" +``` + +### Releasing a Claim + +After completing a task, release your claim so others know the task is done. + +**Step 1: Remove claim from array** +``` +Read claims.json +Remove entry where task_id matches completed task +Update claims.updated_at to now +``` + +**Step 2: Include in task commit** +```bash +# Stage with your task changes: +git add {task_files} {target_repo}/.hq/prd.json {target_repo}/.hq/claims.json +git commit -m "feat(US-006): Add task claim mechanism" +``` + +### Claim Expiration + +Claims automatically expire after 24 hours. This prevents indefinite blocking if: +- A contributor abandons work +- A session crashes +- Someone forgets to release + +**Expired claims are treated as "available"** - no manual cleanup needed. + +### Example: Full Claim Lifecycle + +``` +SESSION START +├── Check claims.json +│ └── US-006: claimed by stefan (expires in 2h) +│ └── US-007: no claim (available) +│ +├── Select US-007 (available) +│ +├── Claim US-007: +│ { +│ "task_id": "US-007", +│ "claimed_by": "pure-ralph-DESKTOP", +│ "claimed_at": "2026-01-27T18:00:00Z", +│ "expires_at": "2026-01-28T18:00:00Z" +│ } +│ +├── WORK ON TASK +│ └── Implement, test, update PRD +│ +├── Release claim: +│ └── Remove US-007 from claims array +│ +└── Commit: + git add src/feature.ts .hq/prd.json .hq/claims.json + git commit -m "feat(US-007): Integrate with pure-ralph loop" +``` + +## Troubleshooting Common Conflicts + +### Conflict: Task Status Differs + +**Symptom:** Local shows `passes: false`, repo shows `passes: true` + +**Cause:** Another contributor completed the task while you were working. + +**Resolution:** +1. Check `updated_at` timestamps on both versions +2. If repo is newer → Accept repo version (task is done) +3. If local is newer → Your work may overwrite; verify the task isn't actually done +4. If timestamps equal or missing → Manual review required + +``` +CONFLICT: US-003 - Add pull-from-repo function +┌──────────────┬─────────────────┬─────────────────┐ +│ Field │ Local │ Repo │ +├──────────────┼─────────────────┼─────────────────┤ +│ passes │ false │ true │ +│ notes │ (empty) │ "Worker: ..." │ +│ updated_at │ - │ 2026-01-27T14:30│ +└──────────────┴─────────────────┴─────────────────┘ + +Repo has timestamp, local doesn't → Accept repo version +``` + +### Conflict: Notes Differ + +**Symptom:** Both local and repo have different `notes` content. + +**Cause:** Two contributors worked on the same task or updated notes independently. + +**Resolution:** +1. Compare `updated_at` - newer wins +2. If both have valuable info, manually merge the notes +3. Write merged result to both locations + +### Conflict: New Tasks in Repo + +**Symptom:** Repo has task IDs that don't exist locally. + +**Cause:** Someone added tasks to the repo PRD (scope expansion). + +**Resolution:** +1. Review new tasks - do they make sense for the project? +2. Add to local PRD if valid +3. Or ignore if they're out of scope for your work + +``` +Tasks added in repo (not in local): + - US-011: "Add retry logic for sync failures" + - US-012: "Improve error messages" + +Action: Add to local? [y/n/review] +``` + +### Conflict: Claimed Task You Need + +**Symptom:** The task you want to work on is claimed by someone else. + +**Cause:** Another contributor is actively working on it. + +**Resolution Options:** +1. **Skip** - Pick a different unclaimed task +2. **Wait** - Check back later (claim may be released) +3. **Override** - Claim anyway if you're sure they're not working on it + +**When to Override:** +- Claim is about to expire (< 1 hour remaining) +- You've communicated with the claimer and they agreed +- The claimer is known to be unavailable + +**When NOT to Override:** +- Claim was made recently (< 12 hours ago) +- You haven't tried to contact the claimer +- Multiple tasks are available - pick another + +### Conflict: Git Merge Conflict on .hq/ Files + +**Symptom:** Git merge conflict in `.hq/prd.json` or `.hq/claims.json` + +**Cause:** Two contributors pushed changes to the same file simultaneously. + +**Resolution for prd.json:** +1. Open the file with conflict markers +2. For each conflicted task, compare `updated_at` +3. Keep the newer version of each task +4. Resolve and commit + +**Resolution for claims.json:** +1. Combine both claim arrays (remove duplicates by task_id) +2. For duplicate task_ids, keep the newer claim +3. Remove any expired claims +4. Resolve and commit + +```bash +# After resolving: +git add .hq/prd.json .hq/claims.json +git commit -m "merge: resolve distributed tracking conflicts" +``` + +### Conflict: Stale Local PRD + +**Symptom:** Your local PRD is significantly behind the repo version. + +**Cause:** You haven't synced in a while; others have completed many tasks. + +**Resolution:** +1. Run `/sync-tasks {project}` to see the full diff +2. If many tasks differ, consider accepting repo state wholesale +3. Apply merge: repo version for completed tasks, keep local for your in-progress work + +### Session Crashed: Claim Not Released + +**Symptom:** You claimed a task but your session crashed before releasing. + +**Impact:** The claim will expire in 24 hours automatically. + +**If you need to work on it sooner:** +1. Manually edit `{target_repo}/.hq/claims.json` +2. Remove your stale claim +3. Re-claim if continuing work + +```bash +# Edit claims.json, remove your stale claim, then: +git add .hq/claims.json +git commit -m "fix: release stale claim from crashed session" +``` + +### Session Crashed: PRD Not Pushed + +**Symptom:** You completed work but the session crashed before pushing to repo. + +**Impact:** Your local PRD has the update, but repo doesn't. + +**Resolution:** +1. Your work is still in local PRD +2. Next session will run `/sync-tasks --push` +3. Conflict resolution will merge if someone else also worked + +## Best Practices + +### Before Starting Work + +1. Always sync first: `/sync-tasks {project}` +2. Review the diff - understand what's changed +3. Pick unclaimed tasks when possible +4. Claim your task before coding + +### During Work + +1. Work on ONE task at a time +2. Don't hold claims longer than needed +3. If blocked, release claim and pick another task + +### After Completing Work + +1. Update PRD with notes AND `updated_at` +2. Push to repo immediately +3. Release your claim +4. Include `.hq/` files in your commit + +### For Distributed Teams + +1. Communicate about large refactors +2. Check sync status before long sessions +3. Don't override claims without good reason +4. Keep sessions short - claim, work, release + +## File Reference + +| File | Purpose | Location | +|------|---------|----------| +| Local PRD | Source of truth for project | `projects/{project}/prd.json` | +| Repo PRD | Shared status for team | `{target_repo}/.hq/prd.json` | +| Claims | Who's working on what | `{target_repo}/.hq/claims.json` | +| Sync Log | Audit trail | `{target_repo}/.hq/sync-log.json` | + +## See Also + +- [Directory Structure](structure.md) - File schemas and directory layout +- `/sync-tasks` command - Manual sync operations +- `prompts/pure-ralph-base.md` - Automated workflow integration diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index 3e4d211..facd83c 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -147,8 +147,9 @@ ], "files": ["knowledge/distributed-tracking/workflow.md"], "dependsOn": ["US-007"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation task creating workflow guide. Created comprehensive workflow.md with: full sync lifecycle diagram (session start to end), claim/release flow examples with JSON snippets, troubleshooting section for 7 common conflict scenarios, best practices for distributed teams, and file reference table.", + "updated_at": "2026-01-27T21:00:00Z" }, { "id": "US-010", From 3d309ed14767f063ba2d2fa2876d2280f350b64e Mon Sep 17 00:00:00 2001 From: johnsonfamily1234 Date: Tue, 27 Jan 2026 09:44:35 -0800 Subject: [PATCH 10/10] feat(US-010): Add prompt templating to .hq/ directory - Updated structure.md to document prompt.md in .hq/ directory - Scripts now check for .hq/prompt.md and copy from HQ if missing - Scripts use .hq/prompt.md and .hq/prd.json for all operations - Prompt now references .hq/prd.json directly (no {{PRD_PATH}} substitution) - Added Initialize-HqDirectory function to both ps1 and sh scripts - Enables project-specific prompt evolution and portability Co-Authored-By: Claude Opus 4.5 --- .claude/scripts/pure-ralph-loop.ps1 | 195 ++++++++------------ .claude/scripts/pure-ralph-loop.sh | 194 +++++++------------ knowledge/distributed-tracking/structure.md | 32 +++- projects/distributed-tracking/prd.json | 5 +- prompts/pure-ralph-base.md | 102 +++++----- 5 files changed, 226 insertions(+), 302 deletions(-) diff --git a/.claude/scripts/pure-ralph-loop.ps1 b/.claude/scripts/pure-ralph-loop.ps1 index 97cd512..c8fe10b 100644 --- a/.claude/scripts/pure-ralph-loop.ps1 +++ b/.claude/scripts/pure-ralph-loop.ps1 @@ -40,11 +40,15 @@ param( # Configuration # ============================================================================ -$BasePromptPath = Join-Path $HqPath "prompts/pure-ralph-base.md" +$HqBasePromptPath = Join-Path $HqPath "prompts/pure-ralph-base.md" $ProjectName = (Split-Path (Split-Path $PrdPath -Parent) -Leaf) $LogDir = Join-Path $HqPath "workspace/orchestrator/$ProjectName" $LogFile = Join-Path $LogDir "pure-ralph.log" -$LockFile = Join-Path $TargetRepo ".pure-ralph.lock" + +# .hq/ directory paths in target repo +$HqDir = Join-Path $TargetRepo ".hq" +$RepoPromptPath = Join-Path $HqDir "prompt.md" +$RepoPrdPath = Join-Path $HqDir "prd.json" # Create log directory New-Item -ItemType Directory -Path $LogDir -Force | Out-Null @@ -53,6 +57,52 @@ New-Item -ItemType Directory -Path $LogDir -Force | Out-Null # Functions # ============================================================================ +function Initialize-HqDirectory { + # Create .hq directory if missing + if (-not (Test-Path $HqDir)) { + Write-Log "Creating .hq directory in target repo" + New-Item -ItemType Directory -Path $HqDir -Force | Out-Null + } + + # Copy prompt.md if missing + if (-not (Test-Path $RepoPromptPath)) { + Write-Log "Copying prompt template to $RepoPromptPath" + if (Test-Path $HqBasePromptPath) { + # Read the base prompt and substitute TARGET_REPO + $promptContent = Get-Content $HqBasePromptPath -Raw + $promptContent = $promptContent -replace '\{\{TARGET_REPO\}\}', $TargetRepo + $promptContent | Out-File -FilePath $RepoPromptPath -Encoding utf8 + Write-Log "Prompt template created at $RepoPromptPath" "SUCCESS" + } else { + Write-Log "Base prompt not found at $HqBasePromptPath" "ERROR" + exit 1 + } + } else { + Write-Log "Using existing prompt at $RepoPromptPath" + } + + # Copy prd.json if missing + if (-not (Test-Path $RepoPrdPath)) { + Write-Log "Copying PRD to $RepoPrdPath" + if (Test-Path $PrdPath) { + # Read the HQ PRD and add sync_metadata + $prdContent = Get-Content $PrdPath -Raw | ConvertFrom-Json + $prdContent | Add-Member -NotePropertyName "sync_metadata" -NotePropertyValue @{ + synced_at = (Get-Date -Format "o") + synced_from = $PrdPath + synced_by = "pure-ralph-init" + } -Force + $prdContent | ConvertTo-Json -Depth 10 | Out-File -FilePath $RepoPrdPath -Encoding utf8 + Write-Log "PRD copied to $RepoPrdPath" "SUCCESS" + } else { + Write-Log "HQ PRD not found at $PrdPath" "ERROR" + exit 1 + } + } else { + Write-Log "Using existing PRD at $RepoPrdPath" + } +} + function Write-Log { param([string]$Message, [string]$Level = "INFO") $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" @@ -67,87 +117,9 @@ function Write-Log { } } -function Create-LockFile { - $lockContent = @{ - project = $ProjectName - pid = $PID - started_at = (Get-Date -Format "o") - } | ConvertTo-Json - $lockContent | Out-File -FilePath $LockFile -Encoding utf8 - Write-Log "Lock file created: $LockFile" -} - -function Remove-LockFile { - if (Test-Path $LockFile) { - Remove-Item -Path $LockFile -Force - Write-Log "Lock file removed: $LockFile" - } -} - -function Check-ExistingLock { - if (Test-Path $LockFile) { - try { - $lockContent = Get-Content $LockFile -Raw | ConvertFrom-Json - $lockProject = $lockContent.project - $lockPid = $lockContent.pid - $lockStarted = [DateTime]::Parse($lockContent.started_at) - $duration = (Get-Date) - $lockStarted - $durationStr = "{0:hh\:mm\:ss}" -f $duration - - Write-Host "" - Write-Host "=== WARNING: Lock File Detected ===" -ForegroundColor Yellow - Write-Host "Another pure-ralph loop may be running on this repo." -ForegroundColor Yellow - Write-Host "" - Write-Host " Project: $lockProject" -ForegroundColor Gray - Write-Host " PID: $lockPid" -ForegroundColor Gray - Write-Host " Started: $($lockContent.started_at)" -ForegroundColor Gray - Write-Host " Duration: $durationStr" -ForegroundColor Gray - Write-Host "" - - # Check if process is still running - $processRunning = $false - try { - $proc = Get-Process -Id $lockPid -ErrorAction SilentlyContinue - if ($proc) { - $processRunning = $true - Write-Host " Process Status: RUNNING" -ForegroundColor Red - } else { - Write-Host " Process Status: NOT RUNNING (stale lock)" -ForegroundColor Yellow - } - } catch { - Write-Host " Process Status: NOT RUNNING (stale lock)" -ForegroundColor Yellow - } - Write-Host "" - - Write-Log "Existing lock file found for project '$lockProject' (PID: $lockPid, Duration: $durationStr)" "WARN" - - # Prompt user - $response = Read-Host "Another pure-ralph is running. Continue anyway? (y/N)" - if ($response -match "^[Yy]$") { - Write-Log "User chose to continue despite existing lock" "WARN" - Write-Host "Continuing... (existing lock will be overwritten)" -ForegroundColor Yellow - return $true - } else { - Write-Log "User chose to abort due to existing lock" "INFO" - Write-Host "Aborting." -ForegroundColor Red - return $false - } - } catch { - Write-Log "Could not parse lock file: $_" "WARN" - # If we can't parse the lock file, ask the user - $response = Read-Host "Lock file exists but couldn't be read. Continue anyway? (y/N)" - if ($response -match "^[Yy]$") { - return $true - } else { - return $false - } - } - } - return $true -} - function Get-TaskProgress { - $prd = Get-Content $PrdPath -Raw | ConvertFrom-Json + # Read from repo's .hq/prd.json + $prd = Get-Content $RepoPrdPath -Raw | ConvertFrom-Json $total = $prd.features.Count $complete = ($prd.features | Where-Object { $_.passes -eq $true }).Count return @{ Total = $total; Complete = $complete; Remaining = $total - $complete } @@ -156,10 +128,9 @@ function Get-TaskProgress { function Build-Prompt { param([bool]$IsManual) - # Read base prompt and substitute only PRD_PATH and TARGET_REPO - $prompt = Get-Content $BasePromptPath -Raw - $prompt = $prompt -replace '\{\{PRD_PATH\}\}', $PrdPath - $prompt = $prompt -replace '\{\{TARGET_REPO\}\}', $TargetRepo + # Read prompt from repo's .hq/prompt.md (already has TARGET_REPO substituted) + # No PRD_PATH substitution needed - prompt references .hq/prd.json directly + $prompt = Get-Content $RepoPromptPath -Raw # In manual mode, add instruction for user to close window if ($IsManual) { @@ -204,27 +175,20 @@ Write-Log "PRD: $PrdPath" Write-Log "Target: $TargetRepo" Write-Log "Mode: $modeLabel" -# Check for existing lock file (conflict detection) -if (-not (Check-ExistingLock)) { - exit 1 -} - -# Create lock file to prevent concurrent execution -Create-LockFile +# Initialize .hq directory (copy prompt.md and prd.json if missing) +Initialize-HqDirectory -# Ensure lock file is removed on exit (success or failure) -try { - # Build the prompt ONCE (only PRD_PATH and TARGET_REPO substituted) - $prompt = Build-Prompt -IsManual $Manual - $promptFile = Join-Path $LogDir "current-prompt.md" - $prompt | Out-File -FilePath $promptFile -Encoding utf8 +# Build the prompt from .hq/prompt.md (no PRD_PATH substitution needed) +$prompt = Build-Prompt -IsManual $Manual +$promptFile = Join-Path $LogDir "current-prompt.md" +$prompt | Out-File -FilePath $promptFile -Encoding utf8 - Write-Log "Prompt built and saved to $promptFile" +Write-Log "Prompt built and saved to $promptFile" - $iteration = 0 - $maxIterations = 50 +$iteration = 0 +$maxIterations = 50 - while ($iteration -lt $maxIterations) { +while ($iteration -lt $maxIterations) { $iteration++ $progress = Get-TaskProgress @@ -293,20 +257,15 @@ exit Start-Sleep -Seconds 2 } - if ($iteration -ge $maxIterations) { - Write-Log "Safety limit reached ($maxIterations iterations)" "WARN" - } +if ($iteration -ge $maxIterations) { + Write-Log "Safety limit reached ($maxIterations iterations)" "WARN" +} - # Final summary - $progress = Get-TaskProgress - Write-Host "" - Write-Host "=== Final Summary ===" -ForegroundColor Cyan - Write-Host "Completed: $($progress.Complete)/$($progress.Total) tasks" -ForegroundColor $(if ($progress.Remaining -eq 0) { "Green" } else { "Yellow" }) - Write-Host "Log: $LogFile" -ForegroundColor Gray +# Final summary +$progress = Get-TaskProgress +Write-Host "" +Write-Host "=== Final Summary ===" -ForegroundColor Cyan +Write-Host "Completed: $($progress.Complete)/$($progress.Total) tasks" -ForegroundColor $(if ($progress.Remaining -eq 0) { "Green" } else { "Yellow" }) +Write-Host "Log: $LogFile" -ForegroundColor Gray - Write-Log "Loop ended. Final: $($progress.Complete)/$($progress.Total) complete" -} -finally { - # Always remove lock file on exit (success or failure) - Remove-LockFile -} +Write-Log "Loop ended. Final: $($progress.Complete)/$($progress.Total) complete" diff --git a/.claude/scripts/pure-ralph-loop.sh b/.claude/scripts/pure-ralph-loop.sh index b619683..ff9f695 100644 --- a/.claude/scripts/pure-ralph-loop.sh +++ b/.claude/scripts/pure-ralph-loop.sh @@ -109,11 +109,15 @@ fi # Configuration # ============================================================================ -BASE_PROMPT_PATH="$HQ_PATH/prompts/pure-ralph-base.md" +HQ_BASE_PROMPT_PATH="$HQ_PATH/prompts/pure-ralph-base.md" PROJECT_NAME=$(basename "$(dirname "$PRD_PATH")") LOG_DIR="$HQ_PATH/workspace/orchestrator/$PROJECT_NAME" LOG_FILE="$LOG_DIR/pure-ralph.log" -LOCK_FILE="$TARGET_REPO/.pure-ralph.lock" + +# .hq/ directory paths in target repo +HQ_DIR="$TARGET_REPO/.hq" +REPO_PROMPT_PATH="$HQ_DIR/prompt.md" +REPO_PRD_PATH="$HQ_DIR/prd.json" # ============================================================================ # Color Output @@ -126,6 +130,53 @@ CYAN='\033[0;36m' GRAY='\033[0;90m' NC='\033[0m' # No Color +# ============================================================================ +# HQ Directory Initialization +# ============================================================================ + +initialize_hq_directory() { + # Create .hq directory if missing + if [[ ! -d "$HQ_DIR" ]]; then + write_log "Creating .hq directory in target repo" + mkdir -p "$HQ_DIR" + fi + + # Copy prompt.md if missing + if [[ ! -f "$REPO_PROMPT_PATH" ]]; then + write_log "Copying prompt template to $REPO_PROMPT_PATH" + if [[ -f "$HQ_BASE_PROMPT_PATH" ]]; then + # Read the base prompt and substitute TARGET_REPO + sed "s|{{TARGET_REPO}}|$TARGET_REPO|g" "$HQ_BASE_PROMPT_PATH" > "$REPO_PROMPT_PATH" + write_log "Prompt template created at $REPO_PROMPT_PATH" "SUCCESS" + else + write_log "Base prompt not found at $HQ_BASE_PROMPT_PATH" "ERROR" + exit 1 + fi + else + write_log "Using existing prompt at $REPO_PROMPT_PATH" + fi + + # Copy prd.json if missing + if [[ ! -f "$REPO_PRD_PATH" ]]; then + write_log "Copying PRD to $REPO_PRD_PATH" + if [[ -f "$PRD_PATH" ]]; then + # Read the HQ PRD and add sync_metadata using jq + local timestamp + timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + jq --arg synced_at "$timestamp" \ + --arg synced_from "$PRD_PATH" \ + '. + {sync_metadata: {synced_at: $synced_at, synced_from: $synced_from, synced_by: "pure-ralph-init"}}' \ + "$PRD_PATH" > "$REPO_PRD_PATH" + write_log "PRD copied to $REPO_PRD_PATH" "SUCCESS" + else + write_log "HQ PRD not found at $PRD_PATH" "ERROR" + exit 1 + fi + else + write_log "Using existing PRD at $REPO_PRD_PATH" + fi +} + # ============================================================================ # Logging Functions # ============================================================================ @@ -147,108 +198,6 @@ initialize_logging() { } >> "$LOG_FILE" } -# ============================================================================ -# Lock File Functions -# ============================================================================ - -create_lock_file() { - local timestamp - timestamp=$(date -Iseconds) - cat > "$LOCK_FILE" </dev/null || echo "unknown") - lock_pid=$(jq -r '.pid' "$LOCK_FILE" 2>/dev/null || echo "unknown") - lock_started=$(jq -r '.started_at' "$LOCK_FILE" 2>/dev/null || echo "unknown") - - # Calculate duration if we can parse the timestamp - local duration_str="unknown" - if [[ "$lock_started" != "unknown" ]]; then - local start_epoch - local now_epoch - local diff_seconds - # Try to parse ISO timestamp - if command -v gdate &> /dev/null; then - start_epoch=$(gdate -d "$lock_started" +%s 2>/dev/null || echo "0") - else - start_epoch=$(date -d "$lock_started" +%s 2>/dev/null || echo "0") - fi - now_epoch=$(date +%s) - if [[ "$start_epoch" != "0" ]]; then - diff_seconds=$((now_epoch - start_epoch)) - local hours=$((diff_seconds / 3600)) - local minutes=$(((diff_seconds % 3600) / 60)) - local seconds=$((diff_seconds % 60)) - duration_str=$(printf "%02d:%02d:%02d" $hours $minutes $seconds) - fi - fi - - echo "" - echo -e "${YELLOW}=== WARNING: Lock File Detected ===${NC}" - echo -e "${YELLOW}Another pure-ralph loop may be running on this repo.${NC}" - echo "" - echo -e "${GRAY} Project: $lock_project${NC}" - echo -e "${GRAY} PID: $lock_pid${NC}" - echo -e "${GRAY} Started: $lock_started${NC}" - echo -e "${GRAY} Duration: $duration_str${NC}" - echo "" - - # Check if process is still running - local process_running=false - if [[ "$lock_pid" != "unknown" ]] && kill -0 "$lock_pid" 2>/dev/null; then - process_running=true - echo -e " Process Status: ${RED}RUNNING${NC}" - else - echo -e " Process Status: ${YELLOW}NOT RUNNING (stale lock)${NC}" - fi - echo "" - - write_log "Existing lock file found for project '$lock_project' (PID: $lock_pid, Duration: $duration_str)" "WARN" - - # Prompt user - read -r -p "Another pure-ralph is running. Continue anyway? (y/N) " response - case "$response" in - [Yy]) - write_log "User chose to continue despite existing lock" "WARN" - echo -e "${YELLOW}Continuing... (existing lock will be overwritten)${NC}" - return 0 - ;; - *) - write_log "User chose to abort due to existing lock" "INFO" - echo -e "${RED}Aborting.${NC}" - return 1 - ;; - esac - fi - return 0 -} - -# Trap to ensure lock file is removed on exit (success or failure) -cleanup_on_exit() { - remove_lock_file -} -trap cleanup_on_exit EXIT - write_log() { local message="$1" local level="${2:-INFO}" @@ -291,11 +240,12 @@ check_jq() { } get_prd() { - if [[ ! -f "$PRD_PATH" ]]; then - write_log "PRD not found: $PRD_PATH" "ERROR" + # Read from repo's .hq/prd.json + if [[ ! -f "$REPO_PRD_PATH" ]]; then + write_log "PRD not found: $REPO_PRD_PATH" "ERROR" exit 1 fi - cat "$PRD_PATH" + cat "$REPO_PRD_PATH" } get_task_count() { @@ -343,14 +293,15 @@ build_task_prompt() { local task="$1" local prd="$2" - # Read base prompt - if [[ ! -f "$BASE_PROMPT_PATH" ]]; then - write_log "Base prompt not found: $BASE_PROMPT_PATH" "ERROR" + # Read prompt from repo's .hq/prompt.md (already has TARGET_REPO substituted) + # No PRD_PATH substitution needed - prompt references .hq/prd.json directly + if [[ ! -f "$REPO_PROMPT_PATH" ]]; then + write_log "Prompt not found: $REPO_PROMPT_PATH" "ERROR" exit 1 fi local base_prompt - base_prompt=$(cat "$BASE_PROMPT_PATH") + base_prompt=$(cat "$REPO_PROMPT_PATH") # Extract task details local task_id @@ -358,10 +309,8 @@ build_task_prompt() { task_id=$(echo "$task" | jq -r '.id') task_title=$(echo "$task" | jq -r '.title') - # Replace placeholders + # Only substitute task-specific placeholders (TARGET_REPO already done during init) local prompt="$base_prompt" - prompt="${prompt//\{\{TARGET_REPO\}\}/$TARGET_REPO}" - prompt="${prompt//\{\{PRD_PATH\}\}/$PRD_PATH}" prompt="${prompt//\{\{TASK_ID\}\}/$task_id}" prompt="${prompt//\{\{TASK_TITLE\}\}/$task_title}" @@ -373,7 +322,7 @@ build_task_prompt() { cat </dev/null || \ start_ralph_loop() { initialize_logging - # Check for existing lock file (conflict detection) - if ! check_existing_lock; then - exit 1 - fi - - # Create lock file to prevent concurrent execution - create_lock_file - echo "" echo -e "${CYAN}=== Pure Ralph Loop ===${NC}" echo -e "${GRAY}PRD: $PRD_PATH${NC}" echo -e "${GRAY}Target: $TARGET_REPO${NC}" echo -e "${GRAY}Log: $LOG_FILE${NC}" + # Initialize .hq directory (copy prompt.md and prd.json if missing) + initialize_hq_directory + # Check for beads CLI availability if check_beads_cli; then echo -e "${GRAY}Beads CLI: ${GREEN}available${NC}" diff --git a/knowledge/distributed-tracking/structure.md b/knowledge/distributed-tracking/structure.md index 090fd55..7295c60 100644 --- a/knowledge/distributed-tracking/structure.md +++ b/knowledge/distributed-tracking/structure.md @@ -9,7 +9,8 @@ The `.hq/` directory enables distributed teams to share PRD and task status via ├── .hq/ │ ├── prd.json # Project requirements and task status │ ├── claims.json # Active task claims -│ └── sync-log.json # Sync history +│ ├── sync-log.json # Sync history +│ └── prompt.md # Pure Ralph prompt (copied from HQ, can evolve with project) ├── src/ └── ... ``` @@ -226,6 +227,35 @@ Audit trail of all sync operations for debugging and history. } ``` +### prompt.md + +The Pure Ralph prompt file, copied from HQ and customizable per project. + +```markdown +# Pure Ralph Prompt + +You are executing the Pure Ralph Loop... + +**PRD Path:** .hq/prd.json +**Target Repo:** {{TARGET_REPO}} + +--- + +[Full prompt content - see prompts/pure-ralph-base.md] +``` + +**Key Characteristics:** +- **Initial source:** Copied from `HQ/prompts/pure-ralph-base.md` on first run +- **References PRD locally:** Uses `.hq/prd.json` (not an HQ path) +- **Project-specific evolution:** Can be edited to add project-specific patterns +- **Version controlled:** Part of the repo, evolves with the project + +**Why prompt.md lives in .hq/:** +1. **Portability:** Project can run Ralph loop without HQ access +2. **Customization:** Project teams can tune the prompt for their needs +3. **Version tracking:** Prompt changes are committed with the project +4. **Self-contained:** Everything needed for distributed work is in one directory + ## .gitignore Recommendations Add to the target repository's `.gitignore`: diff --git a/projects/distributed-tracking/prd.json b/projects/distributed-tracking/prd.json index facd83c..d932043 100644 --- a/projects/distributed-tracking/prd.json +++ b/projects/distributed-tracking/prd.json @@ -171,8 +171,9 @@ "prompts/pure-ralph-base.md" ], "dependsOn": ["US-001"], - "passes": false, - "notes": "" + "passes": true, + "notes": "Worker: knowledge-curator. Selection reason: Documentation and script modification task. Updated structure.md to document prompt.md in .hq/ directory with explanation of portability benefits. Updated pure-ralph-loop.ps1 and pure-ralph-loop.sh with Initialize-HqDirectory/initialize_hq_directory functions that: (1) create .hq/ directory if missing, (2) copy prompt.md from HQ with TARGET_REPO substituted, (3) copy prd.json from HQ with sync_metadata added. Updated prompts/pure-ralph-base.md to reference .hq/prd.json directly instead of {{PRD_PATH}}. Scripts now use repo's .hq/prompt.md and .hq/prd.json for all operations.", + "updated_at": "2026-01-27T22:00:00Z" } ], "metadata": { diff --git a/prompts/pure-ralph-base.md b/prompts/pure-ralph-base.md index 5be37ea..c8c3fd2 100644 --- a/prompts/pure-ralph-base.md +++ b/prompts/pure-ralph-base.md @@ -2,7 +2,7 @@ You are executing the Pure Ralph Loop. Read the PRD, pick ONE task, complete it, update the PRD. -**PRD Path:** {{PRD_PATH}} +**PRD Path:** .hq/prd.json **Target Repo:** {{TARGET_REPO}} --- @@ -62,7 +62,7 @@ This is a **HARD BLOCK**, not a warning. Committing to main is NEVER acceptable 1. **BRANCH** - Ensure you're on `feature/{{PROJECT_NAME}}` (create if needed) 2. **SYNC** - Pull from repo, resolve any conflicts (see "Distributed Tracking - Integrated Workflow") -3. **READ** the PRD at {{PRD_PATH}} +3. **READ** the PRD at .hq/prd.json 4. **PICK** the highest priority incomplete task (check claims, prefer unclaimed tasks) 5. **CLAIM** the selected task before starting work 6. **IMPLEMENT** that ONE task @@ -365,28 +365,29 @@ After completing a task and updating the PRD, push the status to the target repo ### push_to_repo Function -Execute this after each successful task completion (after PRD update, before or as part of commit): +Execute this after each successful task completion (after PRD update, before or as part of commit). + +Since the prompt now reads directly from .hq/prd.json, changes are already in the repo. The push_to_repo function ensures: +1. The .hq/prd.json has sync_metadata for tracking +2. Changes are committed ``` PUSH_TO_REPO: - 1. Create .hq/ directory in target repo if missing: - mkdir -p {target_repo}/.hq - - 2. Read the local PRD from {{PRD_PATH}} - - 3. Add sync_metadata to create the distributed copy: + 1. Ensure .hq/prd.json has sync_metadata: { ...full PRD contents..., "sync_metadata": { "synced_at": "", - "synced_from": "{{PRD_PATH}}", + "synced_from": ".hq/prd.json", "synced_by": "pure-ralph" } } - 4. Write to {target_repo}/.hq/prd.json + 2. If sync_metadata doesn't exist, add it - 5. Commit with message: "sync: update distributed tracking" + 3. Update sync_metadata.synced_at to current timestamp + + 4. Stage .hq/prd.json for commit (included with task commit) ``` ### What Gets Synced @@ -449,38 +450,31 @@ Before starting work, check if the target repo has distributed tracking data tha ### pull_from_repo Function -Execute this at the start of each Pure Ralph session (after branch verification, before task selection): +Execute this at the start of each Pure Ralph session (after branch verification, before task selection). + +Since the prompt now reads directly from .hq/prd.json, the pull is about refreshing from git to get other contributors' changes: ``` PULL_FROM_REPO: - 1. Check if distributed tracking file exists: - if [ -f "{target_repo}/.hq/prd.json" ]; then - echo "Distributed tracking found" - else - echo "No distributed tracking - skip pull" - # Continue with local PRD only - fi - - 2. If exists, read both files: - - Remote: {target_repo}/.hq/prd.json - - Local: {{PRD_PATH}} + 1. Pull latest from remote (if on a tracking branch): + git pull --rebase origin feature/{project-name} 2>/dev/null || true - 3. Compare features arrays by task ID: - For each task, check: - - passes: local vs remote (has status changed?) - - notes: local vs remote (has implementation detail changed?) - - acceptance_criteria: local vs remote (has scope changed?) + 2. Check if .hq/prd.json exists: + if [ ! -f ".hq/prd.json" ]; then + echo "No .hq/prd.json found - will be created" + # Script handles initial setup + fi - 4. Generate diff summary (DO NOT auto-overwrite): - DIFF SUMMARY: - - Tasks added in repo: [list task IDs not in local] - - Tasks removed in repo: [list task IDs not in repo] - - Tasks with different status: [list task IDs where passes differs] - - Tasks with updated notes: [list task IDs where notes differs] + 3. If .hq/prd.json exists, read and validate: + - Check for merge conflicts (<<<<<<< markers) + - Verify JSON is valid + - Report current task progress - 5. If differences found, WARN but continue: - "WARNING: Local and repo PRDs differ. Review before proceeding." - "Use /sync-tasks {project} to merge changes." + 4. Report current state: + CURRENT STATE: + - Total tasks: X + - Completed: Y + - Remaining: Z ``` ### Diff Detection Logic @@ -675,19 +669,18 @@ After user confirms, write to BOTH locations: ``` APPLY_MERGE: 1. Construct merged PRD: - - Start with local PRD as base + - Start with current .hq/prd.json as base - Apply resolved changes per task - Update sync_metadata.merged_at = now() - Add sync_metadata.merge_source = "conflict_resolution" - 2. Write to local PRD: - {{PRD_PATH}} + 2. Write merged result to .hq/prd.json - 3. Write to repo distributed tracking: - {target_repo}/.hq/prd.json + 3. Stage for commit: + git add .hq/prd.json 4. Report success: - "Merge complete. Written to both local and repo." + "Merge complete. Written to .hq/prd.json" ``` ### Example Merge Flow @@ -983,18 +976,15 @@ Execute before reading the PRD: ``` LOOP_START: 1. pull_from_repo() - - Check if {target_repo}/.hq/prd.json exists - - Compare with local {{PRD_PATH}} - - Generate diff summary - - 2. If differences found: - - Show diff summary - - Run conflict resolution (see Conflict Resolution section) - - Apply merge if user approves - - Continue with merged PRD - - 3. If no differences or no .hq/prd.json: - - Continue with local PRD + - Pull latest from remote if tracking branch exists + - Check if .hq/prd.json exists (script creates if not) + - Validate JSON and check for merge conflicts + + 2. If merge conflicts in .hq/prd.json: + - Resolve git conflicts + - Ensure valid JSON + + 3. Continue with .hq/prd.json ``` ### Before Each Task (During Task Selection)