From 8adc47cfe855d65dd885d3843fda64c6d39fd25b Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 16:40:02 +0200 Subject: [PATCH 01/12] Revamp workflow around durable work items Amp-Thread-ID: https://ampcode.com/threads/T-019eefae-419c-7399-bcd1-d40066dfd0d8 Co-authored-by: Amp --- .agents/.dot-agents.json | 5 - .agents/.gitignore | 4 +- .agents/plans/TEMPLATE.md | 39 --- .agents/plans/completed/.gitkeep | 0 .agents/plans/in-progress/.gitkeep | 0 .agents/plans/todo/.gitkeep | 0 .../todo/documentation-troubleshooting.md | 99 ------- .agents/prds/AGENTS.md | 39 --- .agents/prds/TEMPLATE.md | 45 --- .agents/reference/.gitkeep | 1 - .agents/references/.gitkeep | 1 + .agents/scripts/sync.sh | 4 +- .agents/skills/AGENTS.md | 7 +- .agents/skills/adapt/SKILL.md | 13 +- .agents/skills/agent-work/SKILL.md | 94 ++++++ .../skills/agent-work/assets/plan-template.md | 86 ++++++ .../skills/agent-work/assets/prd-template.md | 60 ++++ .../assets/work-decision-template.md | 26 ++ .../agent-work/assets/work-index-template.md | 25 ++ .../skills/agent-work/scripts/list-work.sh | 65 +++++ .agents/skills/agent-work/scripts/new-work.sh | 121 ++++++++ .agents/skills/feature-planning/SKILL.md | 144 +++++++++ .agents/skills/ralph/SKILL.md | 221 -------------- .../ralph/references/progress-format.md | 137 --------- .agents/skills/research/SKILL.md | 166 +++++------ .agents/skills/tmux/SKILL.md | 2 +- .agents/work/AGENTS.md | 68 +++++ .gitignore | 5 +- AGENTS.md | 114 +++----- AGENTS.template.md | 107 +++---- CHANGELOG.md | 26 +- QUICKSTART.md | 94 +++--- README.md | 36 ++- VERSION | 2 +- docs/README.md | 1 + docs/concepts.md | 60 +++- docs/migration-v1.md | 62 ++++ docs/skills.md | 85 +++--- install.sh | 121 +++++++- scripts/build-test-fixture.sh | 25 +- scripts/lint.sh | 2 + site/index.html | 63 ++-- test/fixtures/sample-archive.tar.gz | Bin 44358 -> 19286 bytes test/integration/install.bats | 274 +++++++++++++++++- 44 files changed, 1560 insertions(+), 989 deletions(-) delete mode 100644 .agents/.dot-agents.json delete mode 100644 .agents/plans/TEMPLATE.md delete mode 100644 .agents/plans/completed/.gitkeep delete mode 100644 .agents/plans/in-progress/.gitkeep delete mode 100644 .agents/plans/todo/.gitkeep delete mode 100644 .agents/plans/todo/documentation-troubleshooting.md delete mode 100644 .agents/prds/AGENTS.md delete mode 100644 .agents/prds/TEMPLATE.md delete mode 100644 .agents/reference/.gitkeep create mode 100644 .agents/references/.gitkeep create mode 100644 .agents/skills/agent-work/SKILL.md create mode 100644 .agents/skills/agent-work/assets/plan-template.md create mode 100644 .agents/skills/agent-work/assets/prd-template.md create mode 100644 .agents/skills/agent-work/assets/work-decision-template.md create mode 100644 .agents/skills/agent-work/assets/work-index-template.md create mode 100755 .agents/skills/agent-work/scripts/list-work.sh create mode 100755 .agents/skills/agent-work/scripts/new-work.sh create mode 100644 .agents/skills/feature-planning/SKILL.md delete mode 100644 .agents/skills/ralph/SKILL.md delete mode 100644 .agents/skills/ralph/references/progress-format.md create mode 100644 .agents/work/AGENTS.md create mode 100644 docs/migration-v1.md diff --git a/.agents/.dot-agents.json b/.agents/.dot-agents.json deleted file mode 100644 index c4f4f00..0000000 --- a/.agents/.dot-agents.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "upstream": "https://github.com/colmarius/dot-agents", - "ref": "main", - "installedAt": "2026-01-31T12:34:28Z" -} diff --git a/.agents/.gitignore b/.agents/.gitignore index ef2496a..3cec1d0 100644 --- a/.agents/.gitignore +++ b/.agents/.gitignore @@ -1,6 +1,8 @@ # External reference repositories cloned for analysis # These are typically large and should not be committed reference/ +references/* +!references/.gitkeep # Backup directory created during install --force -../.dot-agents-backup/ +.dot-agents-backup/ diff --git a/.agents/plans/TEMPLATE.md b/.agents/plans/TEMPLATE.md deleted file mode 100644 index 12dfc70..0000000 --- a/.agents/plans/TEMPLATE.md +++ /dev/null @@ -1,39 +0,0 @@ -# Plan: [Feature Name] - -| Field | Value | -|-------|-------| -| PRD | `../../prds/[prd-name].md` or N/A | -| Research | `../../research/[topic].md` or N/A | -| Status | todo | -| Created | YYYY-MM-DD | - -## Overview - -[Brief description of what this plan implements and why.] - -## Tasks - -- [ ] **Task 1: [Short descriptive title]** - - Scope: `path/to/affected/files` or module name - - Depends on: none - - Acceptance: - - Specific, verifiable criterion 1 - - Specific, verifiable criterion 2 - - Notes: Optional implementation hints - -- [ ] **Task 2: [Short descriptive title]** - - Scope: `path/to/affected/files` - - Depends on: Task 1 - - Acceptance: - - Specific, verifiable criterion - - Notes: Optional notes - -## Verification - -After all tasks complete, run: - -```bash -# Add project-specific verification commands -``` - -All checks must pass before marking plan complete. diff --git a/.agents/plans/completed/.gitkeep b/.agents/plans/completed/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/.agents/plans/in-progress/.gitkeep b/.agents/plans/in-progress/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/.agents/plans/todo/.gitkeep b/.agents/plans/todo/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/.agents/plans/todo/documentation-troubleshooting.md b/.agents/plans/todo/documentation-troubleshooting.md deleted file mode 100644 index 786d59e..0000000 --- a/.agents/plans/todo/documentation-troubleshooting.md +++ /dev/null @@ -1,99 +0,0 @@ -# Plan: Troubleshooting Documentation - -| Field | Value | -|-------|-------| -| PRD | N/A | -| Research | `../../research/documentation-troubleshooting.md` | -| Status | todo | -| Created | 2026-02-03 | - -## Overview - -Create a dedicated troubleshooting guide covering common issues from CHANGELOG and anticipated user problems, making solutions easily discoverable. - -## Tasks - -- [ ] **Task 1: Create docs/troubleshooting.md with installation issues** - - Scope: `docs/troubleshooting.md` - - Depends on: none - - Acceptance: - - File exists at docs/troubleshooting.md - - Has "Installation Issues" section - - Documents "BASH_SOURCE[0]: unbound variable" fix - - Documents bash 5.3+ script exit issue - - Each issue has: symptoms, cause, solution - - Notes: Issues from CHANGELOG commits 455019a and 4d97cce - -- [ ] **Task 2: Add skill issues section to troubleshooting** - - Scope: `docs/troubleshooting.md` - - Depends on: Task 1 - - Acceptance: - - "Skill Issues" section exists - - Documents "skill not loading" with checks - - Documents "custom skill not found" with SKILL.md format requirements - - Solutions include directory verification steps - - Notes: Common anticipated issues - -- [ ] **Task 3: Add sync issues section to troubleshooting** - - Scope: `docs/troubleshooting.md` - - Depends on: Task 1 - - Acceptance: - - "Sync Issues" section exists - - Documents "sync overwrote my changes" with backup locations - - Documents "sync reports conflicts" with --dry-run and --force options - - Clarifies what is/isn't overwritten - - Notes: Sync behavior is confusing for users - -- [ ] **Task 4: Add Ralph issues section to troubleshooting** - - Scope: `docs/troubleshooting.md` - - Depends on: Task 1 - - Acceptance: - - "Ralph Issues" section exists - - Documents "Ralph not finding tasks" with checklist - - Documents "Ralph stops unexpectedly" with context/blocking explanations - - Includes resume command example - - Notes: Ralph issues are common for new users - -- [ ] **Task 5: Add permission issues and getting help sections** - - Scope: `docs/troubleshooting.md` - - Depends on: Task 1 - - Acceptance: - - "Permission Issues" section with chmod fix - - "Getting Help" section with GitHub Issues link - - Link to CHANGELOG for known fixes - - Notes: Complete the troubleshooting guide - -- [ ] **Task 6: Add quick troubleshooting reference to QUICKSTART.md** - - Scope: `QUICKSTART.md` - - Depends on: Task 5 - - Acceptance: - - "Troubleshooting" section at end of QUICKSTART - - Table with 3-4 common problems and quick fixes - - Links to docs/troubleshooting.md for details - - Notes: Keep brief, just top issues - -- [ ] **Task 7: Link troubleshooting from docs/index.html** - - Scope: `docs/index.html` - - Depends on: Task 5 - - Acceptance: - - Link to troubleshooting.md on GitHub - - Placed in footer or support section - - Notes: Helps users find help from landing page - -## Verification - -After all tasks complete: - -```bash -# Verify troubleshooting.md exists with all sections -test -f docs/troubleshooting.md -grep -q "Installation Issues" docs/troubleshooting.md -grep -q "Skill Issues" docs/troubleshooting.md -grep -q "Sync Issues" docs/troubleshooting.md -grep -q "Ralph Issues" docs/troubleshooting.md - -# Verify QUICKSTART links to troubleshooting -grep -q "troubleshooting" QUICKSTART.md -``` - -All checks must pass before marking plan complete. diff --git a/.agents/prds/AGENTS.md b/.agents/prds/AGENTS.md deleted file mode 100644 index 91a2997..0000000 --- a/.agents/prds/AGENTS.md +++ /dev/null @@ -1,39 +0,0 @@ -# PRD Guidelines - -Lightweight product requirements for solo development with AI agent execution. - -## Workflow - -```text -Research → PRD → Plan → Ralph executes -``` - -1. **Draft PRD** (15-30 min timebox) — use TEMPLATE.md -2. **Generate plan** — create `.agents/plans/todo/PLAN-XXX.md` with Ralph task format -3. **Execute** — ralph runs the plan -4. **Close** — update PRD status, move plan to completed - -## Rules - -- Keep PRD under 1 page (~400-700 words) -- Timebox to 30 minutes max -- Acceptance criteria must be testable -- Always include non-goals -- Link PRD ↔ Plan bidirectionally - -## PRD vs Plan - -| PRD | Plan | -|-----|------| -| Why / What | How / Tasks | -| Stable context | Execution checklist | -| Problem + goals | File scopes + acceptance | - -## Naming - -```text -PRD-YYYYMMDD-short-title.md -PLAN-YYYYMMDD-short-title.md -``` - -Keep titles aligned between PRD and Plan. diff --git a/.agents/prds/TEMPLATE.md b/.agents/prds/TEMPLATE.md deleted file mode 100644 index bb7ae6b..0000000 --- a/.agents/prds/TEMPLATE.md +++ /dev/null @@ -1,45 +0,0 @@ -# PRD: - -| Field | Value | -|-------|-------| -| Status | draft / ready / in-progress / done | -| Date | YYYY-MM-DD | -| Plan | `../plans/todo/PLAN-XXX.md` | - -## Problem - -What user pain or product gap? (2-4 sentences) - -## Goal - -One sentence describing success. - -## Non-goals - -- What we will NOT do - -## Users / Use case - -- Who uses it + primary scenario - -## Proposed change - -What changes? (bullets, no implementation detail) - -## Acceptance criteria - -- [ ] Testable outcome 1 -- [ ] Testable outcome 2 - -## UX notes - -Optional: sketches, screen states, interactions - -## Open questions / Risks - -- Unanswered questions -- Known risks - -## Research - -- `../research/doc.md` — key takeaway diff --git a/.agents/reference/.gitkeep b/.agents/reference/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/.agents/reference/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.agents/references/.gitkeep b/.agents/references/.gitkeep new file mode 100644 index 0000000..8000e38 --- /dev/null +++ b/.agents/references/.gitkeep @@ -0,0 +1 @@ +# Keep .agents/references/ present on fresh installs. diff --git a/.agents/scripts/sync.sh b/.agents/scripts/sync.sh index 7fcdaef..1d8eaa1 100755 --- a/.agents/scripts/sync.sh +++ b/.agents/scripts/sync.sh @@ -54,7 +54,9 @@ All options are passed through to the upstream install.sh script. Options: --dry-run Show what would happen without making changes + --diff Show unified diff for conflicts instead of overwriting --force Overwrite conflicts (creates backup first) + --write-conflicts Create .dot-agents.md/.dot-agents.new files for conflicts --interactive Prompt for each conflict --yes Skip confirmation prompts --version Show version and installation info @@ -62,7 +64,7 @@ Options: Examples: # Preview changes - .agents/scripts/sync.sh --dry-run + .agents/scripts/sync.sh --diff # Force update with backup .agents/scripts/sync.sh --force diff --git a/.agents/skills/AGENTS.md b/.agents/skills/AGENTS.md index 04e2f91..55305db 100644 --- a/.agents/skills/AGENTS.md +++ b/.agents/skills/AGENTS.md @@ -48,6 +48,8 @@ The description determines when the skill gets loaded: 3. **Define workflows** - Step-by-step processes work best 4. **Add checklists** - Help ensure nothing is missed 5. **Reference patterns** - Point to existing code/files +6. **Keep workflow skills durable** - Put reusable templates in `assets/` and runnable helpers in `scripts/` +7. **Avoid runner-specific concepts** - Prefer work items and handoff prompts over assuming a specific agent runtime ## Testing Skills @@ -63,6 +65,7 @@ Verify your skill by loading it and checking: | Skill | Purpose | | ----- | ------- | | `adapt` | Analyze project and fill in AGENTS.md after installation | -| `ralph` | Autonomous multi-iteration implementation using handoff loops | -| `research` | Deep research on technical topics, saves to `.agents/research/` | +| `agent-work` | Create and maintain `.agents/work/` work items | +| `feature-planning` | Turn context into plans and paste-ready handoff prompts | +| `research` | Research technical topics, saving work-local or reusable findings | | `tmux` | Manage background processes using tmux windows for servers and long-running tasks | diff --git a/.agents/skills/adapt/SKILL.md b/.agents/skills/adapt/SKILL.md index 9202b42..ee2d113 100644 --- a/.agents/skills/adapt/SKILL.md +++ b/.agents/skills/adapt/SKILL.md @@ -1,6 +1,6 @@ --- name: adapt -description: "Analyze project and fill in AGENTS.md. Use when adapting dot-agents to a new project, after initial installation." +description: "Analyzes a project and fills in AGENTS.md. Use after installing dot-agents or when project commands and conventions change. Triggers on: adapt, setup AGENTS, customize AGENTS." --- # Adapt Skill @@ -28,12 +28,13 @@ Run this skill after installing dot-agents into a new project to customize the c - List detected tech stack - Extract commands from package.json scripts, Cargo.toml, Makefile, etc. - Note any project-specific conventions observed + - Keep the `.agents/work/` and handoff-prompt workflow guidance intact ## Example Output After running, AGENTS.md should have these sections filled in: -```markdown +````markdown ## Overview my-awesome-app - A Next.js web application with PostgreSQL backend @@ -72,6 +73,13 @@ pnpm format - Components in src/components/ - API routes in src/app/api/ +## Agent Work + +- Durable work lives in `.agents/work///` +- Use `.agents/research/` only for reusable findings +- Ask for a handoff prompt before starting a fresh implementation thread +```` + ## Checklist - [ ] Read package.json/Cargo.toml/go.mod for project name and scripts @@ -80,3 +88,4 @@ pnpm format - [ ] Check for Makefile, Justfile, or task runners - [ ] Look for .eslintrc, .prettierrc, rustfmt.toml for style configs - [ ] Update AGENTS.md with findings +- [ ] Preserve the dot-agents work-item workflow unless the user asks for a custom one diff --git a/.agents/skills/agent-work/SKILL.md b/.agents/skills/agent-work/SKILL.md new file mode 100644 index 0000000..d7a94f7 --- /dev/null +++ b/.agents/skills/agent-work/SKILL.md @@ -0,0 +1,94 @@ +--- +name: agent-work +description: "Creates and curates .agents/work/ work items. Use for durable indexes, artifacts, progress, migration, and new-thread handoffs. Triggers on: work item, agent work, new work item, list active work, handoff prompt." +--- + +# Agent Work + +Create and maintain work items under `.agents/work///` so research, PRDs, plans, progress, decisions, and handoff prompts stay together for one piece of multi-session work. + +A "work item" is a folder; the entries inside `plan.md` are the executable tasks. + +## Workflow + +1. **Check existing context** + - Run `.agents/skills/agent-work/scripts/list-work.sh --all` or search `.agents/work/` before creating a new work item. + - Read a work item's `index.md` first when continuing existing work. +2. **Create the work item** + - Run `.agents/skills/agent-work/scripts/new-work.sh --category --slug --title ""` from the repo root. + - Create only `index.md` at first; do not add empty support folders. +3. **Place artifacts deliberately** + - Use `research.md` for findings specific to this work item. + - Use `.agents/research/` for reusable cross-work findings. + - Use `prd.md` only when requirements need durable alignment. + - Use `plan.md` for implementation-ready tasks; copy `.agents/skills/agent-work/assets/plan-template.md` as a starting point. + - Use `progress.md` for implementation notes, verification results, blockers, and next action. + - Add `decisions/` only when durable decision records are worth linking. +4. **Keep `index.md` current** + - Update `Status:`, `Updated:`, `Artifacts`, `Next Action`, and material `Open Questions` as the work item evolves. + - Keep status in `index.md`; do not move work folders between status directories. +5. **Prepare handoffs when needed** + - Use `feature-planning` to refine a stale or ambiguous plan. + - Ask for a paste-ready handoff prompt before starting a new implementation thread. + - A good handoff prompt names the work item path, active plan slice, scope limits, expected artifact updates, verification, stop conditions, and expected final response. + +## Paths And Statuses + +- Canonical path: `.agents/work///` +- Category values: `feature`, `bugfix`, `tech-debt`, `docs`, `tooling`, `research`, `other` +- Required file: `index.md` +- Status values: `researching`, `planned`, `in-progress`, `blocked`, `completed` +- Optional files: `research.md`, `prd.md`, `plan.md`, `progress.md` +- Optional folders: `research/`, `decisions/` + +Status meanings: + +- `researching`: context exists, but no implementation-ready plan exists yet. +- `planned`: `plan.md` exists and is ready for a handoff prompt or implementation. +- `in-progress`: implementation has started. +- `blocked`: progress needs input, access, or plan changes before continuing. +- `completed`: implementation and verification are done. + +See `.agents/work/AGENTS.md` for conventions automatically applied inside work items. + +## Scripts + +Run commands from the repository root. + +```bash +.agents/skills/agent-work/scripts/new-work.sh \ + --category feature \ + --slug user-authentication \ + --title "User authentication" +``` + +```bash +.agents/skills/agent-work/scripts/list-work.sh +.agents/skills/agent-work/scripts/list-work.sh --all +.agents/skills/agent-work/scripts/list-work.sh --status blocked +``` + +## Legacy Plan Migration + +Existing legacy plan and PRD documents are user content. Do not auto-migrate or delete them. Retired Ralph guidance/templates in those folders may be backed up and removed by sync. + +When the user asks to migrate one legacy plan: + +1. Create `.agents/work///index.md`. +2. Copy the old plan to `plan.md`, preserving task checkboxes. +3. Copy a matching progress file to `progress.md` if it exists. +4. Copy or summarize a linked PRD into `prd.md` if still relevant. +5. Update `index.md` with status, artifacts, next action, and open questions. +6. Leave legacy files in place unless the user explicitly asks to delete them. + +## Templates + +- `assets/work-index-template.md`: starting point for `index.md` +- `assets/plan-template.md`: implementation-ready `plan.md` contract +- `assets/prd-template.md`: optional `prd.md` structure +- `assets/work-decision-template.md`: optional decision record template + +## Verification + +- Confirm new work items contain `index.md` and no empty support folders. +- Run `.agents/skills/agent-work/scripts/list-work.sh --all` and confirm the work item appears with the expected status. diff --git a/.agents/skills/agent-work/assets/plan-template.md b/.agents/skills/agent-work/assets/plan-template.md new file mode 100644 index 0000000..94173ad --- /dev/null +++ b/.agents/skills/agent-work/assets/plan-template.md @@ -0,0 +1,86 @@ +# Plan Template + +Use this template when creating `.agents/work///plan.md`. Plans following this format are implementation-ready and easy to hand off to a fresh agent thread. + +## Template + +```markdown +# [Plan Title] + +[Brief description of what this plan accomplishes.] + +## Goals + +- Goal 1 +- Goal 2 + +## Tasks + +- [ ] **Task 1: Short descriptive title** + - Scope: `path/to/affected/files` or module name + - Depends on: none + - Acceptance: + - Specific, verifiable criterion 1 + - Specific, verifiable criterion 2 + - Notes: Optional implementation hints + +- [ ] **Task 2: Another task title** + - Scope: `path/to/affected/files` + - Depends on: Task 1 + - Acceptance: + - Specific, verifiable criterion + - Notes: None + +## Implementation Notes + +[Key principles, pitfalls to avoid, testing strategy, and scope limits.] + +## Constraints / Decisions + +- Constraint or decision 1 +- Constraint or decision 2 + +## Acceptance Criteria + +- Overall criterion 1 +- Overall criterion 2 + +## Verification + +- Command or manual check 1 +- Command or manual check 2 +``` + +## Task Format Rules + +Each task must include: + +| Field | Required | Description | +| --- | --- | --- | +| **Title** | Yes | `**Task N: Short descriptive title**` | +| **Scope** | Yes | File path, module, package, or subsystem affected | +| **Depends on** | Yes | Task ID or `none` | +| **Acceptance** | Yes | Specific, verifiable criteria | +| **Notes** | No | Implementation hints, commands, or risks | + +Split a task if it cannot be described in 2-3 sentences or cannot be reviewed independently. + +## Task Status Markers + +| Marker | Meaning | +| --- | --- | +| `- [ ]` | Not started | +| `- [x]` | Completed | +| `- [ ] (blocked)` | Blocked, needs intervention | +| `- [ ] (manual-verify)` | Requires manual verification | + +## Handoff-Ready Checklist + +Before asking for an implementation handoff prompt, confirm: + +- [ ] The plan lives at `.agents/work///plan.md`. +- [ ] `index.md` links the active plan and has the correct `Status:`. +- [ ] Every task has `Scope`, `Depends on`, and verifiable `Acceptance`. +- [ ] The next task or phase is clear. +- [ ] External blockers and human-only steps are explicit. +- [ ] The intended verification commands are named when not obvious. diff --git a/.agents/skills/agent-work/assets/prd-template.md b/.agents/skills/agent-work/assets/prd-template.md new file mode 100644 index 0000000..54eda6e --- /dev/null +++ b/.agents/skills/agent-work/assets/prd-template.md @@ -0,0 +1,60 @@ +# PRD Template + +Use this template when work needs requirements alignment before implementation. For small, scoped changes with clear acceptance criteria, create `plan.md` directly instead. + +## Template + +```markdown +# [Feature Name] PRD + +## Problem Statement + +What problem are we solving? Why now? + +## Goals + +- Goal 1 +- Goal 2 + +## Non-Goals + +- What we are explicitly not doing + +## Users / Use Cases + +- Primary user or system actor and scenario + +## Requirements + +### Must Have + +- [ ] Requirement 1 +- [ ] Requirement 2 + +### Nice to Have + +- [ ] Optional requirement + +## Constraints / Decisions + +- Constraint or decision 1 +- Constraint or decision 2 + +## Acceptance Criteria + +- Criterion 1 +- Criterion 2 + +## Verification / Rollout + +- How this should be verified +- Rollout guardrails or follow-up checks + +## Open Questions + +- [ ] Question that materially affects scope, sequence, or architecture +``` + +## Handoff To Planning + +Once the PRD is approved, create `plan.md` in the same work item using the [agent-work plan template](plan-template.md). Do not create new `.agents/plans/` files. diff --git a/.agents/skills/agent-work/assets/work-decision-template.md b/.agents/skills/agent-work/assets/work-decision-template.md new file mode 100644 index 0000000..2ba0ba2 --- /dev/null +++ b/.agents/skills/agent-work/assets/work-decision-template.md @@ -0,0 +1,26 @@ +# Decision: [Short Title] + +Date: YYYY-MM-DD +Status: proposed | accepted | superseded + +## Context + +[What forced this decision? Link work item artifacts and evidence.] + +## Decision + +[What are we doing?] + +## Rationale + +[Why this option over alternatives?] + +## Consequences + +- Positive consequence +- Trade-off or risk + +## Links + +- Work item: `../index.md` +- Related plan/research/PRD: `../plan.md` diff --git a/.agents/skills/agent-work/assets/work-index-template.md b/.agents/skills/agent-work/assets/work-index-template.md new file mode 100644 index 0000000..68d297b --- /dev/null +++ b/.agents/skills/agent-work/assets/work-index-template.md @@ -0,0 +1,25 @@ +# {{TITLE}} + +Status: {{STATUS}} +Category: {{CATEGORY}} +Updated: {{UPDATED}} + +## Summary + +[2-4 sentences describing the work item and why it exists.] + +## Artifacts + +- Research: none +- PRD: none +- Plan: none +- Progress: none +- Decisions: none + +## Next Action + +- [The next concrete action for a future agent thread.] + +## Open Questions + +- [ ] [Only questions that materially affect scope, sequence, or architecture.] diff --git a/.agents/skills/agent-work/scripts/list-work.sh b/.agents/skills/agent-work/scripts/list-work.sh new file mode 100755 index 0000000..3a11b7e --- /dev/null +++ b/.agents/skills/agent-work/scripts/list-work.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'USAGE' +Usage: + list-work.sh [--all] [--status ] + +Lists agent work items from .agents/work/. By default, completed work items are hidden. +USAGE +} + +show_all=0 +status_filter="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --all) + show_all=1 + shift + ;; + --status) + status_filter="${2:-}" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown argument: $1" >&2 + usage >&2 + exit 2 + ;; + esac +done + +if [[ ! -d .agents/work ]]; then + exit 0 +fi + +printf '%-12s %-14s %-12s %s\n' "Status" "Category" "Updated" "Work Item" +printf '%-12s %-14s %-12s %s\n' "------------" "--------------" "------------" "---------" + +find .agents/work -mindepth 3 -maxdepth 3 -name index.md -type f | sort | while IFS= read -r index_file; do + title=$(sed -n '1s/^# //p' "$index_file") + status=$(sed -n 's/^Status: //p' "$index_file" | head -1) + category=$(sed -n 's/^Category: //p' "$index_file" | head -1) + updated=$(sed -n 's/^Updated: //p' "$index_file" | head -1) + + [[ -n "$status" ]] || status="unknown" + [[ -n "$category" ]] || category="unknown" + [[ -n "$updated" ]] || updated="unknown" + [[ -n "$title" ]] || title="$(basename "$(dirname "$index_file")")" + + if [[ -n "$status_filter" && "$status" != "$status_filter" ]]; then + continue + fi + + if [[ "$show_all" -eq 0 && "$status" == "completed" ]]; then + continue + fi + + printf '%-12s %-14s %-12s %s (%s)\n' "$status" "$category" "$updated" "$title" "$index_file" +done diff --git a/.agents/skills/agent-work/scripts/new-work.sh b/.agents/skills/agent-work/scripts/new-work.sh new file mode 100755 index 0000000..c2059c0 --- /dev/null +++ b/.agents/skills/agent-work/scripts/new-work.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'USAGE' +Usage: + new-work.sh --category --slug --title [--status <status>] + +Creates .agents/work/<category>/<work-slug>/index.md from the work index template. +Default status: researching +Categories: feature, bugfix, tech-debt, docs, tooling, research, other +USAGE +} + +category="" +slug="" +title="" +status="researching" + +while [[ $# -gt 0 ]]; do + case "$1" in + --category) + category="${2:-}" + shift 2 + ;; + --slug) + slug="${2:-}" + shift 2 + ;; + --title) + title="${2:-}" + shift 2 + ;; + --status) + status="${2:-}" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown argument: $1" >&2 + usage >&2 + exit 2 + ;; + esac +done + +if [[ -z "$category" || -z "$slug" || -z "$title" ]]; then + usage >&2 + exit 2 +fi + +case "$status" in + researching|planned|in-progress|blocked|completed) ;; + *) + echo "Invalid status: $status" >&2 + echo "Expected one of: researching, planned, in-progress, blocked, completed" >&2 + exit 2 + ;; +esac + +is_kebab_case() { + [[ "$1" =~ ^[abcdefghijklmnopqrstuvwxyz0123456789]+(-[abcdefghijklmnopqrstuvwxyz0123456789]+)*$ ]] +} + +if ! is_kebab_case "$category"; then + echo "Invalid category: $category" >&2 + echo "Expected one of: feature, bugfix, tech-debt, docs, tooling, research, other" >&2 + exit 2 +fi + +case "$category" in + feature|bugfix|tech-debt|docs|tooling|research|other) ;; + *) + echo "Invalid category: $category" >&2 + echo "Expected one of: feature, bugfix, tech-debt, docs, tooling, research, other" >&2 + exit 2 + ;; +esac + +if ! is_kebab_case "$slug"; then + echo "Invalid slug: $slug" >&2 + echo "Use lowercase kebab-case." >&2 + exit 2 +fi + +work_dir=".agents/work/$category/$slug" +index_file="$work_dir/index.md" +template=".agents/skills/agent-work/assets/work-index-template.md" + +if [[ -e "$index_file" ]]; then + echo "Work item index already exists: $index_file" >&2 + exit 1 +fi + +if [[ ! -f "$template" ]]; then + echo "Missing template: $template" >&2 + exit 1 +fi + +mkdir -p "$work_dir" + +escape_sed_replacement() { + printf '%s' "$1" | sed -e 's/[\\&|]/\\&/g' +} + +escaped_title=$(escape_sed_replacement "$title") +escaped_category=$(escape_sed_replacement "$category") +escaped_status=$(escape_sed_replacement "$status") +updated=$(date +%F) + +sed \ + -e "s|{{TITLE}}|$escaped_title|g" \ + -e "s|{{STATUS}}|$escaped_status|g" \ + -e "s|{{CATEGORY}}|$escaped_category|g" \ + -e "s|{{UPDATED}}|$updated|g" \ + "$template" > "$index_file" + +echo "$index_file" diff --git a/.agents/skills/feature-planning/SKILL.md b/.agents/skills/feature-planning/SKILL.md new file mode 100644 index 0000000..e914628 --- /dev/null +++ b/.agents/skills/feature-planning/SKILL.md @@ -0,0 +1,144 @@ +--- +name: feature-planning +description: "Turns research and PRDs into implementation-ready plans and paste-ready handoff prompts. Use for planning, plan refinement, and new-thread prompts. Triggers on: plan, PRD, feature planning, handoff prompt, stress-test design." +--- + +# Feature Planning + +Manage work-item planning from rough intent through PRD, implementation-ready plan, and paste-ready prompt for a fresh implementation thread. + +## Workflow Overview + +```text +Work Item → Research/PRD as needed → Plan → Refine → Handoff Prompt → Implement → Record Progress +``` + +1. **Work item**: Use `agent-work` to create or locate `.agents/work/<category>/<work-slug>/`. +2. **Research**: Save task-specific findings in the work item and reusable findings in `.agents/research/`. +3. **PRD**: Create `prd.md` only when requirements need durable alignment. +4. **Plan**: Create or update `plan.md` with scoped tasks, dependencies, and acceptance criteria. +5. **Refine**: Validate assumptions against current repo reality before implementation. +6. **Handoff prompt**: Produce a paste-ready prompt for the next implementation thread. +7. **Progress**: The implementation thread updates task checkboxes, `progress.md`, and `index.md`. + +## Plan Locations + +New plans live inside work items: + +```text +.agents/work/<category>/<work-slug>/ +├── index.md +├── research.md +├── prd.md +├── plan.md +└── progress.md +``` + +Legacy standalone plan and PRD documents are user content. Migrate one at a time into `.agents/work/` only when requested. Retired Ralph guidance/templates may be backed up and removed by sync. + +## PRD Guidance + +Create `prd.md` when work is user-facing, ambiguous, cross-team, or likely to span multiple sessions. Use the [agent-work PRD template](../agent-work/assets/prd-template.md). + +Skip the PRD for small scoped fixes when the desired behavior and acceptance criteria are already clear. + +## Plan Guidance + +Use the [agent-work plan template](../agent-work/assets/plan-template.md). Keep plans implementation-ready: + +- Each task has `Scope`, `Depends on`, and verifiable `Acceptance`. +- The next task or phase is obvious. +- Scope limits and verification commands are explicit when not obvious. +- Blockers, manual steps, and risky assumptions are called out. +- Tasks are small enough to review independently. + +For larger work, prefer an early thin slice that proves the end-to-end path before broad hardening. + +## Pre-Implementation Refinement + +Use this before writing a handoff prompt when work is multi-phase, ambiguous, or stale. + +1. Read the work item's `index.md` and active `plan.md`. +2. Read relevant `research.md`, `prd.md`, and decisions only as needed. +3. Validate key assumptions against current code, dependencies, and test setup. +4. Resolve material open questions with repo evidence where possible; ask the user only for decisions the repo cannot answer. +5. If a planned task is already satisfied, record evidence and update the plan instead of creating no-op work. +6. Update `plan.md`, `progress.md`, and `index.md` when refinement changes the next action or known constraints. + +Skip the full pass for small, obvious changes where the plan and repo state are already aligned. + +## New-Thread Handoff Prompt + +Use this mode when asked to write a prompt for a new thread, implementation handoff, or continuation. Produce a paste-ready prompt; do not implement the work yourself unless the user explicitly asks. + +The prompt should include: + +1. Work item path. +2. Files to read first. +3. Goal and current state. +4. Exact task, phase, or slice to implement. +5. Scope limits and non-goals. +6. Artifact update contract for `plan.md`, `progress.md`, and `index.md`. +7. Verification commands or manual checks. +8. Stop conditions. +9. Expected final response format. + +Use this template: + +```text +You are continuing the work item at: + +.agents/work/<category>/<slug>/ + +Read first: +1. .agents/work/<category>/<slug>/index.md +2. .agents/work/<category>/<slug>/plan.md +3. Relevant artifacts linked from index.md + +Goal: +<one-paragraph goal> + +Current state: +<what is already done, plus branch/commit/thread anchors if useful> + +Implement only this slice: +- <Task N / phase / exact acceptance criteria> + +Scope limits: +- Touch only <paths/modules> unless the plan proves the scope is wrong. +- Do not broaden the feature. +- If the plan is stale, update the plan and explain why before implementing. + +Progress contract: +- Update completed task checkboxes in plan.md. +- Append or update progress.md with changes, verification, blockers, and next action. +- Update index.md Status, Updated, Artifacts, and Next Action when they change. + +Verification: +- Run <commands>. +- If verification cannot run, record why and what remains unverified. + +Stop conditions: +- Stop and report if blocked by missing decisions, credentials, unsafe migrations, unrelated failing tests, or scope expansion. + +Expected final response: +- Summary of changes +- Files changed +- Verification results +- Work item updates made +- Remaining next action +``` + +## Stress-Test Mode + +Use this only when the user explicitly asks to stress-test, grill, or walk decision branches. + +1. Inspect the existing PRD, plan, repo docs, and relevant code first. +2. Ask one highest-leverage unresolved question at a time. +3. Provide a recommended default answer and brief rationale for each question. +4. Capture outcomes in `prd.md`, `plan.md`, or `index.md`. +5. Exit once remaining ambiguity no longer materially changes scope, sequencing, or architecture. + +## Definition Of Done + +Planning is done when the work item has a current `index.md`, required context artifacts, an implementation-ready `plan.md`, and either a clear next action or a paste-ready handoff prompt. diff --git a/.agents/skills/ralph/SKILL.md b/.agents/skills/ralph/SKILL.md deleted file mode 100644 index 88804fb..0000000 --- a/.agents/skills/ralph/SKILL.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -name: ralph -description: Autonomous multi-iteration feature implementation using handoff loops. Use when asked to "run ralph", "execute autonomously", "implement this plan autonomously", or for hands-free feature development from structured plans. ---- - -# Ralph Autonomous Agent - -Orchestrates autonomous code generation through repeated iterations using fresh agent instances until all tasks are complete. - -## Execution Contract - -### Inputs - -When invoking ralph, provide: - -- **Plan file path**: Absolute or workspace-relative path to the plan markdown file -- **Starting task** (optional): Task ID to resume from (e.g., "Task 3") -- **Max tasks** (optional): Maximum tasks to complete before pausing for review (default: 5) - -### State Files - -Ralph creates a companion progress file alongside the plan: - -```text -.agents/plans/in-progress/ -├── my-feature.md # The plan -└── my-feature.progress.md # Progress log (auto-created) -``` - -### Task Status Markers - -In plan files, tasks use checkbox status with optional annotations: - -| Marker | Meaning | -|--------|---------| -| `- [ ]` | Not started | -| `- [x]` | Completed | -| `- [ ] (blocked)` | Blocked, needs intervention | -| `- [ ] (manual-verify)` | Requires manual verification | - -### Stop Conditions - -The loop exits when ANY of these occur: - -1. **All tasks complete**: Every task checkbox is `[x]` -2. **Max tasks reached**: Completed N tasks this session (default: 5) — pause for user review -3. **Blocked encountered**: A task is marked `(blocked)` -4. **Only manual-verify remaining**: All incomplete tasks require manual verification -5. **Explicit stop**: User interrupts - -### Handoff Payload - -When handing off to fresh iteration, include: - -```text -Continue ralph execution for: [plan file path] - -Current task: [Task ID and title] -Tasks completed this session: [N of max_tasks] -Last progress: [Most recent progress entry summary] -Next action: [Specific next step] - -Load the ralph skill and continue execution. -``` - -### Pause for Review - -When max tasks is reached (before all tasks complete): - -1. **Update progress file**: Log "Paused after N tasks for review" -2. **Commit all work**: Ensure all completed tasks are committed -3. **Report to user**: List completed tasks and next task to resume from -4. **Do NOT handoff**: Wait for user to review and continue - -**Resume command:** - -```text -Continue ralph from Task X on [plan file path] -``` - -## Phases - -### Phase 1: Setup - -Before running the loop, ensure the plan has proper structure. - -**Required task format:** - -```markdown -- [ ] **Task N: Short descriptive title** - - Scope: `path/to/affected/files` or package name - - Depends on: Task M (or "none") - - Acceptance: - - Specific criterion 1 - - Specific criterion 2 - - Notes: Optional implementation hints -``` - -**Task sizing rule:** If you can't describe the task in 2-3 sentences, it's too big. Split it. - -**Dependency ordering:** Schema → Service → API → UI → Tests - -### Phase 2: Execution Loop - -Each iteration follows this workflow: - -1. **Load context**: Read plan file, identify next incomplete task, track tasks completed this session -2. **Check dependencies**: Ensure all `Depends on` tasks are complete -3. **Implement**: Complete the task following its scope and acceptance criteria -4. **Verify**: Run verification commands (see Verification section) -5. **Update progress**: Append entry to `.progress.md` -6. **Update plan**: Check off completed task `[x]` -7. **Commit**: One task = one commit with proper footers -8. **Increment counter**: tasks_completed++ -9. **Check stop conditions**: - - If tasks_completed >= max_tasks → pause for review (do NOT handoff) - - If all tasks complete → exit with success - - Otherwise → handoff to next iteration - -**Git discipline:** - -- One task = one commit -- Never push to main branch -- Include footers: `Amp-Thread-ID` and `Co-authored-by: Amp <amp@ampcode.com>` -- Commit format: `feat: [Task ID] - [Task Title]` - -## Verification Strategy - -Run verification commands appropriate for the project. Check `AGENTS.md` for project-specific commands. - -| Situation | Action | -|-----------|--------| -| Every task | Run typecheck/build command | -| After code changes | Run linter | -| Logic changes | Run tests | -| Pre-commit | Run full CI check | - -**Examples by language:** - -```bash -# TypeScript/Node -npm run check && npm run lint && npm test - -# Rust -cargo check && cargo clippy && cargo test - -# Go -go build ./... && go test ./... - -# Python -mypy . && ruff check . && pytest -``` - -## Stuck Detection & Safety - -### Limits - -- **Max retries per task**: 2 attempts before marking blocked -- **Scope control**: Only modify files in declared `Scope` - -### Blocking a Task - -When a task cannot proceed: - -1. Add `(blocked)` annotation to the task checkbox -2. Add blocker details to progress file -3. Stop the loop and surface to user - -**Example blocked task:** - -```markdown -- [ ] (blocked) **Task 5: Integrate payment API** - - Scope: `cloud/functions/payments` - - Depends on: Task 4 - - Acceptance: Payment webhook handler works - - Notes: Blocked - need API credentials from finance team -``` - -### Manual Verification Tasks - -Tasks marked `(manual-verify)` require human interaction: - -- Don't retry these automatically -- Stop loop when only manual-verify tasks remain -- Surface verification instructions to user - -## Guardrails - -1. **Scope control**: Only touch files in declared `Scope` -2. **No scope creep**: Expanding scope requires explicit plan edit -3. **No prod commands**: Never run production deployments -4. **No secrets**: Never commit credentials or API keys -5. **Branch safety**: Never push to main - -## Usage - -### Starting Fresh - -```text -Run ralph on .agents/plans/in-progress/my-feature.md -``` - -### Resuming - -```text -Continue ralph from Task 5 on .agents/plans/in-progress/my-feature.md -``` - -### Checking Status - -```text -Show ralph progress for .agents/plans/in-progress/my-feature.md -``` - -## Integration with Plans - -Ralph works with plans in the standard directory structure: - -- Plans live in `.agents/plans/in-progress/` -- Create plans manually following the task format above -- Use ralph to execute plans autonomously diff --git a/.agents/skills/ralph/references/progress-format.md b/.agents/skills/ralph/references/progress-format.md deleted file mode 100644 index b8efc59..0000000 --- a/.agents/skills/ralph/references/progress-format.md +++ /dev/null @@ -1,137 +0,0 @@ -# Progress File Format - -Progress files track work across iterations. They are append-only logs. - -## File Location - -Progress files live alongside their plan: - -```text -.agents/plans/in-progress/ -├── my-feature.md # Plan file -└── my-feature.progress.md # Progress log -``` - -## Entry Format - -Each completed task gets one entry: - -```markdown -## Task N: [Task Title] - -**Thread**: [Amp thread URL] -**Status**: completed | blocked | partial -**Iteration**: N - -### Changes - -- `src/module.rs` - Added X -- `src/lib.rs` - Modified Y - -### Commands Run - -- `just check` ✓ -- `just test` ✓ - -### Learnings - -- [Any patterns discovered or gotchas encountered] - -### Next - -- [What the next iteration should do] - ---- -``` - -## Required Fields - -| Field | Description | -| ----- | ----------- | -| Task ID | Task number and title from plan | -| Thread | Amp thread URL for traceability | -| Status | `completed`, `blocked`, or `partial` | -| Iteration | Which loop iteration this was | -| Changes | Files modified with brief description | -| Commands Run | Verification commands and pass/fail | -| Next | What the next iteration should focus on | - -## Optional Fields - -| Field | Description | -| ----- | ----------- | -| Learnings | Patterns discovered, gotchas, or tips for future | -| Blockers | For blocked status, describe the blocker | - -## Example Progress File - -```markdown -# Progress: My Feature - -## Task 1: Add investor type enum - -**Thread**: https://ampcode.com/threads/T-abc123 -**Status**: completed -**Iteration**: 1 - -### Changes - -- `src/protocol.rs` - Added new command enum variant -- `src/lib.rs` - Exported new command - -### Commands Run - -- `just check` ✓ - -### Next - -- Task 2: Implement command handler - ---- - -## Task 2: Implement command handler - -**Thread**: https://ampcode.com/threads/T-def456 -**Status**: completed -**Iteration**: 2 - -### Changes - -- `src/protocol.rs` - Added handler function - -### Commands Run - -- `just check` ✓ -- `just test` ✓ - -### Learnings - -- Protocol requires proper byte alignment for display commands - -### Next - -- Task 3: Add CLI integration - ---- -``` - -## Blocked Entry Example - -```markdown -## Task 5: Integrate payment API - -**Thread**: https://ampcode.com/threads/T-xyz789 -**Status**: blocked -**Iteration**: 5 - -### Blockers - -- Need API credentials from finance team -- Contact: finance@company.com - -### Next - -- Wait for credentials, then resume from Task 5 - ---- -``` diff --git a/.agents/skills/research/SKILL.md b/.agents/skills/research/SKILL.md index 03d3f69..07e50af 100644 --- a/.agents/skills/research/SKILL.md +++ b/.agents/skills/research/SKILL.md @@ -1,139 +1,127 @@ --- name: research -description: Deep research on technical topics, libraries, APIs, or concepts. Use when asked to research, investigate, explore deeply, or gather comprehensive information on a topic. Saves learnings to .agents/research/. +description: "Researches technical questions with authoritative sources and saves work-local or reusable findings. Use for docs, comparisons, APIs, and architecture references. Triggers on: research, investigate, compare, gather references." --- # Research Skill -Conducts deep research on technical topics, saving findings for future reference. - -## Capabilities - -- Web search for documentation, articles, and examples -- Deep analysis using Oracle for complex reasoning -- Cross-reference multiple sources -- Save structured learnings to `.agents/research/` +Research a technical question, synthesize reliable evidence, and save findings either work-locally or as reusable notes in `.agents/research/`. ## Workflow -### 1. Clarify Scope +### 0. Check Existing Context -Before starting, confirm: +Before doing new research: -- **Topic**: What exactly needs researching? -- **Depth**: Quick overview or comprehensive deep-dive? -- **Focus**: Implementation details, best practices, comparisons, or concepts? +- If the work belongs to an active work item, read `.agents/work/<category>/<work-slug>/index.md` and prefer work-local `research.md` for task-specific findings. +- Search `.agents/research/` for an existing reusable topic note. +- Check repo docs, attached files, and skill `references/` first. +- If an existing note already answers the question, update it only when stale or incomplete. -### 2. Research Phase +### 1. Define the Research Brief -Use these tools in combination: +Capture these before researching: -| Tool | Use For | -|------|---------| -| `web_search` | Find documentation, articles, tutorials | -| `read_web_page` | Extract detailed content from URLs | -| `oracle` | Deep analysis, synthesizing findings, reasoning about trade-offs | -| `librarian` | Explore open-source implementations | -| `gh` (via Bash) | Fetch repo content, issues, PRs, releases when you have a direct GitHub URL | +- **Question**: What exact question must be answered? +- **Depth**: Default to a targeted answer unless a deep-dive is explicitly requested. +- **Focus**: Implementation details, comparisons, best practices, or conceptual overview. -> **Note:** `librarian` accesses GitHub repositories (public repos and private repos you've authorized). For local codebase searches, use `finder` or `Grep` instead. Use `gh` CLI for targeted queries like `gh repo view`, `gh issue list`, or `gh release list`. +If the request is ambiguous but actionable, state assumptions and proceed. Ask follow-up questions only when ambiguity would materially change the recommendation. -**Research strategy:** +### 2. Gather Evidence -1. Start with `web_search` to find authoritative sources -2. Use `read_web_page` to extract key information -3. Consult `oracle` for analysis and synthesis -4. Use `librarian` to find real-world implementations +Use the smallest toolset that can answer the question. -### 3. Document Findings +| Tool | Use for | +| --- | --- | +| Web search | Find authoritative sources when local docs are insufficient | +| Web page reading | Extract relevant details from specific URLs | +| Oracle or another reasoning model | Synthesize trade-offs after evidence is gathered | +| Repository search | Inspect local implementations and patterns | +| GitHub tooling | Inspect issues, PRs, releases, or external repository examples | -Save research to `.agents/research/[topic-slug].md`: +Guidelines: -```markdown -# Research: [Topic Name] +1. Prefer local docs and existing research before external search. +2. Prefer official docs, specs, release notes, and maintainer-authored sources. +3. Use community posts only to fill gaps in official guidance. +4. Target 2-5 high-quality sources instead of broad source dumps. +5. Use deeper reasoning after collecting evidence, not as a substitute for evidence. +6. If the user asks for latest or recent information, force a fresh fetch when your tools support it. -**Date:** YYYY-MM-DD -**Status:** Draft | Complete -**Tags:** [relevant, tags] +### 3. Synthesize Recommendation -## Summary +Produce: -[2-3 sentence overview of key findings] +1. The best current recommendation. +2. Key trade-offs. +3. Confidence level and uncertainty. +4. Unresolved risks or follow-up validations. -## Key Learnings +### 4. Save or Update Findings -- Learning 1 -- Learning 2 -- Learning 3 +Use work-local `.agents/work/<category>/<work-slug>/research.md` when: -## Details +- The research mainly supports one implementation task or work item. +- The findings explain task-specific constraints, alternatives, or plan decisions. +- A future agent should find the research beside `plan.md`, `prd.md`, or `progress.md`. -### [Subtopic 1] +Create or update `.agents/research/<topic-slug>.md` when: -[Detailed findings] +- Findings are likely to be reused across unrelated work. +- The topic needs multiple sources or non-obvious trade-offs. +- The user explicitly asks to document reusable research. -### [Subtopic 2] +If work-local findings later become broadly reusable, add a concise promoted synthesis to `.agents/research/` and link between the files. -[Detailed findings] +Use this template: -## Sources - -- [Source Title](url) - Brief description of what was learned -- [Source Title](url) - Brief description - -## Open Questions - -- [ ] Question that needs further research -- [ ] Another question +```markdown +# Research: [Topic Name] -## Related Research +**Date:** YYYY-MM-DD +**Status:** draft | complete +**Question:** [What was researched] -- [[other-topic.md]] - How it relates -``` +## Recommendation -### 4. Synthesize & Report +[Best current answer in 2-4 sentences] -Provide the user with: +## Key Findings -1. **Executive summary** (3-5 bullet points) -2. **Recommendations** based on findings -3. **Link to saved research file** +- Finding 1 +- Finding 2 +- Finding 3 -## File Naming Convention +## Evidence -Use kebab-case slugs: `.agents/research/[topic-slug].md` +### [Source or Subtopic] -Examples: +[Relevant facts only] -- `react-server-components.md` -- `firebase-auth-patterns.md` -- `zod-vs-yup-comparison.md` +## Sources -## Deep Research Mode +- [Source Title](url) — What this source established -For comprehensive research, use Oracle with focused prompts: +## Open Questions -```text -task: "Analyze [topic] considering: -- Current best practices -- Common pitfalls -- Performance implications -- Security considerations" +- [ ] Include only unresolved questions that materially affect the answer ``` -## Quick Reference +Status definitions: -**Start research:** +- `draft`: Useful findings exist, but material questions remain. +- `complete`: Evidence is sufficient to answer the stated question with confidence. -```text -Research [topic] - [specific focus] -``` +### 5. Report Back -**Check existing research:** +Provide the user with: -```bash -ls -la .agents/research/ -``` +1. A concise summary. +2. A clear recommendation. +3. Link to the saved research file, if saved. +4. Explicit unknowns or open questions. + +## Definition Of Done -**Update existing research:** -Add new sections or update status from Draft to Complete. +Research is complete when the question has a clear answer or recommendation, supporting evidence is cited, reusable findings are saved when warranted, and the user receives the summary plus any saved file path. diff --git a/.agents/skills/tmux/SKILL.md b/.agents/skills/tmux/SKILL.md index e20fea8..656be02 100644 --- a/.agents/skills/tmux/SKILL.md +++ b/.agents/skills/tmux/SKILL.md @@ -1,6 +1,6 @@ --- name: tmux -description: Instructions for using tmux to spawn multiple processes, inspect them, and capture their output. Use when running servers, long-running tasks, or background processes. +description: "Manages background processes in tmux windows. Use when running servers, watchers, long checks, or other non-blocking commands. Triggers on: tmux, background process, dev server, long-running task." --- # tmux diff --git a/.agents/work/AGENTS.md b/.agents/work/AGENTS.md new file mode 100644 index 0000000..1703d64 --- /dev/null +++ b/.agents/work/AGENTS.md @@ -0,0 +1,68 @@ +# Agent Work Guide + +Guidance for durable work-item context under `.agents/work/`. + +## Scope + +Each work item lives at: + +```text +.agents/work/<category>/<work-slug>/ +``` + +Use work items for multi-session work where research, requirements, plans, progress, decisions, and handoff prompts should stay together. Keep `.agents/research/` for reusable cross-work findings. + +A work item is a *container of tasks*; the task checklist lives inside `plan.md`. + +## Required Entrypoint + +Every work item must have `index.md` with these metadata lines near the top: + +```markdown +Status: researching | planned | in-progress | blocked | completed +Category: feature | bugfix | tech-debt | docs | tooling | research | other +Updated: YYYY-MM-DD +``` + +Read `index.md` first when entering a work item, then load only the artifacts needed for the current step. + +## Status Rules + +- Use `researching`, `planned`, `in-progress`, `blocked`, or `completed`: + - `researching`: context exists, but no implementation-ready plan exists yet. + - `planned`: `plan.md` exists and is ready for a handoff prompt or implementation. + - `in-progress`: implementation has started. + - `blocked`: progress needs input, access, or plan changes before continuing. + - `completed`: implementation and verification are done. +- Update `Updated:` whenever `Status:` or `Next Action` changes. +- Keep status in `index.md`; do not move folders between status directories. + +## Artifact Rules + +- `index.md`: required work-item landing page and current summary. +- `research.md`: work-local synthesis when investigation mainly supports this work item. +- `research/`: optional indexed folder for multiple focused research notes. +- `prd.md`: optional requirements document for user-facing, ambiguous, or cross-team work. +- `plan.md`: implementation-ready task plan. +- `progress.md`: running implementation log, verification notes, blockers, and next actions. +- `decisions/`: optional one-file-per-decision records when a decision should outlive chat context. + +Do not create empty support folders by default. Add `research/`, `decisions/`, or other subfolders only when they hold useful files. + +## Research Placement + +Use work-local `research.md` when findings mainly explain this work item's implementation choices. Promote or duplicate a concise reusable synthesis to `.agents/research/` only when the findings are likely to guide future unrelated work. + +## Planning And Progress + +Work-local plans live at `plan.md` and use the canonical agent-work plan contract. A new implementation thread should update task checkboxes, append to `progress.md`, and refresh `index.md` when status, artifacts, or next action changes. + +One active implementation thread should own a work item at a time. If `progress.md` conflicts, preserve both entries in chronological order and recompute the current `index.md` summary. + +## Handoff Prompts + +When preparing a new implementation thread, ask for a paste-ready handoff prompt that names the work item path, the active plan task or phase, scope limits, expected artifact updates, verification commands, stop conditions, and expected final response. + +## Decisions + +Create a file under `decisions/` only when a decision would otherwise be repeated across research, PRD, plan, and chat. Link to the decision file from other artifacts instead of restating the full rationale. diff --git a/.gitignore b/.gitignore index bec93c2..dfeec41 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # External reference repositories -.agents/reference/* -!.agents/reference/.gitkeep +.agents/reference/ +.agents/references/* +!.agents/references/.gitkeep diff --git a/AGENTS.md b/AGENTS.md index d34a54a..0f32be3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## Overview -dot-agents is an AI-ready `.agents/` workspace scaffold for any project. It provides plans, PRDs, research folders, and skills for agent-assisted development workflows. +dot-agents is an AI-ready `.agents/` workspace scaffold for any project. It provides durable work items, reusable research, and skills for planning, handoff prompts, and agent-assisted development across threads. ## Tech Stack @@ -12,85 +12,62 @@ dot-agents is an AI-ready `.agents/` workspace scaffold for any project. It prov ## Workflow ```text -Research → PRD → Plan → Execute +Work Item → Research/PRD as needed → Plan → Handoff Prompt → Implement → Record Progress ``` -1. **Research:** Investigate problem space, save findings to `.agents/research/` -2. **PRD:** Define requirements and acceptance criteria in `.agents/prds/` -3. **Plan:** Break PRD into executable tasks with Ralph-ready format -4. **Execute:** Ralph runs tasks autonomously, commits after each +1. **Work Item:** Create `.agents/work/<category>/<slug>/index.md` as the durable entrypoint. +2. **Research/PRD:** Save task-specific findings and requirements beside the work item. +3. **Plan:** Break work into implementation-ready tasks in `plan.md`. +4. **Handoff Prompt:** Generate a paste-ready prompt for a fresh implementation thread. +5. **Progress:** Implementation threads update `progress.md`, task checkboxes, and `index.md`. ## Project Structure ```text dot-agents/ -├── AGENTS.md # This file - project instructions +├── AGENTS.md # This file - contributor instructions ├── AGENTS.template.md # Template copied to user projects ├── install.sh # Main installation script ├── .agents/ -│ ├── skills/ # Agent skills (adapt, ralph, research, tmux) -│ ├── plans/ # Implementation plans -│ ├── prds/ # Product requirements documents -│ └── research/ # Research and reference material +│ ├── work/ # Work-item guidance installed into projects +│ ├── skills/ # adapt, agent-work, feature-planning, research, tmux +│ ├── research/ # Reusable research notes +│ ├── references/ # External reference repos (gitignored) +│ └── scripts/ # sync.sh ├── docs/ # Full documentation ├── site/ # Landing page source ├── scripts/ # Development scripts └── test/ # Bats integration tests - ├── integration/ # install.bats, sync.bats - ├── fixtures/ # Test fixtures (sample-archive.tar.gz) - ├── mocks/ # Mock curl for offline testing - └── test_helper/ # Bats support libraries ``` ## Using Skills | Command | Effect | -|---------|--------| -| `Run adapt` | Analyze project and fill in AGENTS.md sections | -| `Research [topic]` | Deep investigation, saves to `.agents/research/` | -| `Run ralph on [plan.md]` | Autonomous execution of plan tasks | +| --- | --- | +| `Run adapt` | Analyze project and fill in `AGENTS.md` sections | +| `Create a new work item for ...` | Create durable `.agents/work/` context | +| `Research ...` | Investigate and save work-local or reusable findings | +| `Create/refine a plan for ...` | Produce implementation-ready `plan.md` tasks | +| `Write a handoff prompt for ...` | Produce a paste-ready prompt for a new implementation thread | -Skills are loaded via natural language. See each skill's SKILL.md in `.agents/skills/` for details. +Skills are loaded via natural language. See each skill's `SKILL.md` in `.agents/skills/` for details. -## Plan Management +## Work Item Management -Plans in `.agents/plans/` follow this workflow: +Work items live under: -| Status | Location | -|--------|----------| -| **TODO** | `plans/todo/` | -| **IN-PROGRESS** | `plans/in-progress/` | -| **COMPLETED** | `plans/completed/` | - -**Completing plans:** When moving a plan to `completed/`, also move its corresponding `.progress.md` file if one exists. - -**Archive command:** When asked to "archive completed plans", delete each plan from `completed/` with its own commit. Git history preserves them. - -### Writing Ralph-Ready Plans - -```markdown -- [ ] **Task N: Short descriptive title** - - Scope: `path/to/affected/files` or module name - - Depends on: Task M (or "none") - - Acceptance: - - Specific, verifiable criterion 1 - - Specific, verifiable criterion 2 - - Notes: Optional implementation hints +```text +.agents/work/<category>/<slug>/ ``` -**Task markers:** +Every work item has `index.md` with status, category, updated date, artifact links, next action, and open questions. Optional files include `research.md`, `prd.md`, `plan.md`, `progress.md`, and `decisions/` records. -| Marker | Meaning | -|--------|---------| -| `- [ ]` | Not started | -| `- [x]` | Completed | -| `- [ ] (blocked)` | Blocked, needs intervention | -| `- [ ] (manual-verify)` | Requires manual verification | +Legacy `.agents/plans/` and `.agents/prds/` paths may exist in older installs. Preserve legacy plan and PRD documents as user content, but allow sync to retire stale Ralph guidance/templates. Migrate one plan at a time into `.agents/work/` only when requested. ## Commands ```bash -# Run all tests (lint + BATS) +# Run all tests (lint + Bats) ./scripts/test.sh # Run tests with filter @@ -120,52 +97,45 @@ git push ### Commit Guidelines -- Write clear, descriptive commit messages -- Reference plan numbers in commits (e.g., "Plan 001: Initial setup") -- Commit after each logical step +- Write clear, descriptive commit messages. +- Commit after each logical step. +- Do not push directly to the default branch unless the repository maintainer explicitly requests it. ### Release Workflow ```bash # 1. Update VERSION file with new version -echo "1.0.0" > VERSION +echo "0.3.0" > VERSION # 2. Update CHANGELOG.md - move [Unreleased] items to new version section # 3. Commit changes -git add -A && git commit -m "Release v1.0.0" +git add -A && git commit -m "Release v0.3.0" # 4. Create and push release ./scripts/release.sh --push ``` -The release script: - -- Reads version from `VERSION` file -- Extracts release notes from `CHANGELOG.md` -- Creates git tag `vX.Y.Z` -- Pushes tag and creates GitHub release (requires `gh` CLI) - ## Maintenance After making changes: -1. **Update AGENTS.md** - Keep project structure and commands current -2. **Update README.md** - Reflect user-facing changes -3. **Update plan status** - Move completed plans to `completed/` -4. **Rebuild test fixture** - Run `./scripts/build-test-fixture.sh` if `.agents/` or `AGENTS.template.md` changed +1. **Update AGENTS.md** - Keep contributor structure and commands current. +2. **Update README.md / QUICKSTART.md / docs** - Reflect user-facing workflow changes. +3. **Update tests** - Preserve install/sync behavior in Bats. +4. **Rebuild test fixture** - Run `./scripts/build-test-fixture.sh` if `.agents/` or `AGENTS.template.md` changed. ## Conventions -- Shell scripts use `set -euo pipefail` -- Skills use YAML frontmatter with `name` and `description` -- Documentation in Markdown +- Shell scripts use `set -euo pipefail`. +- Skills use YAML frontmatter with quoted `description` values and `Triggers on:` phrases. +- Documentation uses Markdown with fenced code blocks. ## Architecture Notes The installer (`install.sh`) downloads a tarball from GitHub, extracts it to a temp directory, and copies: -- `AGENTS.template.md` → `./AGENTS.md` (only on fresh install, skipped on sync) -- `.agents/` contents (skills, empty directories for plans/prds/research) +- `AGENTS.template.md` → `./AGENTS.md` on fresh install only. +- Upstream-owned `.agents/` files such as skills, `.agents/work/AGENTS.md`, and `sync.sh`. -User content in `.agents/research/`, `.agents/plans/`, and `.agents/prds/` is preserved during sync. The `AGENTS.md` file is treated as user content after initial install. +User content under `.agents/work/<category>/<slug>/`, `.agents/research/`, and legacy plan/PRD documents is preserved during sync. Retired upstream skills and stale legacy guidance/templates may be backed up and removed during sync. diff --git a/AGENTS.template.md b/AGENTS.template.md index d08f3e9..2198c24 100644 --- a/AGENTS.template.md +++ b/AGENTS.template.md @@ -1,6 +1,5 @@ -> **📝 TEMPLATE:** This is the dot-agents AGENTS.md template. -> Customize it for your project by filling in the sections below. -> Delete this banner when done. +> **📝 TEMPLATE:** This is the dot-agents `AGENTS.md` template. +> Customize it for your project, then delete this banner. # Project Instructions @@ -17,13 +16,14 @@ ## Workflow ```text -Research → PRD → Plan → Execute +Work Item → Research/PRD as needed → Plan → Handoff Prompt → Implement → Record Progress ``` -1. **Research:** Investigate problem space, save findings to `.agents/research/` -2. **PRD:** Define requirements and acceptance criteria in `.agents/prds/` -3. **Plan:** Break PRD into executable tasks with Ralph-ready format -4. **Execute:** Ralph runs tasks autonomously, commits after each +1. **Work Item:** Create durable context in `.agents/work/<category>/<slug>/`. +2. **Research/PRD:** Save task-specific findings and requirements beside the work item. +3. **Plan:** Break work into implementation-ready tasks in `plan.md`. +4. **Handoff Prompt:** Generate a paste-ready prompt for a fresh implementation thread. +5. **Progress:** Implementation threads update `progress.md`, task checkboxes, and `index.md`. ## Project Structure @@ -31,66 +31,73 @@ Research → PRD → Plan → Execute project/ ├── AGENTS.md # This file - project instructions ├── .agents/ -│ ├── reference/ # External repos (gitignored) -│ ├── research/ # Research and reference material -│ ├── prds/ # Product requirements documents -│ ├── plans/ # Implementation plans -│ │ ├── todo/ # Planned but not started -│ │ ├── in-progress/ # Currently being worked on -│ │ └── completed/ # Finished and verified +│ ├── work/ # Durable work items +│ │ └── <category>/<slug>/ +│ │ ├── index.md # Required entrypoint +│ │ ├── plan.md # Optional implementation plan +│ │ └── progress.md # Optional implementation log +│ ├── research/ # Reusable cross-work research notes +│ ├── references/ # External repos or docs checkouts (gitignored) +│ ├── scripts/ # dot-agents helper scripts │ └── skills/ # Agent skills -│ ├── adapt/ # Project analysis and AGENTS.md setup -│ ├── ralph/ # Autonomous implementation loops -│ ├── research/ # Deep research workflow -│ └── tmux/ # Background process management +│ ├── adapt/ +│ ├── agent-work/ +│ ├── feature-planning/ +│ ├── research/ +│ └── tmux/ └── src/ # Source code ``` ## Using Skills | Command | Effect | -|---------|--------| -| `Run adapt` | Analyze project and fill in AGENTS.md sections | -| `Research [topic]` | Deep investigation, saves to `.agents/research/` | -| `Run ralph on [plan.md]` | Autonomous execution of plan tasks | +| --- | --- | +| `Run adapt` | Analyze project and fill in `AGENTS.md` sections | +| `Create a new work item for ...` | Create durable `.agents/work/` context | +| `Research [topic]` | Investigate and save work-local or reusable findings | +| `Create a plan for ...` | Produce implementation-ready `plan.md` tasks | +| `Write a handoff prompt for ...` | Produce a paste-ready prompt for a new implementation thread | -Skills are loaded via natural language. See each skill's SKILL.md in `.agents/skills/` for details. +Skills are loaded via natural language. See each skill's `SKILL.md` in `.agents/skills/` for details. -## Plan Management +## Work Items -Plans in `.agents/plans/` follow this workflow: +Work items live at: -| Status | Location | -|--------|----------| -| **TODO** | `plans/todo/` | -| **IN-PROGRESS** | `plans/in-progress/` | -| **COMPLETED** | `plans/completed/` | +```text +.agents/work/<category>/<slug>/ +``` + +Every work item has `index.md` with: -**Completing plans:** When moving a plan to `completed/`, also move its corresponding `.progress.md` file if one exists. +```markdown +Status: researching | planned | in-progress | blocked | completed +Category: feature | bugfix | tech-debt | docs | tooling | research | other +Updated: YYYY-MM-DD +``` -**Archive command:** When asked to "archive completed plans", delete each plan from `completed/` with its own commit. Git history preserves them. +Use optional files only when useful: -### Writing Ralph-Ready Plans +- `research.md` - work-specific investigation notes +- `prd.md` - requirements when alignment is needed +- `plan.md` - implementation-ready task checklist +- `progress.md` - implementation log, verification, blockers, and next action +- `decisions/` - durable decision records + +Do not create empty support folders by default. + +### Task Format ```markdown - [ ] **Task N: Short descriptive title** - Scope: `path/to/affected/files` or module name - - Depends on: Task M (or "none") + - Depends on: Task M or `none` - Acceptance: - Specific, verifiable criterion 1 - Specific, verifiable criterion 2 - Notes: Optional implementation hints ``` -**Task markers:** - -| Marker | Meaning | -|--------|---------| -| `- [ ]` | Not started | -| `- [x]` | Completed | -| `- [ ] (blocked)` | Blocked, needs intervention | -| `- [ ] (manual-verify)` | Requires manual verification | - ## Commands ```bash @@ -112,17 +119,17 @@ git push ### Commit Guidelines -- Write clear, descriptive commit messages -- Reference plan numbers in commits (e.g., "Plan 001: Initial setup") -- Commit after each logical step +- Write clear, descriptive commit messages. +- Commit after each logical step. +- Do not push directly to the default branch unless project policy allows it. ## Maintenance After making changes: -1. **Update AGENTS.md** - Keep project structure and commands current -2. **Update README.md** - Reflect user-facing changes -3. **Update plan status** - Move completed plans to `completed/` +1. **Update AGENTS.md** - Keep project commands and conventions current. +2. **Update work items** - Keep `index.md`, `plan.md`, and `progress.md` in sync with implementation state. +3. **Update docs** - Reflect user-facing behavior changes. ## Conventions diff --git a/CHANGELOG.md b/CHANGELOG.md index 09b67b1..293bd1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,29 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +## [0.3.0] - 2026-06-22 + +### Changed + +- **BREAKING:** Replaced the Ralph-centered `.agents/plans/` / `.agents/prds/` workflow with durable work items under `.agents/work/<category>/<slug>/`. +- **BREAKING:** Fresh installs now ship `adapt`, `agent-work`, `feature-planning`, `research`, and `tmux` as core skills. +- Research guidance now distinguishes work-local `research.md` from reusable `.agents/research/` notes. +- Documentation, quickstart, and landing page now describe prompt-based implementation handoffs instead of autonomous runner execution. +- `--diff` now exits non-zero for any pending sync change, including missing files, retired skills, retired guidance, and `.gitignore` updates. + +### Removed + +- **BREAKING:** Removed the `ralph` skill from core installs. Sync backs up and removes retired upstream `ralph` skill directories. +- Fresh installs no longer create legacy `.agents/plans/` or `.agents/prds/` directories. +- Sync backs up and removes retired legacy guidance/templates such as `.agents/prds/AGENTS.md` and old plan/PRD templates. + +### Added + +- Work-item guidance at `.agents/work/AGENTS.md`. +- `agent-work` skill with templates and scripts for creating and listing work items. +- `feature-planning` skill for PRDs, implementation-ready plans, plan refinement, and paste-ready new-thread prompts. +- Legacy migration guide for moving old plans into `.agents/work/`. + ## [0.2.0] - 2026-06-22 ### Added @@ -64,7 +87,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Installer skip logic now correctly includes plans/TEMPLATE.md - Postfix increment operators causing script exit on bash 5.3+ with `set -e` ([#1](https://github.com/colmarius/dot-agents/issues/1)) -[Unreleased]: https://github.com/colmarius/dot-agents/compare/v0.2.0...HEAD +[Unreleased]: https://github.com/colmarius/dot-agents/compare/v0.3.0...HEAD +[0.3.0]: https://github.com/colmarius/dot-agents/compare/v0.2.0...v0.3.0 [0.2.0]: https://github.com/colmarius/dot-agents/compare/v0.1.1...v0.2.0 [0.1.1]: https://github.com/colmarius/dot-agents/compare/v0.1.0...v0.1.1 [0.1.0]: https://github.com/colmarius/dot-agents/releases/tag/v0.1.0 diff --git a/QUICKSTART.md b/QUICKSTART.md index 7d2e799..833d193 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -17,106 +17,110 @@ Get productive with dot-agents in 5 minutes. ## 1. Install -**cmd:** ```bash curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash ``` ### What Gets Installed -After running the install command, you'll have: - -``` +```text your-project/ -├── AGENTS.md # Template - customize for your project +├── AGENTS.md └── .agents/ - ├── plans/ - │ ├── todo/ - │ ├── in-progress/ - │ └── completed/ - ├── prds/ - │ └── TEMPLATE.md + ├── work/ + │ └── AGENTS.md ├── research/ - ├── reference/ # gitignored - for external repos + ├── references/ ├── scripts/ │ └── sync.sh └── skills/ ├── adapt/ - ├── ralph/ + ├── agent-work/ + ├── feature-planning/ ├── research/ └── tmux/ ``` -If the project already has a `.claude/` directory, dot-agents also links skills into `.claude/skills/` so Claude Code can discover them as project skills and invoke them with slash commands such as `/adapt`. +If the project already has a `.claude/` directory, dot-agents also links skills into `.claude/skills/` so Claude Code can discover them as project skills. ### Verify Installation -**cmd:** ```bash ls -la .agents/ cat AGENTS.md | head -20 ``` -For Claude Code projects, you can also check: +## 2. Adapt `AGENTS.md` -**cmd:** -```bash -ls -la .claude/skills/ -``` +Ask your agent: -## 2. Adapt AGENTS.md - -**prompt:** ```text Run adapt ``` -This analyzes your project and fills in the AGENTS.md template with your tech stack, commands, and conventions. You can also customize it manually. +This analyzes your project and fills in the `AGENTS.md` template with tech stack, commands, and conventions. You can also customize it manually. -## 3. Research +## 3. Create a Work Item -Before building, research the problem space: +Ask your agent: -**prompt:** ```text -Research authentication patterns for Express.js APIs +Create a new work item for user authentication. ``` -Findings are saved to `.agents/research/` for reference. +Or run the helper directly: -## 4. Create PRD +```bash +.agents/skills/agent-work/scripts/new-work.sh \ + --category feature \ + --slug user-authentication \ + --title "User authentication" +``` -Turn research into a product requirements document: +The work item starts at: -**prompt:** ```text -Create a PRD for user authentication based on .agents/research/authentication-patterns.md +.agents/work/feature/user-authentication/index.md ``` -PRDs go to `.agents/prds/` with acceptance criteria. +## 4. Research and Plan + +Ask for work-local research: -## 5. Generate Plan +```text +Research authentication patterns for this work item. +``` -Convert PRD into implementation tasks: +Then ask for a plan: -**prompt:** ```text -Create a plan from .agents/prds/user-authentication.md +Create an implementation-ready plan in .agents/work/feature/user-authentication/plan.md. ``` -Plans use Ralph-ready task format with scope, dependencies, and acceptance criteria. +Plans use tasks with scope, dependencies, and acceptance criteria. -## 6. Execute with Ralph +## 5. Generate a Handoff Prompt -Run autonomous implementation: +When the plan is ready, ask: -**prompt:** ```text -Run ralph on .agents/plans/in-progress/user-authentication.md +Review .agents/work/feature/user-authentication and write a paste-ready handoff prompt for the next implementation thread. ``` -Ralph iterates through tasks, commits after each, and pauses for review. +Paste the generated prompt into a fresh agent thread. The new thread should read `index.md`, implement the requested slice, update `plan.md` checkboxes, append to `progress.md`, refresh `index.md`, and report verification results. + +## 6. Continue Later + +List active work: + +```bash +.agents/skills/agent-work/scripts/list-work.sh +``` + +Then ask for a continuation prompt from the next action in the work item. + +## Legacy Plans and PRDs ---- +Older dot-agents installs used `.agents/plans/` and `.agents/prds/`. Legacy plan and PRD documents are preserved on sync, while retired Ralph guidance/templates are backed up and removed. Migrate one plan at a time into `.agents/work/<category>/<slug>/` when you need to resume it. **Next:** [Concepts](./docs/concepts.md) · [Skills Reference](./docs/skills.md) · [dot-agents.dev](https://dot-agents.dev) diff --git a/README.md b/README.md index f208795..9dd5ebf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # dot-agents -AI-ready `.agents/` workspace for any project—plans, PRDs, research, and skills for agent-assisted workflows. +AI-ready `.agents/` workspace for any project — durable work items, reusable research, planning skills, and paste-ready handoff prompts for agent-assisted development across threads. ## Install @@ -11,46 +11,50 @@ curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.s Pin a version: ```bash -curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.2.0 +curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.3.0 ``` ## Documentation -- **[Quickstart](./QUICKSTART.md)** — Step-by-step guide from install to autonomous execution -- **[Full Docs](./docs/README.md)** — Concepts, skills reference +- **[Quickstart](./QUICKSTART.md)** — Install, create a work item, and generate a handoff prompt +- **[Full Docs](./docs/README.md)** — Concepts, skills, and migration notes - **[Website](https://dot-agents.dev)** — Landing page (source: [site/](./site/)) ## Agent Support -dot-agents works with any AI coding agent that reads markdown instructions. When a project already has a `.claude/` directory, install/sync also links dot-agents skills into `.claude/skills/` so Claude Code can discover them as project skills. +dot-agents works with any AI coding agent that reads Markdown instructions. When a project already has a `.claude/` directory, install/sync also links dot-agents skills into `.claude/skills/` so Claude Code can discover them as project skills. ## Next Steps -Then: +After install: -1. Customize `AGENTS.md` for your project — run `adapt` to auto-fill or edit manually -2. Sync updates later: `.agents/scripts/sync.sh` +1. Customize `AGENTS.md` for your project — run `adapt` to auto-fill or edit manually. +2. Create a work item under `.agents/work/<category>/<slug>/`. +3. Ask for research, a plan, or a paste-ready handoff prompt. +4. Sync updates later with `.agents/scripts/sync.sh`. ## Sync Behavior Re-running `install.sh` updates dot-agents from upstream while preserving your work: | What | Behavior | -|------|----------| -| Skills, scripts | Updated from upstream | -| AGENTS.md | Skipped (your customizations preserved) | -| PRDs, plans | Skipped (your content preserved) | -| Research | Skipped (your content preserved) | +| --- | --- | +| Skills, scripts, `.agents/work/AGENTS.md` | Updated from upstream | +| Retired upstream skills and legacy guidance/templates | Backed up and removed on sync | +| `AGENTS.md` | Skipped after fresh install | +| Work items | Preserved under `.agents/work/<category>/<slug>/` | +| Reusable research | Preserved under `.agents/research/` | +| Legacy plan/PRD documents | Preserved if present | The installer copies `AGENTS.template.md` → `AGENTS.md` on fresh install only. **Sync options:** | Flag | Behavior | -|------|----------| -| (default) | Overwrite conflicts with backup | +| --- | --- | +| default | Overwrite upstream-owned conflicts with backup during sync | | `--diff` | Preview changes without modifying files | -| `--write-conflicts` | Create `.dot-agents.new` files for manual review | +| `--write-conflicts` | Create `.dot-agents.md` or `.dot-agents.new` files for manual review | | `--dry-run` | Show what would happen without changes | ## Versioning diff --git a/VERSION b/VERSION index 0ea3a94..0d91a54 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 +0.3.0 diff --git a/docs/README.md b/docs/README.md index 7b9a7dd..72be303 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,6 +9,7 @@ - [Workflow Overview](./concepts.md#workflow) - [Glossary](./concepts.md#glossary) +- [v0.3 Migration](./migration-v1.md) ## Reference diff --git a/docs/concepts.md b/docs/concepts.md index 5663891..5ec3f85 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -3,21 +3,57 @@ ## Workflow ```text -Research → PRD → Plan → Execute +Work Item → Research/PRD as needed → Plan → Handoff Prompt → Implement → Record Progress ``` -1. **Research:** Investigate problem space, save findings to `.agents/research/` -2. **PRD:** Define requirements and acceptance criteria in `.agents/prds/` -3. **Plan:** Break PRD into executable tasks with Ralph-ready format -4. **Execute:** Ralph runs tasks autonomously, commits after each +1. **Work Item:** Create `.agents/work/<category>/<slug>/index.md` as the durable context entrypoint. +2. **Research/PRD:** Save task-specific research and requirements beside the work item. Use `.agents/research/` only for reusable notes. +3. **Plan:** Break work into implementation-ready tasks in `plan.md` with scope, dependencies, and acceptance criteria. +4. **Handoff Prompt:** Ask an agent to write a paste-ready prompt for a fresh implementation thread. +5. **Implement:** Paste the prompt into the new thread and let that agent do the scoped work. +6. **Record Progress:** Update `progress.md`, task checkboxes, and `index.md` so future threads can resume. + +## Work Item Shape + +```text +.agents/work/<category>/<slug>/ +├── index.md # required landing page +├── research.md # optional, work-specific findings +├── prd.md # optional requirements +├── plan.md # optional implementation-ready tasks +├── progress.md # optional implementation log +└── decisions/ # optional durable decisions +``` + +Create optional files only when they hold useful context. The required `index.md` should stay short and point to the current next action. + +## Handoff Prompts + +A handoff prompt is a paste-ready prompt for a new agent thread. It should name: + +- Work item path and files to read first. +- Goal, current state, and exact implementation slice. +- Scope limits and non-goals. +- Required updates to `plan.md`, `progress.md`, and `index.md`. +- Verification commands and stop conditions. +- Expected final response shape. + +dot-agents does not assume a specific execution runtime. The work item is the continuity layer. + +## Legacy Content + +Older dot-agents installs used `.agents/plans/` and `.agents/prds/`. v0.3.0 preserves legacy plan and PRD documents as user content but no longer creates those paths on fresh install. See [migration guide](./migration-v1.md) for how to move active work into `.agents/work/`. ## Glossary | Term | Definition | -|------|------------| -| adapt | Skill that analyzes your project and fills in AGENTS.md | -| Ralph | Autonomous execution skill that works through plans task-by-task | -| PRD | Product Requirements Document defining what to build | -| Plan | List of tasks in Ralph-ready format with scope, dependencies, acceptance criteria | -| Skills | Specialized agent instructions loaded via natural language | -| sync | Script that updates dot-agents from upstream while preserving your customizations | +| --- | --- | +| adapt | Skill that analyzes your project and fills in `AGENTS.md` | +| work item | Durable folder under `.agents/work/<category>/<slug>/` for one multi-session effort | +| task | Checkbox entry inside `plan.md` | +| PRD | Optional product or requirements document defining what to build | +| plan | Implementation-ready task list with scope, dependencies, and acceptance criteria | +| handoff prompt | Paste-ready prompt for a fresh implementation thread | +| progress log | `progress.md`, the implementation log for changes, verification, blockers, and next action | +| skills | Specialized agent instructions loaded via natural language | +| sync | Script that updates dot-agents from upstream while preserving user work | diff --git a/docs/migration-v1.md b/docs/migration-v1.md new file mode 100644 index 0000000..1e4743e --- /dev/null +++ b/docs/migration-v1.md @@ -0,0 +1,62 @@ +# Migration Guide: Work Items and Handoff Prompts + +dot-agents v0.3.0 replaces the old `.agents/plans/` / `.agents/prds/` / Ralph workflow with durable work items and paste-ready handoff prompts. + +## What Changed + +Fresh installs now create: + +```text +.agents/work/ +.agents/research/ +.agents/references/ +.agents/skills/{adapt,agent-work,feature-planning,research,tmux}/ +``` + +Fresh installs no longer create: + +```text +.agents/plans/ +.agents/prds/ +.agents/skills/ralph/ +``` + +Existing legacy plan and PRD documents, `.agents/research/`, and legacy `.agents/reference/` content are preserved on sync. Retired Ralph support is backed up and removed so stale guidance does not conflict with the new workflow. This includes `.agents/skills/ralph`, `.agents/plans/AGENTS.md`, `.agents/prds/AGENTS.md`, and old plan/PRD templates. Any `.agents/skills/ralph` directory is treated as retired upstream content, even if it was locally edited; restore it from `.agents/.dot-agents-backup/` and rename it only if you intentionally want to keep a custom skill with that behavior. + +v0.3.0 does not ship a Ralph compatibility layer, alias, or stub skill. Pin to `v0.2.0` only if you need the old runner workflow for an existing project. + +The preferred external-reference path is now `.agents/references/`. Existing `.agents/reference/` checkouts remain ignored so large local clones are not accidentally committed. Rename them manually when convenient. + +## Migrate One Legacy Plan + +Ask your agent: + +```text +Migrate legacy plan .agents/plans/in-progress/<plan>.md into a new work item. + +Create .agents/work/<category>/<slug>/index.md. +Copy the old plan to plan.md, preserving task checkboxes. +If there is a matching .progress.md file, copy it to progress.md. +If the plan links a PRD under .agents/prds/, copy or summarize it into prd.md. +Update index.md with Status, Artifacts, Next Action, and Open Questions. +Do not delete the legacy files unless I explicitly ask. +``` + +## Status Mapping + +| Legacy location | New `index.md` status | +| --- | --- | +| `.agents/plans/todo/` | `planned` | +| `.agents/plans/in-progress/` | `in-progress` | +| `.agents/plans/completed/` | `completed` | +| PRD only | `researching` or `planned`, depending whether a plan exists | + +## After Migration + +Ask for a handoff prompt: + +```text +Review .agents/work/<category>/<slug> and write a paste-ready handoff prompt for the next implementation thread. +``` + +Paste the generated prompt into a fresh thread. The implementation thread should update `plan.md`, `progress.md`, and `index.md` as it works. diff --git a/docs/skills.md b/docs/skills.md index 323a883..dd2a8d7 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -1,56 +1,71 @@ # Skills -Skills are specialized instructions that agents load for specific workflows. When you invoke a skill, the agent receives detailed guidance for that particular task type. +Skills are specialized instructions that agents load for specific workflows. dot-agents keeps them under `.agents/skills/` and, for Claude Code projects, links them into `.claude/skills/` when `.claude/` already exists. ## Available Skills | Skill | Trigger | Purpose | -|-------|---------|---------| -| [adapt](#adapt) | `Run adapt` | Analyze project, fill in AGENTS.md | -| [ralph](#ralph) | `Run ralph on [plan]` | Autonomous task execution | -| [research](#research) | `Research [topic]` | Deep investigation workflow | -| [tmux](#tmux) | (auto-loaded) | Background process management | +| --- | --- | --- | +| [adapt](#adapt) | `Run adapt` | Analyze project, fill in `AGENTS.md` | +| [agent-work](#agent-work) | `Create a work item` | Create and maintain `.agents/work/` context | +| [feature-planning](#feature-planning) | `Create a plan`, `write a handoff prompt` | Turn context into plans and new-thread prompts | +| [research](#research) | `Research [topic]` | Investigate and save work-local or reusable findings | +| [tmux](#tmux) | `tmux`, `background process` | Manage background processes | ## adapt -Analyzes your project and fills in AGENTS.md with: +Analyzes your project and fills in `AGENTS.md` with: - Project overview and tech stack - Build/test/lint commands - Code conventions - Project structure +- dot-agents work-item workflow guidance **Invoke:** `Run adapt` **Details:** [.agents/skills/adapt/SKILL.md](../.agents/skills/adapt/SKILL.md) -## ralph +## agent-work -Executes plans autonomously, iterating through tasks: +Creates and curates durable work item folders: -- Reads plan from `.agents/plans/` -- Completes tasks one by one -- Commits after each task -- Hands off to new thread when context fills +```text +.agents/work/<category>/<slug>/index.md +``` + +Use it to create work items, list active work, place artifacts deliberately, and migrate legacy plans when requested. + +**Invoke:** `Create a new work item for user authentication` + +**Details:** [.agents/skills/agent-work/SKILL.md](../.agents/skills/agent-work/SKILL.md) + +## feature-planning -**Invoke:** `Run ralph on .agents/plans/in-progress/my-plan.md` +Turns research and requirements into implementation-ready plans and paste-ready handoff prompts. -**Options:** +Use it to: -- Start from specific task: `Continue ralph from Task 5 on [plan]` -- Default max tasks per session: 5 +- Create or refine `prd.md` +- Create or refine `plan.md` +- Validate stale assumptions before implementation +- Generate a new-thread handoff prompt +- Stress-test a plan when explicitly asked -**Details:** [.agents/skills/ralph/SKILL.md](../.agents/skills/ralph/SKILL.md) +**Invoke:** `Write a handoff prompt for .agents/work/feature/user-authentication` + +**Details:** [.agents/skills/feature-planning/SKILL.md](../.agents/skills/feature-planning/SKILL.md) ## research -Deep investigation workflow: +Investigates technical questions using available local, web, and repository evidence. + +Research is saved: -- Web search and documentation reading -- Explores libraries, APIs, patterns -- Saves findings to `.agents/research/` +- Work-locally at `.agents/work/<category>/<slug>/research.md` when it supports one work item +- Reusably at `.agents/research/<topic>.md` when it should guide future unrelated work -**Invoke:** `Research [topic]` +**Invoke:** `Research authentication patterns for this work item` **Details:** [.agents/skills/research/SKILL.md](../.agents/skills/research/SKILL.md) @@ -58,11 +73,11 @@ Deep investigation workflow: Background process management: -- Spawns long-running processes (servers, watchers) +- Spawns long-running processes such as servers or watchers - Captures output for review -- Auto-loaded by other skills when needed +- Sends interrupts or kills background windows when needed -**Note:** This skill is typically loaded automatically when background processes are required. +**Invoke:** `Use tmux to run the dev server in the background` **Details:** [.agents/skills/tmux/SKILL.md](../.agents/skills/tmux/SKILL.md) @@ -70,31 +85,29 @@ Background process management: Create a new skill by adding a directory under `.agents/skills/`: -``` +```text .agents/skills/my-skill/ └── SKILL.md ``` -### SKILL.md Format +### `SKILL.md` Format ```markdown --- name: my-skill -description: Brief description for skill discovery +description: "Brief description. Use when relevant context applies. Triggers on: keyword1, keyword2." --- # My Skill -Instructions for the agent when this skill is loaded... +Instructions for the agent when this skill is loaded. ``` -The `name` and `description` in the frontmatter are used for skill discovery. The agent matches user requests against skill descriptions to determine which skill to load. - -**Invocation:** Skills are loaded via natural language matching. If your description mentions "deploy" or "deployment", saying "help me deploy" will load your skill. +The `name` and `description` fields are used for skill discovery. Keep descriptions quoted, concise, and trigger-rich. ### Preserving Custom Skills -Custom skills in `.agents/skills/` are preserved during `sync.sh` updates. Only upstream skills (adapt, ralph, research, tmux) are updated—your custom skills remain untouched. +Custom skills in `.agents/skills/` are preserved during `sync.sh` updates. Only upstream core skills are updated or retired by dot-agents. ## Claude Code Project Skill Discovery @@ -102,7 +115,7 @@ Claude Code discovers project skills in `.claude/skills/<skill>/SKILL.md`. dot-a ```text .claude/skills/adapt -> ../../.agents/skills/adapt -.claude/skills/ralph -> ../../.agents/skills/ralph +.claude/skills/agent-work -> ../../.agents/skills/agent-work ``` -Directory symlinks expose the whole skill, including optional supporting files like `references/` and `scripts/`. The installer skips user-owned Claude Code skills and only removes dot-agents-managed symlinks during uninstall. +Directory symlinks expose the whole skill, including optional supporting files like `assets/`, `references/`, and `scripts/`. The installer skips user-owned Claude Code skills and only removes dot-agents-managed symlinks during uninstall or retired-skill cleanup. diff --git a/install.sh b/install.sh index 7698e5f..a59782b 100755 --- a/install.sh +++ b/install.sh @@ -38,7 +38,7 @@ Options: --dry-run Show what would happen without making changes --diff Show unified diff for conflicts instead of overwriting --force Overwrite conflicts (creates backup first, default on sync) - --write-conflicts Create .dot-agents.new files for conflicts + --write-conflicts Create .dot-agents.md/.dot-agents.new files for conflicts --ref <ref> Git ref to install (branch, tag, commit). Default: main --yes Skip confirmation prompts --uninstall Remove dot-agents @@ -51,7 +51,7 @@ Examples: curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash # Install specific version - curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.2.0 + curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.3.0 # Preview changes first curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --dry-run @@ -190,6 +190,7 @@ do_uninstall() { installed_count=0 skipped_count=0 conflict_count=0 +pending_change_count=0 backup_count=0 BACKUP_DIR="" CLAUDE_SKILL_SYMLINKS_REMOVED=0 @@ -233,7 +234,7 @@ create_backup_dir() { if [[ -z "$BACKUP_DIR" ]]; then local timestamp timestamp="$(date -u +%Y-%m-%dT%H%M%SZ)" - BACKUP_DIR=".dot-agents-backup/${timestamp}" + BACKUP_DIR=".agents/.dot-agents-backup/${timestamp}" if [[ "$DRY_RUN" != "true" ]]; then mkdir -p "$BACKUP_DIR" fi @@ -257,6 +258,27 @@ backup_file() { backup_count=$((backup_count + 1)) } +backup_item() { + local path="$1" + create_backup_dir + local backup_path="${BACKUP_DIR}/${path}" + local backup_dir + backup_dir="$(dirname "$backup_path")" + + if [[ "$DRY_RUN" == "true" ]]; then + log_info " ${BLUE}[BACKUP]${NC} $path → $backup_path" + else + mkdir -p "$backup_dir" + if [[ -d "$path" && ! -L "$path" ]]; then + cp -Rp "$path" "$backup_path" + else + cp -p "$path" "$backup_path" + fi + log_info " ${BLUE}[BACKUP]${NC} $path" + fi + backup_count=$((backup_count + 1)) +} + detect_stack() { local detected="" @@ -419,8 +441,10 @@ format_version_string() { fi } -# Core skills that come from upstream (sample-skill is for testing) -CORE_SKILLS="adapt ralph research tmux sample-skill" +# Core skills that come from upstream +CORE_SKILLS="adapt agent-work feature-planning research tmux" +RETIRED_CORE_SKILLS="ralph" +RETIRED_LEGACY_GUIDANCE_FILES=".agents/plans/AGENTS.md .agents/prds/AGENTS.md .agents/plans/TEMPLATE.md .agents/prds/TEMPLATE.md" detect_custom_skills() { local skills_dir=".agents/skills" @@ -437,7 +461,7 @@ detect_custom_skills() { # Skip if it's a core skill local is_core=false - for core in $CORE_SKILLS; do + for core in $CORE_SKILLS $RETIRED_CORE_SKILLS; do if [[ "$skill_name" == "$core" ]]; then is_core=true break @@ -467,6 +491,53 @@ report_custom_skills() { fi } +cleanup_retired_core_skills() { + local retired skill_dir + + [[ -d ".agents/skills" ]] || return 0 + + for retired in $RETIRED_CORE_SKILLS; do + skill_dir=".agents/skills/$retired" + [[ -e "$skill_dir" || -L "$skill_dir" ]] || continue + + if [[ "$DIFF_ONLY" == "true" ]]; then + log_info " ${RED}[REMOVE]${NC} $skill_dir (retired core skill, preview only)" + pending_change_count=$((pending_change_count + 1)) + continue + fi + + backup_item "$skill_dir" + if [[ "$DRY_RUN" == "true" ]]; then + log_info " ${RED}[REMOVE]${NC} $skill_dir (retired core skill)" + else + rm -rf "$skill_dir" + log_info " ${RED}[REMOVE]${NC} $skill_dir (retired core skill)" + fi + done +} + +cleanup_retired_legacy_guidance() { + local path + + for path in $RETIRED_LEGACY_GUIDANCE_FILES; do + [[ -e "$path" || -L "$path" ]] || continue + + if [[ "$DIFF_ONLY" == "true" ]]; then + log_info " ${RED}[REMOVE]${NC} $path (retired legacy guidance, preview only)" + pending_change_count=$((pending_change_count + 1)) + continue + fi + + backup_item "$path" + if [[ "$DRY_RUN" == "true" ]]; then + log_info " ${RED}[REMOVE]${NC} $path (retired legacy guidance)" + else + rm -rf "$path" + log_info " ${RED}[REMOVE]${NC} $path (retired legacy guidance)" + fi + done +} + cleanup_stale_claude_code_skill_symlinks() { local agents_skills_dir="$1" local claude_skills_dir="$2" @@ -570,13 +641,19 @@ setup_claude_code_integration() { ensure_gitignore_entry() { local gitignore_file=".agents/.gitignore" - local backup_entry="../.dot-agents-backup/" + local backup_entry=".dot-agents-backup/" - if [[ "$DRY_RUN" == "true" ]]; then + if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then if [[ ! -f "$gitignore_file" ]]; then log_info " ${GREEN}[CREATE]${NC} $gitignore_file" + if [[ "$DIFF_ONLY" == "true" ]]; then + pending_change_count=$((pending_change_count + 1)) + fi elif ! grep -qxF "$backup_entry" "$gitignore_file" 2>/dev/null; then log_info " ${GREEN}[UPDATE]${NC} $gitignore_file (add backup entry)" + if [[ "$DIFF_ONLY" == "true" ]]; then + pending_change_count=$((pending_change_count + 1)) + fi fi return 0 fi @@ -599,6 +676,13 @@ install_file() { dest_dir="$(dirname "$dest")" if [[ ! -e "$dest" ]]; then + if [[ "$DIFF_ONLY" == "true" ]]; then + log_install "$dest (would install)" + installed_count=$((installed_count + 1)) + pending_change_count=$((pending_change_count + 1)) + return 0 + fi + if [[ "$DRY_RUN" == "true" ]]; then log_install "$dest" else @@ -654,6 +738,7 @@ install_file() { diff -u "$dest" "$src" 2>/dev/null || true echo "" conflict_count=$((conflict_count + 1)) + pending_change_count=$((pending_change_count + 1)) return 0 fi @@ -682,13 +767,13 @@ process_directory() { local rel_path="${file#$src_dir/}" local dest_path="${dest_dir}/${rel_path}" - # Skip *.md files in user content directories (research, plans, prds) - if [[ "$rel_path" == research/*.md || "$rel_path" == plans/*.md || "$rel_path" == plans/**/*.md || "$rel_path" == prds/*.md ]]; then + # Skip user content directories. Fresh installs get guidance files, not sample work. + if [[ "$rel_path" == research/*.md || "$rel_path" == research/**/*.md || "$rel_path" == work/*/*/* || "$rel_path" == plans/* || "$rel_path" == prds/* ]]; then continue fi - # Skip metadata file in diff mode (it's auto-generated and will always differ) - if [[ "$DIFF_ONLY" == "true" ]] && [[ "$rel_path" == ".dot-agents.json" ]]; then + # Metadata is generated locally by write_metadata. + if [[ "$rel_path" == ".dot-agents.json" ]]; then continue fi @@ -763,6 +848,11 @@ main() { process_directory "${extracted_dir}/.agents" "./.agents" fi + if [[ "$IS_FRESH_INSTALL" != "true" ]]; then + cleanup_retired_core_skills + cleanup_retired_legacy_guidance + fi + # Ensure .agents/.gitignore includes backup directory ensure_gitignore_entry @@ -781,6 +871,9 @@ main() { log_info " Installed: ${installed_count}" log_info " Skipped: ${skipped_count}" log_info " Conflicts: ${conflict_count}" + if [[ "$DIFF_ONLY" == "true" ]]; then + log_info " Pending changes: ${pending_change_count}" + fi if [[ $backup_count -gt 0 ]]; then log_info " Backed up: ${backup_count}" @@ -802,8 +895,8 @@ main() { fi fi - # In diff mode, exit 1 if conflicts exist - if [[ "$DIFF_ONLY" == "true" ]] && [[ $conflict_count -gt 0 ]]; then + # In diff mode, exit 1 if any change would be applied. + if [[ "$DIFF_ONLY" == "true" ]] && [[ $pending_change_count -gt 0 ]]; then return 1 fi diff --git a/scripts/build-test-fixture.sh b/scripts/build-test-fixture.sh index 0dc98e8..35c74e0 100755 --- a/scripts/build-test-fixture.sh +++ b/scripts/build-test-fixture.sh @@ -32,29 +32,24 @@ if [[ -d "$REPO_ROOT/.agents" ]]; then echo " Added: .agents/" fi -# Add sample files for testing user content preservation +# Add sample files for testing user content preservation and skip rules mkdir -p "$ARCHIVE_DIR/.agents/research" mkdir -p "$ARCHIVE_DIR/.agents/plans/todo" mkdir -p "$ARCHIVE_DIR/.agents/prds" +mkdir -p "$ARCHIVE_DIR/.agents/work/feature/example-work" echo "# Example research" > "$ARCHIVE_DIR/.agents/research/example.md" echo "# Example plan" > "$ARCHIVE_DIR/.agents/plans/todo/plan-001.md" echo "# Example PRD" > "$ARCHIVE_DIR/.agents/prds/feature.md" -echo " Added: sample user content files for testing" - -# Add a sample skill for testing -mkdir -p "$ARCHIVE_DIR/.agents/skills/sample-skill" -cat > "$ARCHIVE_DIR/.agents/skills/sample-skill/SKILL.md" << 'EOF' ---- -name: sample-skill -description: A sample skill for testing ---- - -# Sample Skill - -This is a sample skill used for testing the installation process. +echo "# Example work item" > "$ARCHIVE_DIR/.agents/work/feature/example-work/index.md" +cat > "$ARCHIVE_DIR/.agents/.dot-agents.json" <<'EOF' +{ + "upstream": "https://github.com/example/bogus-dot-agents", + "ref": "bogus-archive-metadata", + "installedAt": "2000-01-01T00:00:00Z" +} EOF -echo " Added: sample-skill for testing" +echo " Added: sample user content files for testing" # Create the archive tar -czf "$FIXTURES_DIR/sample-archive.tar.gz" -C "$TMP_DIR" dot-agents-main diff --git a/scripts/lint.sh b/scripts/lint.sh index afcc23d..f0ef47f 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -13,6 +13,8 @@ cd "$ROOT_DIR" SCRIPTS=( install.sh .agents/scripts/sync.sh + .agents/skills/agent-work/scripts/list-work.sh + .agents/skills/agent-work/scripts/new-work.sh scripts/lint.sh scripts/test.sh test/mocks/curl diff --git a/site/index.html b/site/index.html index f93d6ae..9a0fd7b 100644 --- a/site/index.html +++ b/site/index.html @@ -4,19 +4,19 @@ <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>dot-agents — AI-ready agent workspace - + - + - + @@ -41,7 +41,7 @@

Ship faster with structured AI workflows

-

One command to set up PRDs, plans, and an execution loop—so you can start building, not just planning.

+

One command to set up durable work items, research, plans, and handoff prompts—so context survives across agent threads.

@@ -61,7 +61,14 @@

Ship faster with structured AI workflows

Then point your agent at a real problem and iterate.

Pin a version - curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.2.0 + curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.3.0 +
+

Current release: v0.3.0. Older releases are available on GitHub.

+
+ Older releases +
@@ -71,10 +78,10 @@

What you get

your-project/
 ├── AGENTS.md           # Customize for your project
 └── .agents/
-    ├── plans/          # todo → in-progress → completed
-    ├── prds/           # Product requirements
-    ├── research/       # Discoveries and context
-    └── skills/         # adapt, ralph, research, tmux
+ ├── work/ # durable work items + ├── research/ # reusable findings + ├── references/ # local reference repos + └── skills/ # adapt, agent-work, planning, research, tmux

Using Claude Code? If .claude/ already exists, install/sync links these skills into .claude/skills/ for project skill discovery.

@@ -84,22 +91,22 @@

What you get

Instant Setup

-

One command creates .agents/ with plans, PRDs, skills, and research directories.

+

One command creates .agents/ with work-item guidance, reusable research, references, and skills.

📋
-

Structured Plans

-

Task format with dependencies, scopes, and acceptance criteria for autonomous execution.

+

Durable Work Items

+

Keep research, requirements, plans, progress, decisions, and next actions together.

🤖
-

Autonomous Execution (Ralph)

-

Multi-iteration execution with handoff between agent threads.

+

Handoff Prompts

+

Generate paste-ready prompts for fresh implementation threads with clear scope and verification.

🔬

Built-in Research

-

Save discoveries to .agents/research/ for persistent project knowledge.

+

Save work-local findings beside the task and reusable knowledge in .agents/research/.

@@ -110,16 +117,16 @@

The workflow

1
- Research - Deep dive into requirements and constraints + Work item + Create durable context under .agents/work/
2
- PRD - Define features and acceptance criteria + Research/PRD + Capture findings and requirements as needed
@@ -127,15 +134,15 @@

The workflow

3
Plan - Break down into executable tasks + Break work into implementation-ready tasks
4
- Execute - Ralph runs autonomously + Handoff + Paste a scoped prompt into a fresh thread
@@ -161,22 +168,22 @@

Get started in 5 steps

3
- Research - Research [topic] + Work item + Create a new work item for [feature]
4
- PRD - Create PRD for [feature] + Plan + Create/refine a plan for [work item]
5
- Execute - Run ralph on [plan] + Handoff + Write a handoff prompt for [work item]
diff --git a/test/fixtures/sample-archive.tar.gz b/test/fixtures/sample-archive.tar.gz index 1e737441c0ec5fabcb9fd79fc26e8d1ff2e68a54..1a74c49ad7cf72c8e897d0e12179ccf6842bfea3 100644 GIT binary patch literal 19286 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 literal 44358 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 diff --git a/test/integration/install.bats b/test/integration/install.bats index a681e64..2a6d456 100755 --- a/test/integration/install.bats +++ b/test/integration/install.bats @@ -55,6 +55,17 @@ teardown() { [ -f "AGENTS.md" ] [ -d ".agents" ] [ -d ".agents/skills" ] + [ -f ".agents/work/AGENTS.md" ] + [ -d ".agents/references" ] + [ -f ".agents/references/.gitkeep" ] + [ -f ".agents/skills/adapt/SKILL.md" ] + [ -f ".agents/skills/agent-work/SKILL.md" ] + [ -f ".agents/skills/feature-planning/SKILL.md" ] + [ -f ".agents/skills/research/SKILL.md" ] + [ -f ".agents/skills/tmux/SKILL.md" ] + [ ! -d ".agents/skills/ralph" ] + [ ! -d ".agents/plans" ] + [ ! -d ".agents/prds" ] } @test "fresh install creates .agents/.dot-agents.json with valid JSON" { @@ -68,6 +79,8 @@ teardown() { run cat ".agents/.dot-agents.json" assert_output --partial "upstream" assert_output --partial "installedAt" + refute_output --partial "bogus-archive-metadata" + refute_output --partial "example/bogus-dot-agents" } @test "identical files are skipped on re-install" { @@ -106,7 +119,7 @@ teardown() { bash "$INSTALL_SCRIPT" --yes # Modify a skill file (not AGENTS.md which is skipped on sync) - echo "# Modified skill" > .agents/skills/sample-skill/SKILL.md + echo "# Modified skill" > .agents/skills/research/SKILL.md # Force re-install run bash "$INSTALL_SCRIPT" --force --yes @@ -115,6 +128,8 @@ teardown() { # Should create backup directory run find . -type d -name ".dot-agents-backup*" assert_output --partial ".dot-agents-backup" + [ -d ".agents/.dot-agents-backup" ] + [ ! -d ".dot-agents-backup" ] } @test "--uninstall removes installed files" { @@ -189,25 +204,144 @@ teardown() { [ -d ".agents" ] } -@test "md files in research/plans/prds are not installed" { +@test "user content samples are not installed" { run bash "$INSTALL_SCRIPT" --yes assert_success # Skills should be installed - [ -f ".agents/skills/sample-skill/SKILL.md" ] + [ -f ".agents/skills/agent-work/SKILL.md" ] + [ -f ".agents/work/AGENTS.md" ] # User content directories should NOT have md files from upstream [ ! -f ".agents/research/example.md" ] + [ ! -f ".agents/work/feature/example-work/index.md" ] [ ! -f ".agents/plans/todo/plan-001.md" ] [ ! -f ".agents/prds/feature.md" ] + [ ! -d ".agents/plans" ] + [ ! -d ".agents/prds" ] } -@test "--write-conflicts creates .dot-agents.new files for conflicts" { +@test "agent-work helpers create and list work items" { + bash "$INSTALL_SCRIPT" --yes + + run .agents/skills/agent-work/scripts/new-work.sh \ + --category feature \ + --slug demo-work \ + --title "Demo work" \ + --status planned + assert_success + assert_output ".agents/work/feature/demo-work/index.md" + + [ -f ".agents/work/feature/demo-work/index.md" ] + [ ! -d ".agents/work/feature/demo-work/decisions" ] + + run .agents/skills/agent-work/scripts/list-work.sh --status planned + assert_success + assert_output --partial "Demo work" + assert_output --partial "planned" + + run .agents/skills/agent-work/scripts/list-work.sh --status blocked + assert_success + refute_output --partial "Demo work" +} + +@test "agent-work helper rejects invalid status" { + bash "$INSTALL_SCRIPT" --yes + + run .agents/skills/agent-work/scripts/new-work.sh \ + --category feature \ + --slug invalid-status \ + --title "Invalid status" \ + --status unknown + assert_failure + assert_output --partial "Invalid status" +} + +@test "agent-work helper rejects invalid category" { + bash "$INSTALL_SCRIPT" --yes + + run .agents/skills/agent-work/scripts/new-work.sh \ + --category custom-category \ + --slug invalid-category \ + --title "Invalid category" + assert_failure + assert_output --partial "Invalid category" + assert_output --partial "Expected one of" +} + +@test "sync preserves existing work item content" { + bash "$INSTALL_SCRIPT" --yes + + mkdir -p .agents/work/feature/demo-work + echo "# Demo Work" > .agents/work/feature/demo-work/index.md + echo "- [ ] Keep this task" > .agents/work/feature/demo-work/plan.md + echo "progress stays" > .agents/work/feature/demo-work/progress.md + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + run cat .agents/work/feature/demo-work/index.md + assert_output "# Demo Work" + + run cat .agents/work/feature/demo-work/plan.md + assert_output "- [ ] Keep this task" + + run cat .agents/work/feature/demo-work/progress.md + assert_output "progress stays" +} + +@test "sync preserves legacy plans and PRDs as user content" { + bash "$INSTALL_SCRIPT" --yes + + mkdir -p .agents/plans/in-progress .agents/prds + echo "# Legacy plan" > .agents/plans/in-progress/demo.md + echo "# Legacy PRD" > .agents/prds/demo.md + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + run cat .agents/plans/in-progress/demo.md + assert_output "# Legacy plan" + + run cat .agents/prds/demo.md + assert_output "# Legacy PRD" +} + +@test "sync removes retired legacy guidance and templates with backup" { + bash "$INSTALL_SCRIPT" --yes + + mkdir -p .agents/plans .agents/prds + echo "Use Ralph for plans" > .agents/plans/AGENTS.md + echo "# Old plan template" > .agents/plans/TEMPLATE.md + echo "Use Ralph for PRDs" > .agents/prds/AGENTS.md + echo "# Old PRD template" > .agents/prds/TEMPLATE.md + echo "# Real PRD" > .agents/prds/demo.md + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + assert_output --partial "retired legacy guidance" + assert_output --partial "BACKUP" + + [ ! -e ".agents/plans/AGENTS.md" ] + [ ! -e ".agents/plans/TEMPLATE.md" ] + [ ! -e ".agents/prds/AGENTS.md" ] + [ ! -e ".agents/prds/TEMPLATE.md" ] + [ -f ".agents/prds/demo.md" ] + + run find .agents/.dot-agents-backup -path '*/.agents/prds/AGENTS.md' -type f + assert_output --partial ".agents/prds/AGENTS.md" + + run find .agents/.dot-agents-backup -path '*/.agents/plans/TEMPLATE.md' -type f + assert_output --partial ".agents/plans/TEMPLATE.md" +} + +@test "--write-conflicts creates .dot-agents.md files for Markdown conflicts" { # First install bash "$INSTALL_SCRIPT" --yes # Modify a skill file to create conflict - echo "# Modified skill" > .agents/skills/sample-skill/SKILL.md + echo "# Modified skill" > .agents/skills/research/SKILL.md # Re-install with --write-conflicts should create conflict files run bash "$INSTALL_SCRIPT" --write-conflicts --yes @@ -215,7 +349,7 @@ teardown() { assert_output --partial "CONFLICT" # Should create conflict file for the skill - [ -f ".agents/skills/sample-skill/SKILL.dot-agents.md" ] + [ -f ".agents/skills/research/SKILL.dot-agents.md" ] } @test "sync defaults to force mode (overwrites with backup)" { @@ -223,7 +357,7 @@ teardown() { bash "$INSTALL_SCRIPT" --yes # Modify a skill file to create conflict - echo "# Modified skill" > .agents/skills/sample-skill/SKILL.md + echo "# Modified skill" > .agents/skills/research/SKILL.md # Re-install (sync) should default to force mode run bash "$INSTALL_SCRIPT" @@ -241,7 +375,7 @@ teardown() { bash "$INSTALL_SCRIPT" --yes # Modify a skill file to create conflict - echo "# Modified skill" > .agents/skills/sample-skill/SKILL.md + echo "# Modified skill" > .agents/skills/research/SKILL.md # --diff should show diff output run bash "$INSTALL_SCRIPT" --diff @@ -251,7 +385,7 @@ teardown() { assert_output --partial "+++" # Diff header # Should NOT create conflict files - [ ! -f ".agents/skills/sample-skill/SKILL.dot-agents.md" ] + [ ! -f ".agents/skills/research/SKILL.dot-agents.md" ] } @test "--diff exits 0 when no conflicts" { @@ -273,7 +407,7 @@ teardown() { original_meta=$(cat .agents/.dot-agents.json) # Modify a skill file - echo "# Modified skill" > .agents/skills/sample-skill/SKILL.md + echo "# Modified skill" > .agents/skills/research/SKILL.md # --diff should not update metadata run bash "$INSTALL_SCRIPT" --diff @@ -284,6 +418,79 @@ teardown() { assert_output "$original_meta" } +@test "--diff exits 1 when core files are missing without installing them" { + bash "$INSTALL_SCRIPT" --yes + + rm -rf .agents/skills/agent-work + + local original_meta + original_meta=$(cat .agents/.dot-agents.json) + + run bash "$INSTALL_SCRIPT" --diff + assert_failure + assert_output --partial "would install" + assert_output --partial "Pending changes:" + + [ ! -d ".agents/skills/agent-work" ] + [ ! -d ".agents/.dot-agents-backup" ] + + run cat .agents/.dot-agents.json + assert_output "$original_meta" +} + +@test "--diff exits 1 for retired Ralph without removing it" { + bash "$INSTALL_SCRIPT" --yes + + mkdir -p .agents/skills/ralph + echo "# Legacy Ralph" > .agents/skills/ralph/SKILL.md + + run bash "$INSTALL_SCRIPT" --diff + assert_failure + assert_output --partial "retired core skill, preview only" + assert_output --partial "Pending changes:" + + [ -f ".agents/skills/ralph/SKILL.md" ] + [ ! -d ".agents/.dot-agents-backup" ] +} + +@test "--diff exits 1 for retired legacy guidance without removing it" { + bash "$INSTALL_SCRIPT" --yes + + mkdir -p .agents/prds + echo "Use Ralph" > .agents/prds/AGENTS.md + + run bash "$INSTALL_SCRIPT" --diff + assert_failure + assert_output --partial "retired legacy guidance, preview only" + assert_output --partial "Pending changes:" + + [ -f ".agents/prds/AGENTS.md" ] + [ ! -d ".agents/.dot-agents-backup" ] +} + +@test "clean sync does not create backup for generated metadata" { + bash "$INSTALL_SCRIPT" --yes + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + [ ! -d ".agents/.dot-agents-backup" ] +} + +@test "sync preserves legacy singular reference directory ignore" { + bash "$INSTALL_SCRIPT" --yes + mkdir -p .agents/reference/legacy-repo + echo "legacy" > .agents/reference/legacy-repo/file.txt + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + [ -f ".agents/reference/legacy-repo/file.txt" ] + run cat .agents/.gitignore + assert_output --partial "reference/" + assert_output --partial "references/*" +} + # ===== Task 1: .gitignore entry tests ===== @test "fresh install creates .agents/.gitignore with backup entry" { @@ -293,7 +500,7 @@ teardown() { # .gitignore should exist and contain backup entry [ -f ".agents/.gitignore" ] run cat ".agents/.gitignore" - assert_output --partial "../.dot-agents-backup/" + assert_output --partial ".dot-agents-backup/" } @test "sync overwrites .agents/.gitignore and adds backup entry" { @@ -311,7 +518,7 @@ teardown() { # Should contain backup entry (custom content overwritten by upstream) run cat ".agents/.gitignore" - assert_output --partial "../.dot-agents-backup/" + assert_output --partial ".dot-agents-backup/" } # ===== Task 2: Post-install guidance tests ===== @@ -425,7 +632,8 @@ teardown() { assert_output --partial "Claude Code skills linked" [ -L ".claude/skills/adapt" ] - [ -L ".claude/skills/ralph" ] + [ -L ".claude/skills/agent-work" ] + [ -L ".claude/skills/feature-planning" ] [ -L ".claude/skills/research" ] [ -L ".claude/skills/tmux" ] @@ -434,7 +642,7 @@ teardown() { [ "$target" = "../../.agents/skills/adapt" ] # Directory symlinks expose supporting skill files, not just SKILL.md. - [ -f ".claude/skills/ralph/references/progress-format.md" ] + [ -f ".claude/skills/agent-work/assets/plan-template.md" ] } @test "install does not create .claude when absent" { @@ -497,6 +705,41 @@ teardown() { [ ! -L ".claude/skills/old-skill" ] } +@test "sync removes retired Ralph Claude Code skill symlink" { + mkdir -p .claude + + bash "$INSTALL_SCRIPT" --yes + mkdir -p .agents/skills/ralph + echo "# Legacy Ralph" > .agents/skills/ralph/SKILL.md + ln -s ../../.agents/skills/ralph .claude/skills/ralph + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + [ ! -L ".claude/skills/ralph" ] +} + +@test "sync removes retired ralph core skill with backup" { + bash "$INSTALL_SCRIPT" --yes + mkdir -p .agents/skills/ralph + echo "# Legacy Ralph" > .agents/skills/ralph/SKILL.md + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + assert_output --partial "retired core skill" + assert_output --partial "BACKUP" + [ ! -d ".agents/skills/ralph" ] + + run find .agents/.dot-agents-backup -path '*/.agents/skills/ralph/SKILL.md' -type f + assert_output --partial ".agents/skills/ralph/SKILL.md" + + local backup_file + backup_file=$(find .agents/.dot-agents-backup -path '*/.agents/skills/ralph/SKILL.md' -type f | head -1) + run cat "$backup_file" + assert_output "# Legacy Ralph" +} + @test "--uninstall removes only dot-agents Claude Code skill symlinks" { mkdir -p .claude @@ -508,6 +751,7 @@ teardown() { assert_success [ ! -L ".claude/skills/adapt" ] - [ ! -L ".claude/skills/ralph" ] + [ ! -L ".claude/skills/agent-work" ] + [ ! -L ".claude/skills/feature-planning" ] [ -f ".claude/skills/my-custom-skill/SKILL.md" ] } From cc3988be7742aeef83fc3ee1eb58ae7abdcf80c0 Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 17:02:41 +0200 Subject: [PATCH 02/12] Clarify optional context workflow Amp-Thread-ID: https://ampcode.com/threads/T-019eefae-419c-7399-bcd1-d40066dfd0d8 Co-authored-by: Amp --- .agents/skills/agent-work/SKILL.md | 6 ++--- .../skills/agent-work/assets/prd-template.md | 23 ++++++++-------- .agents/skills/feature-planning/SKILL.md | 25 +++++++++--------- .agents/work/AGENTS.md | 6 ++--- AGENTS.md | 4 +-- AGENTS.template.md | 6 ++--- QUICKSTART.md | 12 ++++++--- docs/concepts.md | 10 ++++--- docs/skills.md | 4 +-- site/index.html | 13 +++++---- test/fixtures/sample-archive.tar.gz | Bin 19286 -> 19352 bytes 11 files changed, 60 insertions(+), 49 deletions(-) diff --git a/.agents/skills/agent-work/SKILL.md b/.agents/skills/agent-work/SKILL.md index d7a94f7..bc4662a 100644 --- a/.agents/skills/agent-work/SKILL.md +++ b/.agents/skills/agent-work/SKILL.md @@ -5,7 +5,7 @@ description: "Creates and curates .agents/work/ work items. Use for durable inde # Agent Work -Create and maintain work items under `.agents/work///` so research, PRDs, plans, progress, decisions, and handoff prompts stay together for one piece of multi-session work. +Create and maintain work items under `.agents/work///` so context, plans, progress, decisions, and handoff prompts stay together for one piece of multi-session work. A "work item" is a folder; the entries inside `plan.md` are the executable tasks. @@ -20,7 +20,7 @@ A "work item" is a folder; the entries inside `plan.md` are the executable tasks 3. **Place artifacts deliberately** - Use `research.md` for findings specific to this work item. - Use `.agents/research/` for reusable cross-work findings. - - Use `prd.md` only when requirements need durable alignment. + - Use `prd.md` as a short requirements brief only when alignment is needed. - Use `plan.md` for implementation-ready tasks; copy `.agents/skills/agent-work/assets/plan-template.md` as a starting point. - Use `progress.md` for implementation notes, verification results, blockers, and next action. - Add `decisions/` only when durable decision records are worth linking. @@ -85,7 +85,7 @@ When the user asks to migrate one legacy plan: - `assets/work-index-template.md`: starting point for `index.md` - `assets/plan-template.md`: implementation-ready `plan.md` contract -- `assets/prd-template.md`: optional `prd.md` structure +- `assets/prd-template.md`: optional requirements brief (`prd.md`) structure - `assets/work-decision-template.md`: optional decision record template ## Verification diff --git a/.agents/skills/agent-work/assets/prd-template.md b/.agents/skills/agent-work/assets/prd-template.md index 54eda6e..a93b955 100644 --- a/.agents/skills/agent-work/assets/prd-template.md +++ b/.agents/skills/agent-work/assets/prd-template.md @@ -1,16 +1,22 @@ -# PRD Template +# Requirements Brief Template -Use this template when work needs requirements alignment before implementation. For small, scoped changes with clear acceptance criteria, create `plan.md` directly instead. +Use this template only when work needs durable requirements alignment before planning. For small, scoped changes with clear behavior and acceptance criteria, create `plan.md` directly instead. + +Keep this brief. If technical discovery dominates, use `research.md` instead. ## Template ```markdown -# [Feature Name] PRD +# [Work Item] Requirements Brief -## Problem Statement +## Problem What problem are we solving? Why now? +## Desired Outcome + +What should be true when this is done? + ## Goals - Goal 1 @@ -31,7 +37,7 @@ What problem are we solving? Why now? - [ ] Requirement 1 - [ ] Requirement 2 -### Nice to Have +### Optional - [ ] Optional requirement @@ -45,11 +51,6 @@ What problem are we solving? Why now? - Criterion 1 - Criterion 2 -## Verification / Rollout - -- How this should be verified -- Rollout guardrails or follow-up checks - ## Open Questions - [ ] Question that materially affects scope, sequence, or architecture @@ -57,4 +58,4 @@ What problem are we solving? Why now? ## Handoff To Planning -Once the PRD is approved, create `plan.md` in the same work item using the [agent-work plan template](plan-template.md). Do not create new `.agents/plans/` files. +Once the brief is aligned, create `plan.md` in the same work item using the [agent-work plan template](plan-template.md). Do not create new `.agents/plans/` files. diff --git a/.agents/skills/feature-planning/SKILL.md b/.agents/skills/feature-planning/SKILL.md index e914628..6e35407 100644 --- a/.agents/skills/feature-planning/SKILL.md +++ b/.agents/skills/feature-planning/SKILL.md @@ -1,25 +1,24 @@ --- name: feature-planning -description: "Turns research and PRDs into implementation-ready plans and paste-ready handoff prompts. Use for planning, plan refinement, and new-thread prompts. Triggers on: plan, PRD, feature planning, handoff prompt, stress-test design." +description: "Turns work-item context into plans and paste-ready handoff prompts. Use for planning, requirements briefs, plan refinement, and new-thread prompts. Triggers on: plan, requirements, PRD, feature planning, handoff prompt." --- # Feature Planning -Manage work-item planning from rough intent through PRD, implementation-ready plan, and paste-ready prompt for a fresh implementation thread. +Manage work-item planning from rough intent through optional context, implementation-ready plan, and paste-ready prompt for a fresh implementation thread. ## Workflow Overview ```text -Work Item → Research/PRD as needed → Plan → Refine → Handoff Prompt → Implement → Record Progress +Work Item → Context as needed → Plan → Refine → Handoff Prompt → Implement → Record Progress ``` 1. **Work item**: Use `agent-work` to create or locate `.agents/work///`. -2. **Research**: Save task-specific findings in the work item and reusable findings in `.agents/research/`. -3. **PRD**: Create `prd.md` only when requirements need durable alignment. -4. **Plan**: Create or update `plan.md` with scoped tasks, dependencies, and acceptance criteria. -5. **Refine**: Validate assumptions against current repo reality before implementation. -6. **Handoff prompt**: Produce a paste-ready prompt for the next implementation thread. -7. **Progress**: The implementation thread updates task checkboxes, `progress.md`, and `index.md`. +2. **Context**: Add `research.md` for technical facts or `prd.md` as a short requirements brief only when needed. +3. **Plan**: Create or update `plan.md` with scoped tasks, dependencies, and acceptance criteria. +4. **Refine**: Validate assumptions against current repo reality before implementation. +5. **Handoff prompt**: Produce a paste-ready prompt for the next implementation thread. +6. **Progress**: The implementation thread updates task checkboxes, `progress.md`, and `index.md`. ## Plan Locations @@ -36,11 +35,11 @@ New plans live inside work items: Legacy standalone plan and PRD documents are user content. Migrate one at a time into `.agents/work/` only when requested. Retired Ralph guidance/templates may be backed up and removed by sync. -## PRD Guidance +## Requirements Brief Guidance -Create `prd.md` when work is user-facing, ambiguous, cross-team, or likely to span multiple sessions. Use the [agent-work PRD template](../agent-work/assets/prd-template.md). +Most work does not need a PRD. Create `prd.md` only when the missing context is requirements alignment: users, behavior, goals, non-goals, acceptance, rollout, or stakeholder decisions. Use the [agent-work requirements brief template](../agent-work/assets/prd-template.md). -Skip the PRD for small scoped fixes when the desired behavior and acceptance criteria are already clear. +Use `research.md` for technical discovery. If acceptance criteria fit naturally in `plan.md`, skip `prd.md`. ## Plan Guidance @@ -59,7 +58,7 @@ For larger work, prefer an early thin slice that proves the end-to-end path befo Use this before writing a handoff prompt when work is multi-phase, ambiguous, or stale. 1. Read the work item's `index.md` and active `plan.md`. -2. Read relevant `research.md`, `prd.md`, and decisions only as needed. +2. Read relevant `research.md`, requirements brief (`prd.md`), and decisions only as needed. 3. Validate key assumptions against current code, dependencies, and test setup. 4. Resolve material open questions with repo evidence where possible; ask the user only for decisions the repo cannot answer. 5. If a planned task is already satisfied, record evidence and update the plan instead of creating no-op work. diff --git a/.agents/work/AGENTS.md b/.agents/work/AGENTS.md index 1703d64..e832501 100644 --- a/.agents/work/AGENTS.md +++ b/.agents/work/AGENTS.md @@ -10,7 +10,7 @@ Each work item lives at: .agents/work/// ``` -Use work items for multi-session work where research, requirements, plans, progress, decisions, and handoff prompts should stay together. Keep `.agents/research/` for reusable cross-work findings. +Use work items for multi-session work where context, plans, progress, decisions, and handoff prompts should stay together. Keep `.agents/research/` for reusable cross-work findings. A work item is a *container of tasks*; the task checklist lives inside `plan.md`. @@ -42,7 +42,7 @@ Read `index.md` first when entering a work item, then load only the artifacts ne - `index.md`: required work-item landing page and current summary. - `research.md`: work-local synthesis when investigation mainly supports this work item. - `research/`: optional indexed folder for multiple focused research notes. -- `prd.md`: optional requirements document for user-facing, ambiguous, or cross-team work. +- `prd.md`: optional short requirements brief for user-facing, ambiguous, or cross-team work. - `plan.md`: implementation-ready task plan. - `progress.md`: running implementation log, verification notes, blockers, and next actions. - `decisions/`: optional one-file-per-decision records when a decision should outlive chat context. @@ -65,4 +65,4 @@ When preparing a new implementation thread, ask for a paste-ready handoff prompt ## Decisions -Create a file under `decisions/` only when a decision would otherwise be repeated across research, PRD, plan, and chat. Link to the decision file from other artifacts instead of restating the full rationale. +Create a file under `decisions/` only when a decision would otherwise be repeated across research, requirements brief, plan, and chat. Link to the decision file from other artifacts instead of restating the full rationale. diff --git a/AGENTS.md b/AGENTS.md index 0f32be3..240e350 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,11 +12,11 @@ dot-agents is an AI-ready `.agents/` workspace scaffold for any project. It prov ## Workflow ```text -Work Item → Research/PRD as needed → Plan → Handoff Prompt → Implement → Record Progress +Work Item → Context as needed → Plan → Handoff Prompt → Implement → Record Progress ``` 1. **Work Item:** Create `.agents/work///index.md` as the durable entrypoint. -2. **Research/PRD:** Save task-specific findings and requirements beside the work item. +2. **Context:** Add `research.md` for technical facts or `prd.md` as a short requirements brief only when needed. 3. **Plan:** Break work into implementation-ready tasks in `plan.md`. 4. **Handoff Prompt:** Generate a paste-ready prompt for a fresh implementation thread. 5. **Progress:** Implementation threads update `progress.md`, task checkboxes, and `index.md`. diff --git a/AGENTS.template.md b/AGENTS.template.md index 2198c24..af05d03 100644 --- a/AGENTS.template.md +++ b/AGENTS.template.md @@ -16,11 +16,11 @@ ## Workflow ```text -Work Item → Research/PRD as needed → Plan → Handoff Prompt → Implement → Record Progress +Work Item → Context as needed → Plan → Handoff Prompt → Implement → Record Progress ``` 1. **Work Item:** Create durable context in `.agents/work///`. -2. **Research/PRD:** Save task-specific findings and requirements beside the work item. +2. **Context:** Add `research.md` for technical facts or `prd.md` as a short requirements brief only when needed. 3. **Plan:** Break work into implementation-ready tasks in `plan.md`. 4. **Handoff Prompt:** Generate a paste-ready prompt for a fresh implementation thread. 5. **Progress:** Implementation threads update `progress.md`, task checkboxes, and `index.md`. @@ -79,7 +79,7 @@ Updated: YYYY-MM-DD Use optional files only when useful: - `research.md` - work-specific investigation notes -- `prd.md` - requirements when alignment is needed +- `prd.md` - short requirements brief when alignment is needed - `plan.md` - implementation-ready task checklist - `progress.md` - implementation log, verification, blockers, and next action - `decisions/` - durable decision records diff --git a/QUICKSTART.md b/QUICKSTART.md index 833d193..3213539 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -83,15 +83,21 @@ The work item starts at: .agents/work/feature/user-authentication/index.md ``` -## 4. Research and Plan +## 4. Add Context Only If Needed, Then Plan -Ask for work-local research: +If the unknowns are technical, ask for work-local research: ```text Research authentication patterns for this work item. ``` -Then ask for a plan: +If the desired behavior is ambiguous, ask for a short requirements brief: + +```text +Create a short requirements brief for this work item. +``` + +If the goal is already clear, skip extra context and ask for a plan: ```text Create an implementation-ready plan in .agents/work/feature/user-authentication/plan.md. diff --git a/docs/concepts.md b/docs/concepts.md index 5ec3f85..89ba0e0 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -3,23 +3,25 @@ ## Workflow ```text -Work Item → Research/PRD as needed → Plan → Handoff Prompt → Implement → Record Progress +Work Item → Context as needed → Plan → Handoff Prompt → Implement → Record Progress ``` 1. **Work Item:** Create `.agents/work///index.md` as the durable context entrypoint. -2. **Research/PRD:** Save task-specific research and requirements beside the work item. Use `.agents/research/` only for reusable notes. +2. **Context:** Add optional context only when it helps: `research.md` for technical facts, or `prd.md` as a short requirements brief when behavior needs alignment. 3. **Plan:** Break work into implementation-ready tasks in `plan.md` with scope, dependencies, and acceptance criteria. 4. **Handoff Prompt:** Ask an agent to write a paste-ready prompt for a fresh implementation thread. 5. **Implement:** Paste the prompt into the new thread and let that agent do the scoped work. 6. **Record Progress:** Update `progress.md`, task checkboxes, and `index.md` so future threads can resume. +Context is optional. Use `research.md` when the question is "what is true?" Use `prd.md` as a requirements brief when the question is "what should be true?" Skip both when the plan can state the goal and acceptance criteria clearly. + ## Work Item Shape ```text .agents/work/// ├── index.md # required landing page ├── research.md # optional, work-specific findings -├── prd.md # optional requirements +├── prd.md # optional requirements brief ├── plan.md # optional implementation-ready tasks ├── progress.md # optional implementation log └── decisions/ # optional durable decisions @@ -51,7 +53,7 @@ Older dot-agents installs used `.agents/plans/` and `.agents/prds/`. v0.3.0 pres | adapt | Skill that analyzes your project and fills in `AGENTS.md` | | work item | Durable folder under `.agents/work///` for one multi-session effort | | task | Checkbox entry inside `plan.md` | -| PRD | Optional product or requirements document defining what to build | +| PRD | Optional short requirements brief defining what should be true | | plan | Implementation-ready task list with scope, dependencies, and acceptance criteria | | handoff prompt | Paste-ready prompt for a fresh implementation thread | | progress log | `progress.md`, the implementation log for changes, verification, blockers, and next action | diff --git a/docs/skills.md b/docs/skills.md index dd2a8d7..5875c24 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -42,11 +42,11 @@ Use it to create work items, list active work, place artifacts deliberately, and ## feature-planning -Turns research and requirements into implementation-ready plans and paste-ready handoff prompts. +Turns work-item context into implementation-ready plans and paste-ready handoff prompts. Use it to: -- Create or refine `prd.md` +- Create or refine a short requirements brief (`prd.md`) only when alignment is needed - Create or refine `plan.md` - Validate stale assumptions before implementation - Generate a new-thread handoff prompt diff --git a/site/index.html b/site/index.html index 9a0fd7b..88c8ef8 100644 --- a/site/index.html +++ b/site/index.html @@ -63,10 +63,12 @@

Ship faster with structured AI workflows

Pin a version curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.3.0 -

Current release: v0.3.0. Older releases are available on GitHub.

+

Current release: v0.3.0 — the work-items and handoff-prompts workflow.

- Older releases + Need the old Ralph workflow? +

v0.2.0 is archived for existing projects that still depend on .agents/plans/, .agents/prds/, or Ralph. New projects should use v0.3.0.

@@ -96,7 +98,7 @@

Instant Setup

📋

Durable Work Items

-

Keep research, requirements, plans, progress, decisions, and next actions together.

+

Keep context, plans, progress, decisions, and next actions together.

🤖
@@ -125,8 +127,8 @@

The workflow

2
- Research/PRD - Capture findings and requirements as needed + Context as needed + Research technical unknowns; use a requirements brief only when behavior needs alignment
@@ -146,6 +148,7 @@

The workflow

+

Create only the artifacts that help: research for facts, a requirements brief for alignment, a plan for executable tasks, and progress for continuity.

diff --git a/test/fixtures/sample-archive.tar.gz b/test/fixtures/sample-archive.tar.gz index 1a74c49ad7cf72c8e897d0e12179ccf6842bfea3..c37fe8fa7b55e001f6b1773e89dc20ef19cbb330 100644 GIT binary patch delta 19121 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 Date: Mon, 22 Jun 2026 17:05:34 +0200 Subject: [PATCH 03/12] Simplify archived workflow note Amp-Thread-ID: https://ampcode.com/threads/T-019eefae-419c-7399-bcd1-d40066dfd0d8 Co-authored-by: Amp --- site/index.html | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/site/index.html b/site/index.html index 88c8ef8..2b99ffb 100644 --- a/site/index.html +++ b/site/index.html @@ -64,14 +64,7 @@

Ship faster with structured AI workflows

curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.3.0
-
- Need the old Ralph workflow? -

v0.2.0 is archived for existing projects that still depend on .agents/plans/, .agents/prds/, or Ralph. New projects should use v0.3.0.

- -
+

Need the old Ralph workflow? v0.2.0 release and docs/source are archived for existing projects.

Current release: v0.3.0 — the work-items and handoff-prompts workflow.

From 4e172d709d158baa015fffee3efb02399739c512 Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 17:13:49 +0200 Subject: [PATCH 04/12] Polish site install metadata Amp-Thread-ID: https://ampcode.com/threads/T-019eefae-419c-7399-bcd1-d40066dfd0d8 Co-authored-by: Amp --- site/index.html | 8 +------- site/style.css | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/site/index.html b/site/index.html index 2b99ffb..0a5fc9e 100644 --- a/site/index.html +++ b/site/index.html @@ -58,13 +58,7 @@

Ship faster with structured AI workflows

Review first: curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | less

-

Then point your agent at a real problem and iterate.

-
- Pin a version - curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.3.0 -
-

Current release: v0.3.0 — the work-items and handoff-prompts workflow.

-

Need the old Ralph workflow? v0.2.0 release and docs/source are archived for existing projects.

+

Current: v0.3.0. Need Ralph? v0.2.0 is archived.

diff --git a/site/style.css b/site/style.css index 976e19a..063b468 100644 --- a/site/style.css +++ b/site/style.css @@ -3,7 +3,7 @@ --bg-secondary: #12121a; --bg-card: #16161f; --text: #e8e8ed; - --text-muted: #8b8b9e; + --text-muted: #a0a0b4; --accent: #00d9ff; --accent-glow: rgba(0, 217, 255, 0.15); --border: #2a2a3a; @@ -164,7 +164,7 @@ header { .terminal-dot.green { background: #27c93f; } .code-block pre { - padding: 1.25rem 3.5rem 1.25rem 1.25rem; + padding: 1.25rem 4.75rem 1.25rem 1.25rem; font-family: "SF Mono", "Fira Code", "Consolas", monospace; font-size: 0.9rem; line-height: 1.6; From a582e052bec5bc740c08bb571b50d7404b0e94e3 Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 17:31:47 +0200 Subject: [PATCH 05/12] Harden dot-agents sync previews Amp-Thread-ID: https://ampcode.com/threads/T-019eefe7-2b0f-70fd-8d2c-8a5df32b7c0c Co-authored-by: Amp --- .agents/scripts/sync.sh | 4 +- .agents/skills/agent-work/SKILL.md | 1 + README.md | 4 +- docs/migration-v1.md | 2 + install.sh | 70 ++++++++++++++++++++++----- scripts/lint.sh | 2 + scripts/serve-docs.sh | 2 +- test/fixtures/sample-archive.tar.gz | Bin 19352 -> 19374 bytes test/integration/install.bats | 71 ++++++++++++++++++++++++++++ 9 files changed, 139 insertions(+), 17 deletions(-) diff --git a/.agents/scripts/sync.sh b/.agents/scripts/sync.sh index 1d8eaa1..bcef7cf 100755 --- a/.agents/scripts/sync.sh +++ b/.agents/scripts/sync.sh @@ -54,9 +54,9 @@ All options are passed through to the upstream install.sh script. Options: --dry-run Show what would happen without making changes - --diff Show unified diff for conflicts instead of overwriting + --diff Preview pending changes without writing; exit 1 if pending --force Overwrite conflicts (creates backup first) - --write-conflicts Create .dot-agents.md/.dot-agents.new files for conflicts + --write-conflicts Create file.dot-agents.md/file.ext.dot-agents.new conflicts --interactive Prompt for each conflict --yes Skip confirmation prompts --version Show version and installation info diff --git a/.agents/skills/agent-work/SKILL.md b/.agents/skills/agent-work/SKILL.md index bc4662a..c90c62f 100644 --- a/.agents/skills/agent-work/SKILL.md +++ b/.agents/skills/agent-work/SKILL.md @@ -36,6 +36,7 @@ A "work item" is a folder; the entries inside `plan.md` are the executable tasks - Canonical path: `.agents/work///` - Category values: `feature`, `bugfix`, `tech-debt`, `docs`, `tooling`, `research`, `other` +- Categories are intentionally closed; use `other` when none fit. - Required file: `index.md` - Status values: `researching`, `planned`, `in-progress`, `blocked`, `completed` - Optional files: `research.md`, `prd.md`, `plan.md`, `progress.md` diff --git a/README.md b/README.md index 9dd5ebf..792d1c0 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ The installer copies `AGENTS.template.md` → `AGENTS.md` on fresh install only. | Flag | Behavior | | --- | --- | | default | Overwrite upstream-owned conflicts with backup during sync | -| `--diff` | Preview changes without modifying files | -| `--write-conflicts` | Create `.dot-agents.md` or `.dot-agents.new` files for manual review | +| `--diff` | Preview pending installs, updates, removals, and conflicts without modifying files; exits 1 if any change is pending | +| `--write-conflicts` | Create conflict files for manual review: Markdown writes `file.dot-agents.md`; other files write `file.ext.dot-agents.new` | | `--dry-run` | Show what would happen without changes | ## Versioning diff --git a/docs/migration-v1.md b/docs/migration-v1.md index 1e4743e..cda1305 100644 --- a/docs/migration-v1.md +++ b/docs/migration-v1.md @@ -25,6 +25,8 @@ Existing legacy plan and PRD documents, `.agents/research/`, and legacy `.agents v0.3.0 does not ship a Ralph compatibility layer, alias, or stub skill. Pin to `v0.2.0` only if you need the old runner workflow for an existing project. +Use `--diff` before syncing to preview pending installs, updates, removals, and conflicts without modifying files; it exits non-zero when any change is pending. Use `--write-conflicts` to write conflicts beside the original: Markdown conflicts use `file.dot-agents.md`, while other files use `file.ext.dot-agents.new`. + The preferred external-reference path is now `.agents/references/`. Existing `.agents/reference/` checkouts remain ignored so large local clones are not accidentally committed. Rename them manually when convenient. ## Migrate One Legacy Plan diff --git a/install.sh b/install.sh index a59782b..db8b11d 100755 --- a/install.sh +++ b/install.sh @@ -36,9 +36,9 @@ Install dot-agents into the current project. Options: --dry-run Show what would happen without making changes - --diff Show unified diff for conflicts instead of overwriting + --diff Preview pending changes without writing; exit 1 if pending --force Overwrite conflicts (creates backup first, default on sync) - --write-conflicts Create .dot-agents.md/.dot-agents.new files for conflicts + --write-conflicts Create file.dot-agents.md/file.ext.dot-agents.new conflicts --ref Git ref to install (branch, tag, commit). Default: main --yes Skip confirmation prompts --uninstall Remove dot-agents @@ -194,6 +194,18 @@ pending_change_count=0 backup_count=0 BACKUP_DIR="" CLAUDE_SKILL_SYMLINKS_REMOVED=0 +AGENTS_GITIGNORE_PENDING=false + +is_agents_gitignore_path() { + local path="${1#./}" + [[ "$path" == ".agents/.gitignore" ]] +} + +mark_agents_gitignore_pending() { + if is_agents_gitignore_path "$1"; then + AGENTS_GITIGNORE_PENDING=true + fi +} is_dot_agents_claude_skill_symlink() { local path="$1" @@ -271,6 +283,8 @@ backup_item() { mkdir -p "$backup_dir" if [[ -d "$path" && ! -L "$path" ]]; then cp -Rp "$path" "$backup_path" + elif [[ -L "$path" ]]; then + cp -Pp "$path" "$backup_path" else cp -p "$path" "$backup_path" fi @@ -446,6 +460,19 @@ CORE_SKILLS="adapt agent-work feature-planning research tmux" RETIRED_CORE_SKILLS="ralph" RETIRED_LEGACY_GUIDANCE_FILES=".agents/plans/AGENTS.md .agents/prds/AGENTS.md .agents/plans/TEMPLATE.md .agents/prds/TEMPLATE.md" +is_retired_core_skill() { + local skill_name="$1" + local retired + + for retired in $RETIRED_CORE_SKILLS; do + if [[ "$skill_name" == "$retired" ]]; then + return 0 + fi + done + + return 1 +} + detect_custom_skills() { local skills_dir=".agents/skills" local custom_skills=() @@ -550,10 +577,15 @@ cleanup_stale_claude_code_skill_symlinks() { is_dot_agents_claude_skill_symlink "$skill_link" || continue skill_name="$(basename "$skill_link")" - [[ -f "$agents_skills_dir/$skill_name/SKILL.md" ]] && continue + if [[ -f "$agents_skills_dir/$skill_name/SKILL.md" ]] && ! is_retired_core_skill "$skill_name"; then + continue + fi - if [[ "$DRY_RUN" == "true" ]]; then + if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then log_info " ${RED}[REMOVE]${NC} $skill_link (stale)" + if [[ "$DIFF_ONLY" == "true" ]]; then + pending_change_count=$((pending_change_count + 1)) + fi else rm -f "$skill_link" log_info " ${RED}[REMOVE]${NC} $skill_link (stale)" @@ -579,7 +611,7 @@ setup_claude_code_integration() { return 0 fi - if [[ "$DRY_RUN" != "true" ]]; then + if [[ "$DRY_RUN" != "true" && "$DIFF_ONLY" != "true" ]]; then if ! mkdir -p "$claude_skills_dir"; then log_info " ${YELLOW}[SKIP]${NC} $claude_skills_dir (could not create directory)" return 0 @@ -591,6 +623,10 @@ setup_claude_code_integration() { [[ -f "$skill_dir/SKILL.md" ]] || continue skill_name="$(basename "$skill_dir")" + if is_retired_core_skill "$skill_name"; then + continue + fi + dest="$claude_skills_dir/$skill_name" link_target="../../.agents/skills/$skill_name" @@ -600,9 +636,12 @@ setup_claude_code_integration() { continue fi if is_dot_agents_claude_skill_symlink "$dest"; then - if [[ "$DRY_RUN" == "true" ]]; then - log_info " ${GREEN}[LINK]${NC} $dest → $link_target" + if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then + log_info " ${GREEN}[LINK]${NC} $dest → $link_target (preview only)" linked=$((linked + 1)) + if [[ "$DIFF_ONLY" == "true" ]]; then + pending_change_count=$((pending_change_count + 1)) + fi continue fi rm -f "$dest" @@ -617,9 +656,12 @@ setup_claude_code_integration() { continue fi - if [[ "$DRY_RUN" == "true" ]]; then - log_info " ${GREEN}[LINK]${NC} $dest → $link_target" + if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then + log_info " ${GREEN}[LINK]${NC} $dest → $link_target (preview only)" linked=$((linked + 1)) + if [[ "$DIFF_ONLY" == "true" ]]; then + pending_change_count=$((pending_change_count + 1)) + fi continue fi @@ -644,6 +686,10 @@ ensure_gitignore_entry() { local backup_entry=".dot-agents-backup/" if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then + if [[ "$DIFF_ONLY" == "true" && "$AGENTS_GITIGNORE_PENDING" == "true" ]]; then + return 0 + fi + if [[ ! -f "$gitignore_file" ]]; then log_info " ${GREEN}[CREATE]${NC} $gitignore_file" if [[ "$DIFF_ONLY" == "true" ]]; then @@ -680,6 +726,7 @@ install_file() { log_install "$dest (would install)" installed_count=$((installed_count + 1)) pending_change_count=$((pending_change_count + 1)) + mark_agents_gitignore_pending "$dest" return 0 fi @@ -739,6 +786,7 @@ install_file() { echo "" conflict_count=$((conflict_count + 1)) pending_change_count=$((pending_change_count + 1)) + mark_agents_gitignore_pending "$dest" return 0 fi @@ -857,9 +905,7 @@ main() { ensure_gitignore_entry # Link dot-agents skills into Claude Code's project skill directory when present. - if [[ "$DIFF_ONLY" != "true" ]]; then - setup_claude_code_integration - fi + setup_claude_code_integration # Skip metadata write in diff-only mode if [[ "$DIFF_ONLY" != "true" ]]; then diff --git a/scripts/lint.sh b/scripts/lint.sh index f0ef47f..6b73f07 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -15,7 +15,9 @@ SCRIPTS=( .agents/scripts/sync.sh .agents/skills/agent-work/scripts/list-work.sh .agents/skills/agent-work/scripts/new-work.sh + scripts/build-test-fixture.sh scripts/lint.sh + scripts/serve-docs.sh scripts/test.sh test/mocks/curl ) diff --git a/scripts/serve-docs.sh b/scripts/serve-docs.sh index 145c6cc..8f29758 100755 --- a/scripts/serve-docs.sh +++ b/scripts/serve-docs.sh @@ -9,7 +9,7 @@ # ./scripts/serve-docs.sh --docs # Serve docs on port 8000 # -set -e +set -euo pipefail PORT="8000" DIR="site" diff --git a/test/fixtures/sample-archive.tar.gz b/test/fixtures/sample-archive.tar.gz index c37fe8fa7b55e001f6b1773e89dc20ef19cbb330..6471877523cce8ea0ce712f827874f1df85f139a 100644 GIT binary patch delta 18984 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 i+)O$7m7sJW1h~QCvI@T5d diff --git a/test/integration/install.bats b/test/integration/install.bats index 2a6d456..a4a4659 100755 --- a/test/integration/install.bats +++ b/test/integration/install.bats @@ -352,6 +352,18 @@ teardown() { [ -f ".agents/skills/research/SKILL.dot-agents.md" ] } +@test "--write-conflicts creates .dot-agents.new files for non-Markdown conflicts" { + bash "$INSTALL_SCRIPT" --yes + + printf '# Custom ignore\n.dot-agents-backup/\n' > .agents/.gitignore + + run bash "$INSTALL_SCRIPT" --write-conflicts --yes + assert_success + assert_output --partial "CONFLICT" + + [ -f ".agents/.gitignore.dot-agents.new" ] +} + @test "sync defaults to force mode (overwrites with backup)" { # First install bash "$INSTALL_SCRIPT" --yes @@ -468,6 +480,45 @@ teardown() { [ ! -d ".agents/.dot-agents-backup" ] } +@test "--diff counts .agents/.gitignore once when the file is missing" { + bash "$INSTALL_SCRIPT" --yes + rm .agents/.gitignore + + run bash "$INSTALL_SCRIPT" --diff + assert_failure + assert_output --partial "./.agents/.gitignore (would install)" + assert_output --partial "Pending changes: 1" +} + +@test "--diff exits 1 for pending Claude Code skill links without creating them" { + bash "$INSTALL_SCRIPT" --yes + mkdir -p .claude + + run bash "$INSTALL_SCRIPT" --diff + assert_failure + assert_output --partial "Claude Code skills linked" + assert_output --partial ".claude/skills/agent-work" + assert_output --partial "Pending changes:" + + [ ! -e ".claude/skills" ] +} + +@test "--diff exits 1 for stale retired Ralph Claude Code symlink without removing it" { + mkdir -p .claude + bash "$INSTALL_SCRIPT" --yes + + mkdir -p .agents/skills/ralph + echo "# Legacy Ralph" > .agents/skills/ralph/SKILL.md + ln -s ../../.agents/skills/ralph .claude/skills/ralph + + run bash "$INSTALL_SCRIPT" --diff + assert_failure + assert_output --partial ".claude/skills/ralph (stale)" + assert_output --partial "Pending changes:" + + [ -L ".claude/skills/ralph" ] +} + @test "clean sync does not create backup for generated metadata" { bash "$INSTALL_SCRIPT" --yes @@ -740,6 +791,26 @@ teardown() { assert_output "# Legacy Ralph" } +@test "sync backs up symlinked retired ralph core skill without following it" { + bash "$INSTALL_SCRIPT" --yes + ln -s ../missing-ralph .agents/skills/ralph + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + assert_output --partial "retired core skill" + assert_output --partial "BACKUP" + [ ! -L ".agents/skills/ralph" ] + + local backup_link + backup_link=$(find .agents/.dot-agents-backup -path '*/.agents/skills/ralph' -type l | head -1) + [ -n "$backup_link" ] + + local target + target="$(readlink "$backup_link")" + [ "$target" = "../missing-ralph" ] +} + @test "--uninstall removes only dot-agents Claude Code skill symlinks" { mkdir -p .claude From ac0971b1abc22ae331d13719270c8c663077e865 Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 18:49:05 +0200 Subject: [PATCH 06/12] Harden Claude Code skill symlink handling Amp-Thread-ID: https://ampcode.com/threads/T-019ef02e-f43d-74aa-82cc-78a02b0d5116 Co-authored-by: Amp --- docs/README.md | 2 +- install.sh | 13 ++++++++++- test/integration/install.bats | 44 +++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 72be303..5ace078 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,7 +15,7 @@ - [Skills](./skills.md) - [Claude Code Project Skill Discovery](./skills.md#claude-code-project-skill-discovery) -- [AGENTS.md Template](../AGENTS.md) +- [AGENTS.md Template](../AGENTS.template.md) ## For Contributors diff --git a/install.sh b/install.sh index db8b11d..1c9be02 100755 --- a/install.sh +++ b/install.sh @@ -54,7 +54,7 @@ Examples: curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --ref v0.3.0 # Preview changes first - curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --dry-run + curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --diff # Force update (backup + overwrite) curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash -s -- --force @@ -222,6 +222,11 @@ remove_claude_code_skill_symlinks() { CLAUDE_SKILL_SYMLINKS_REMOVED=0 + [[ -e "$claude_skills_dir" || -L "$claude_skills_dir" ]] || return 0 + if [[ -L "$claude_skills_dir" ]]; then + log_info "${YELLOW}[SKIP]${NC} $claude_skills_dir (user-owned symlink)" + return 0 + fi [[ -d "$claude_skills_dir" ]] || return 0 for skill_link in "$claude_skills_dir"/*; do @@ -570,6 +575,7 @@ cleanup_stale_claude_code_skill_symlinks() { local claude_skills_dir="$2" local skill_link skill_name + [[ ! -L "$claude_skills_dir" ]] || return 0 [[ -d "$claude_skills_dir" ]] || return 0 for skill_link in "$claude_skills_dir"/*; do @@ -606,6 +612,11 @@ setup_claude_code_integration() { log_info "" log_info "Detected ${BLUE}.claude/${NC} directory — linking dot-agents skills for Claude Code..." + if [[ -L "$claude_skills_dir" ]]; then + log_info " ${YELLOW}[SKIP]${NC} $claude_skills_dir (user-owned symlink)" + return 0 + fi + if [[ ( -e "$claude_skills_dir" || -L "$claude_skills_dir" ) && ! -d "$claude_skills_dir" ]]; then log_info " ${YELLOW}[SKIP]${NC} $claude_skills_dir (user-owned)" return 0 diff --git a/test/integration/install.bats b/test/integration/install.bats index a4a4659..22f3843 100755 --- a/test/integration/install.bats +++ b/test/integration/install.bats @@ -715,6 +715,20 @@ teardown() { assert_output "user file" } +@test "install skips Claude Code integration when .claude/skills is user-owned symlink" { + mkdir -p .claude external-skills + ln -s ../external-skills .claude/skills + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + assert_output --partial ".claude/skills (user-owned symlink)" + [ -L ".claude/skills" ] + + run find external-skills -mindepth 1 -maxdepth 1 -print + assert_output "" +} + @test "install preserves existing Claude Code user skill directory" { mkdir -p .claude/skills/adapt echo "# User adapt skill" > .claude/skills/adapt/SKILL.md @@ -756,6 +770,21 @@ teardown() { [ ! -L ".claude/skills/old-skill" ] } +@test "sync preserves symlinked Claude Code skills directory" { + mkdir -p .claude external-skills + ln -s ../external-skills .claude/skills + + bash "$INSTALL_SCRIPT" --yes + ln -s ../../.agents/skills/old-skill external-skills/old-skill + + run bash "$INSTALL_SCRIPT" --yes + assert_success + + assert_output --partial ".claude/skills (user-owned symlink)" + [ -L ".claude/skills" ] + [ -L "external-skills/old-skill" ] +} + @test "sync removes retired Ralph Claude Code skill symlink" { mkdir -p .claude @@ -826,3 +855,18 @@ teardown() { [ ! -L ".claude/skills/feature-planning" ] [ -f ".claude/skills/my-custom-skill/SKILL.md" ] } + +@test "--uninstall preserves symlinked Claude Code skills directory" { + mkdir -p .claude external-skills + ln -s ../external-skills .claude/skills + + bash "$INSTALL_SCRIPT" --yes + ln -s ../../.agents/skills/adapt external-skills/adapt + + run bash "$INSTALL_SCRIPT" --uninstall --yes + assert_success + + assert_output --partial ".claude/skills (user-owned symlink)" + [ -L ".claude/skills" ] + [ -L "external-skills/adapt" ] +} From 351286a690996aecb20504555def8aea53e039bd Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 19:09:40 +0200 Subject: [PATCH 07/12] Fix Claude Code preview guidance Amp-Thread-ID: https://ampcode.com/threads/T-019ef03a-77da-7784-b06c-192b5af07cef Co-authored-by: Amp --- install.sh | 8 ++++++-- test/integration/install.bats | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index 1c9be02..0920ac4 100755 --- a/install.sh +++ b/install.sh @@ -600,6 +600,7 @@ cleanup_stale_claude_code_skill_symlinks() { } setup_claude_code_integration() { + local source_agents_skills_dir="${1:-.agents/skills}" local agents_skills_dir=".agents/skills" local claude_skills_dir=".claude/skills" local linked=0 @@ -607,6 +608,9 @@ setup_claude_code_integration() { local skill_dir skill_name dest link_target existing_target [[ -d ".claude" ]] || return 0 + if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then + agents_skills_dir="$source_agents_skills_dir" + fi [[ -d "$agents_skills_dir" ]] || return 0 log_info "" @@ -916,7 +920,7 @@ main() { ensure_gitignore_entry # Link dot-agents skills into Claude Code's project skill directory when present. - setup_claude_code_integration + setup_claude_code_integration "${extracted_dir}/.agents/skills" # Skip metadata write in diff-only mode if [[ "$DIFF_ONLY" != "true" ]]; then @@ -962,7 +966,7 @@ main() { log_info "" log_info "${GREEN}Next steps:${NC}" log_info " 1. Run 'adapt' to customize AGENTS.md for your project" - log_info " 2. See QUICKSTART.md for workflow guidance" + log_info " 2. Read the quickstart: https://github.com/${REPO_OWNER}/${REPO_NAME}/blob/main/QUICKSTART.md" fi # Show sync update hint on sync (not fresh install) diff --git a/test/integration/install.bats b/test/integration/install.bats index 22f3843..99630da 100755 --- a/test/integration/install.bats +++ b/test/integration/install.bats @@ -503,6 +503,31 @@ teardown() { [ ! -e ".claude/skills" ] } +@test "--diff previews Claude Code skill links on fresh install without creating them" { + mkdir -p .claude + + run bash "$INSTALL_SCRIPT" --diff + assert_failure + assert_output --partial "Claude Code skills linked" + assert_output --partial ".claude/skills/agent-work" + assert_output --partial "Pending changes:" + + [ ! -e ".claude/skills" ] + [ ! -d ".agents" ] +} + +@test "--dry-run previews Claude Code skill links on fresh install without creating them" { + mkdir -p .claude + + run bash "$INSTALL_SCRIPT" --dry-run + assert_success + assert_output --partial "Claude Code skills linked" + assert_output --partial ".claude/skills/agent-work" + + [ ! -e ".claude/skills" ] + [ ! -d ".agents" ] +} + @test "--diff exits 1 for stale retired Ralph Claude Code symlink without removing it" { mkdir -p .claude bash "$INSTALL_SCRIPT" --yes @@ -581,7 +606,7 @@ teardown() { # Should show next steps assert_output --partial "Next steps:" assert_output --partial "Run 'adapt'" - assert_output --partial "QUICKSTART.md" + assert_output --partial "https://github.com/colmarius/dot-agents/blob/main/QUICKSTART.md" } @test "sync does not show next steps guidance" { From c426468cf9fe973c81d541e05a85b9aa48b836b4 Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 21:43:40 +0200 Subject: [PATCH 08/12] Harden install conflict handling Amp-Thread-ID: https://ampcode.com/threads/T-019ef07e-7eee-769c-8ce2-fa40271df7c9 Co-authored-by: Amp --- install.sh | 70 +++++++++++++++-------- test/integration/install.bats | 103 ++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 23 deletions(-) diff --git a/install.sh b/install.sh index 0920ac4..b9dbd94 100755 --- a/install.sh +++ b/install.sh @@ -269,7 +269,11 @@ backup_file() { log_info " ${BLUE}[BACKUP]${NC} $file → $backup_path" else mkdir -p "$backup_dir" - cp "$file" "$backup_path" + if [[ -L "$file" ]]; then + cp -Pp "$file" "$backup_path" + else + cp -p "$file" "$backup_path" + fi log_info " ${BLUE}[BACKUP]${NC} $file" fi backup_count=$((backup_count + 1)) @@ -375,44 +379,60 @@ log_info() { echo -e "$1"; } INTERACTIVE_SKIP_ALL=false INTERACTIVE_OVERWRITE_ALL=false +PROMPT_ACTION="" prompt_conflict() { local src="$1" local dest="$2" + local response="" if [[ "$INTERACTIVE_SKIP_ALL" == "true" ]]; then - echo "skip" + PROMPT_ACTION="skip" return fi if [[ "$INTERACTIVE_OVERWRITE_ALL" == "true" ]]; then - echo "overwrite" + PROMPT_ACTION="overwrite" return fi - echo "" - echo -e "${YELLOW}CONFLICT:${NC} $dest differs from upstream" + echo "" >&2 + echo -e "${YELLOW}CONFLICT:${NC} $dest differs from upstream" >&2 if command -v diff >/dev/null 2>&1; then - echo "--- $dest (yours)" - echo "+++ upstream" - diff -u "$dest" "$src" 2>/dev/null | head -20 || true - echo "" + echo "--- $dest (yours)" >&2 + echo "+++ upstream" >&2 + diff -u "$dest" "$src" 2>/dev/null | head -20 >&2 || true + echo "" >&2 + fi + + echo -n "[k]eep / [o]verwrite / [n]ew file / [s]kip all / [O]verwrite all? " >&2 + if [[ -n "${DOT_AGENTS_INTERACTIVE_RESPONSE:-}" ]]; then + response="$DOT_AGENTS_INTERACTIVE_RESPONSE" + DOT_AGENTS_INTERACTIVE_RESPONSE="" + elif [[ -r /dev/tty ]]; then + read -r response < /dev/tty || response="" + else + echo "" >&2 + log_info " ${YELLOW}[SKIP]${NC} no terminal available; writing conflict file for manual review" + PROMPT_ACTION="new" + return fi - echo -n "[k]eep / [o]verwrite / [n]ew file / [s]kip all / [O]verwrite all? " - read -r response case "$response" in - k|K) echo "keep" ;; - o) echo "overwrite" ;; - n|N) echo "new" ;; - s|S) INTERACTIVE_SKIP_ALL=true; echo "skip" ;; - O) INTERACTIVE_OVERWRITE_ALL=true; echo "overwrite" ;; - *) echo "new" ;; + k|K) PROMPT_ACTION="keep" ;; + o) PROMPT_ACTION="overwrite" ;; + n|N) PROMPT_ACTION="new" ;; + s|S) INTERACTIVE_SKIP_ALL=true; PROMPT_ACTION="skip" ;; + O) INTERACTIVE_OVERWRITE_ALL=true; PROMPT_ACTION="overwrite" ;; + *) PROMPT_ACTION="new" ;; esac } files_identical() { local file1="$1" local file2="$2" + + [[ -f "$file1" && -f "$file2" ]] || return 1 + if command -v md5sum >/dev/null 2>&1; then [[ "$(md5sum "$file1" | cut -d' ' -f1)" == "$(md5sum "$file2" | cut -d' ' -f1)" ]] elif command -v md5 >/dev/null 2>&1; then @@ -700,11 +720,11 @@ ensure_gitignore_entry() { local gitignore_file=".agents/.gitignore" local backup_entry=".dot-agents-backup/" - if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then - if [[ "$DIFF_ONLY" == "true" && "$AGENTS_GITIGNORE_PENDING" == "true" ]]; then - return 0 - fi + if [[ "$AGENTS_GITIGNORE_PENDING" == "true" ]]; then + return 0 + fi + if [[ "$DRY_RUN" == "true" || "$DIFF_ONLY" == "true" ]]; then if [[ ! -f "$gitignore_file" ]]; then log_info " ${GREEN}[CREATE]${NC} $gitignore_file" if [[ "$DIFF_ONLY" == "true" ]]; then @@ -736,7 +756,7 @@ install_file() { local dest_dir dest_dir="$(dirname "$dest")" - if [[ ! -e "$dest" ]]; then + if [[ ! -e "$dest" && ! -L "$dest" ]]; then if [[ "$DIFF_ONLY" == "true" ]]; then log_install "$dest (would install)" installed_count=$((installed_count + 1)) @@ -777,7 +797,8 @@ install_file() { # Interactive mode if [[ "$INTERACTIVE" == "true" ]] && [[ "$DRY_RUN" != "true" ]]; then local action - action="$(prompt_conflict "$src" "$dest")" + prompt_conflict "$src" "$dest" + action="$PROMPT_ACTION" case "$action" in keep|skip) log_skip "$dest (kept yours)" @@ -811,9 +832,12 @@ install_file() { else conflict_file="${dest}.dot-agents.new" fi + mark_agents_gitignore_pending "$dest" if [[ "$DRY_RUN" == "true" ]]; then log_conflict "$dest (would write ${conflict_file})" + elif [[ -e "$conflict_file" || -L "$conflict_file" ]]; then + log_conflict "$dest differs. Kept existing ${conflict_file}; remove it to regenerate." else cp -p "$src" "$conflict_file" log_conflict "$dest differs. Wrote ${conflict_file} for review." diff --git a/test/integration/install.bats b/test/integration/install.bats index 99630da..8df966a 100755 --- a/test/integration/install.bats +++ b/test/integration/install.bats @@ -364,6 +364,65 @@ teardown() { [ -f ".agents/.gitignore.dot-agents.new" ] } +@test "--write-conflicts does not mutate conflicted .agents/.gitignore" { + bash "$INSTALL_SCRIPT" --yes + + printf '# Custom ignore\n' > .agents/.gitignore + local original_gitignore + original_gitignore=$(cat .agents/.gitignore) + + run bash "$INSTALL_SCRIPT" --write-conflicts --yes + assert_success + assert_output --partial "CONFLICT" + + [ -f ".agents/.gitignore.dot-agents.new" ] + run cat .agents/.gitignore + assert_output "$original_gitignore" +} + +@test "--write-conflicts preserves an existing conflict sidecar" { + bash "$INSTALL_SCRIPT" --yes + + echo "# Modified skill" > .agents/skills/research/SKILL.md + echo "review notes stay" > .agents/skills/research/SKILL.dot-agents.md + + run bash "$INSTALL_SCRIPT" --write-conflicts --yes + assert_success + assert_output --partial "Kept existing ./.agents/skills/research/SKILL.dot-agents.md" + + run cat .agents/skills/research/SKILL.dot-agents.md + assert_output "review notes stay" +} + +@test "--interactive overwrite applies selected conflict action" { + bash "$INSTALL_SCRIPT" --yes + + echo "# Modified skill" > .agents/skills/research/SKILL.md + + run env DOT_AGENTS_INTERACTIVE_RESPONSE=o bash "$INSTALL_SCRIPT" --interactive --yes + assert_success + assert_output --partial "overwritten" + assert_output --partial "BACKUP" + + run head -1 .agents/skills/research/SKILL.md + assert_output "---" + [ ! -f ".agents/skills/research/SKILL.dot-agents.md" ] +} + +@test "--interactive keep preserves selected local conflict" { + bash "$INSTALL_SCRIPT" --yes + + echo "# Modified skill" > .agents/skills/research/SKILL.md + + run env DOT_AGENTS_INTERACTIVE_RESPONSE=k bash "$INSTALL_SCRIPT" --interactive --yes + assert_success + assert_output --partial "kept yours" + + run cat .agents/skills/research/SKILL.md + assert_output "# Modified skill" + [ ! -f ".agents/skills/research/SKILL.dot-agents.md" ] +} + @test "sync defaults to force mode (overwrites with backup)" { # First install bash "$INSTALL_SCRIPT" --yes @@ -382,6 +441,50 @@ teardown() { assert_output --partial ".dot-agents-backup" } +@test "sync backs up symlinked managed files without following them" { + bash "$INSTALL_SCRIPT" --yes + + mkdir -p external + echo "custom skill link target" > external/research-skill.md + rm .agents/skills/research/SKILL.md + ln -s ../../../external/research-skill.md .agents/skills/research/SKILL.md + + run bash "$INSTALL_SCRIPT" --yes + assert_success + assert_output --partial "force overwrite" + assert_output --partial "BACKUP" + + [ ! -L ".agents/skills/research/SKILL.md" ] + local backup_link + backup_link=$(find .agents/.dot-agents-backup -path '*/.agents/skills/research/SKILL.md' -type l | head -1) + [ -n "$backup_link" ] + + local target + target="$(readlink "$backup_link")" + [ "$target" = "../../../external/research-skill.md" ] +} + +@test "sync backs up broken symlinked managed files without following them" { + bash "$INSTALL_SCRIPT" --yes + + rm .agents/skills/research/SKILL.md + ln -s ../../../missing-research-skill.md .agents/skills/research/SKILL.md + + run bash "$INSTALL_SCRIPT" --yes + assert_success + assert_output --partial "force overwrite" + assert_output --partial "BACKUP" + + [ ! -L ".agents/skills/research/SKILL.md" ] + local backup_link + backup_link=$(find .agents/.dot-agents-backup -path '*/.agents/skills/research/SKILL.md' -type l | head -1) + [ -n "$backup_link" ] + + local target + target="$(readlink "$backup_link")" + [ "$target" = "../../../missing-research-skill.md" ] +} + @test "--diff shows unified diff for conflicts" { # First install bash "$INSTALL_SCRIPT" --yes From e0dbd89eba88c39f5b752790e6c8fe9bb012251a Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 21:59:28 +0200 Subject: [PATCH 09/12] Remove deprecated .agents/reference/ support; polish docs for v0.3.0 Amp-Thread-ID: https://ampcode.com/threads/T-019ef0d8-86c4-76fa-98f7-eda192859dc8 Co-authored-by: Amp --- .agents/.gitignore | 1 - .gitignore | 1 - CHANGELOG.md | 1 + docs/README.md | 2 +- docs/concepts.md | 2 +- docs/{migration-v1.md => migration-v0.3.md} | 4 ++-- test/fixtures/sample-archive.tar.gz | Bin 19374 -> 19361 bytes test/integration/install.bats | 10 +++++++--- 8 files changed, 12 insertions(+), 9 deletions(-) rename docs/{migration-v1.md => migration-v0.3.md} (71%) diff --git a/.agents/.gitignore b/.agents/.gitignore index 3cec1d0..ce68b55 100644 --- a/.agents/.gitignore +++ b/.agents/.gitignore @@ -1,6 +1,5 @@ # External reference repositories cloned for analysis # These are typically large and should not be committed -reference/ references/* !references/.gitkeep diff --git a/.gitignore b/.gitignore index dfeec41..e7590ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ # External reference repositories -.agents/reference/ .agents/references/* !.agents/references/.gitkeep diff --git a/CHANGELOG.md b/CHANGELOG.md index 293bd1a..fc7ed30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - **BREAKING:** Removed the `ralph` skill from core installs. Sync backs up and removes retired upstream `ralph` skill directories. - Fresh installs no longer create legacy `.agents/plans/` or `.agents/prds/` directories. - Sync backs up and removes retired legacy guidance/templates such as `.agents/prds/AGENTS.md` and old plan/PRD templates. +- Dropped support for the deprecated singular `.agents/reference/` path. External reference checkouts now live under `.agents/references/`; rename any existing `.agents/reference/` checkout, which is no longer gitignored. ### Added diff --git a/docs/README.md b/docs/README.md index 5ace078..8741e58 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,7 +9,7 @@ - [Workflow Overview](./concepts.md#workflow) - [Glossary](./concepts.md#glossary) -- [v0.3 Migration](./migration-v1.md) +- [v0.3 Migration](./migration-v0.3.md) ## Reference diff --git a/docs/concepts.md b/docs/concepts.md index 89ba0e0..bb52107 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -44,7 +44,7 @@ dot-agents does not assume a specific execution runtime. The work item is the co ## Legacy Content -Older dot-agents installs used `.agents/plans/` and `.agents/prds/`. v0.3.0 preserves legacy plan and PRD documents as user content but no longer creates those paths on fresh install. See [migration guide](./migration-v1.md) for how to move active work into `.agents/work/`. +Older dot-agents installs used `.agents/plans/` and `.agents/prds/`. v0.3.0 preserves legacy plan and PRD documents as user content but no longer creates those paths on fresh install. See [migration guide](./migration-v0.3.md) for how to move active work into `.agents/work/`. ## Glossary diff --git a/docs/migration-v1.md b/docs/migration-v0.3.md similarity index 71% rename from docs/migration-v1.md rename to docs/migration-v0.3.md index cda1305..1dd82ed 100644 --- a/docs/migration-v1.md +++ b/docs/migration-v0.3.md @@ -21,13 +21,13 @@ Fresh installs no longer create: .agents/skills/ralph/ ``` -Existing legacy plan and PRD documents, `.agents/research/`, and legacy `.agents/reference/` content are preserved on sync. Retired Ralph support is backed up and removed so stale guidance does not conflict with the new workflow. This includes `.agents/skills/ralph`, `.agents/plans/AGENTS.md`, `.agents/prds/AGENTS.md`, and old plan/PRD templates. Any `.agents/skills/ralph` directory is treated as retired upstream content, even if it was locally edited; restore it from `.agents/.dot-agents-backup/` and rename it only if you intentionally want to keep a custom skill with that behavior. +Existing legacy plan and PRD documents and `.agents/research/` content are preserved on sync. Retired Ralph support is backed up and removed so stale guidance does not conflict with the new workflow. This includes `.agents/skills/ralph`, `.agents/plans/AGENTS.md`, `.agents/prds/AGENTS.md`, and old plan/PRD templates. Any `.agents/skills/ralph` directory is treated as retired upstream content, even if it was locally edited; restore it from `.agents/.dot-agents-backup/` and rename it only if you intentionally want to keep a custom skill with that behavior. v0.3.0 does not ship a Ralph compatibility layer, alias, or stub skill. Pin to `v0.2.0` only if you need the old runner workflow for an existing project. Use `--diff` before syncing to preview pending installs, updates, removals, and conflicts without modifying files; it exits non-zero when any change is pending. Use `--write-conflicts` to write conflicts beside the original: Markdown conflicts use `file.dot-agents.md`, while other files use `file.ext.dot-agents.new`. -The preferred external-reference path is now `.agents/references/`. Existing `.agents/reference/` checkouts remain ignored so large local clones are not accidentally committed. Rename them manually when convenient. +External reference checkouts now live under `.agents/references/`. The deprecated singular `.agents/reference/` path is no longer ignored, so rename any existing `.agents/reference/` checkout to `.agents/references/` to keep large local clones out of version control. ## Migrate One Legacy Plan diff --git a/test/fixtures/sample-archive.tar.gz b/test/fixtures/sample-archive.tar.gz index 6471877523cce8ea0ce712f827874f1df85f139a..081f3b87d40b4ff65fc1e8e320b1a6db4f4ca0cc 100644 GIT binary patch literal 19361 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 A{{R30 literal 19374 zcmX_nV|XP^7j10Yb~3ST+qRtvCpxih+qN~)WMbQx*qHd-%=_JYf1a*g`*iQF>Syh> zRuMPnu-i(Z`tC}tm zR}0w_85!9#eq4$=V&Wj#Jl@MD;Keh5*17y)PcKhCcEUe98; z(65n304Q{O-SwY@@0COOM!U$LpTyA`o$hXK1w@U*fIuOjKiNdT%nop;*I2tzid;!k z(!`n6Z{zxR{pZw<-=k+fH1Kt0Zs%jh2gf|ovefTwA%5P&yyN!hc|iZQUW59if2&5L zA1(i?5t(g)yc{U0fnerI(_igwxM(-EZdt2oLqQaNn2wx5H5$S$kkHI`{^l>b%A zJ5w8|=UxC@PCuD6_da|O;sK_{>j_=-3Gmhof9Jlt(AEr_HrN31YRR6WJnZ*wU9ZBt z+mTfz1qz(8%K$6+y#T((j2}wlfJfcx1=_=Yjgr$lBOh1vKUJDz0AxXhdEiI==lw~) zrUSbk`khhvRt?rUkZ%63sow|S<1Y}{A6dM`^;X{==h1zBzHhxN3HBKety%&@rik$! zAs5{QW%$+59vmUK@Xd;LQ~M!UIVP9_L-+)c)Y}o#`aGDJ7emP})>__nJ<(vQqckjN zh34ar5iY~z0WK8uS82E#9@ntrZoVnbD6H<{{H&m;0=tWRl6IU7m#3}Hqv;4)eJ=3= zaoEKE@AS872E&a{9k8L(C^H?N>XhL*FAC(!!6fbgmy}^-5t)nl1Cd=o09d`K4-HfB z&1MRB0%x4<-vyc!6?HVd{3H{Zo~B|iI{h@)sHsG^0<`s2*6%_HbTr7mFNlOPUpYEIFyv zG%(6h$ARQTLBrp9BH7SEiR<5a=DbU4zUES-(*}|f;aaFDzwpyti2Sz4LeIgNKCjxf(bTJvb#U=!TBiOIWa=-msw{m|{lqF$X zI*hlOgJ)!}^ZbX}S%7R?16bPxc$HPojUw}VC)~)UgK>U3EhZXuwK|>l zHN@M@{X2Ryfpa+fC*iN3W0!sdcRrt?F(B?0xF>4nM$EnGy&yb-Ef}`ySKvorI8<+8 zYRQ*q&fL_XAc{wS!XoMW6g56Dy3`khT^+W!kgu)il7XM32`^-ur*?|g`?Sae=CJK z!OcK+th;a>J-KRHN%k5fRE%b35)XK1*U{|H$3p8?%`AE1P z$_;C+Fxk~X_bZyD&72C@KS|PD@+`NV$!eh!|B;)1y`uIK)+x9cQxm5BBXUCr!|yo4 z+(C~T0D`M~ZIkQPwI81_?zEla>EWe+O->6oW#a-G&Dtc2_S=8oUFBf{p4?(|(wf4@ zap&@oV4DqRVoe>HF~RFn2UCkF zjENd29?D7vi0Dv%QnMtU5ZSpJyP@6%AlAsMwfVyri*%wi*ijFV4uOfe!4&!NW2vy> z?IpYg9t(f$yCFcndF+pblh$Ks$-qMOwx0ZlqpW z`3Bm{djUzFkg6odnA<6Wft%KQ-3U=PdTml6vzV-*y2ORpQwn2r_Y$Z<9x_gBSSMqoFCC-}b)g z+Z+EVzznXKssPR5Z?ajH^oAE7;7&Kw4GACyq4lRpiEdtayceRB-!#LY*Z{PiKkmOf zaa3{xeHLw=UUoii1CK8Id2=mYKHHPnFW>7m?6~kAHG3O?-p{A&ul4G%f7eFuo{TPS ztJPKkwPaISz;UTs#!er6xe36dZR;}KVSj3g=;v29tdH{VyIU^<^LIwQ%eI_wFHV>? zUGFQl%UQ8gUjffw0oi7=KGtSGUXYtO{u^$4*OC#^_{4zpbcU&BbO0LJEy8{5*!~Yt z7=3p05ogE&m!=^;xT>Z!NrAOwOI+o@0Zdi3-oGnpVxLApFnl(VvlL*T3O* zv0is{%XLlwT8WOlz?DB;o(^Uxop$G=AqZtx#Qt%lFQ8j3Arpv}JUR%`6p-EIE) zrQ}zsDZY?hu_F8`U^^3evJ^=BD%1jGJnU!6FB=DN8(nJFMgZS$7A7Bo+nT_ahaKzX z`WGN4{9Ao$iN3IM>D|$6fg?dkU5xk)Jo6^8gyis8aw5JC4x^@IQV_}L0jlKg-RNNR z5F6&J3kpS^SYn5wI|)+^v~|{M11sDg_j9gHqlh2Js&UNx4|3g}c`@oF^&|wRKRqdJx`0~M%f53o!$7G7%Q>OYq`q=a$6}zvGTg^C-MsyalEig?IHw~i z(A{?AL+D?gzyI=F|1Zy9piL3bh!p7e!fpW6vvYK8(`AAKz4=+L^H9(9+8O_EVyiMx zZwz20xJ3e->t+8tH~Q_cU$gfHsH5<;U8Hic5`b5e&}l2crL$VmPd%BeDqwZn#?%z{ zl<51{J}GT2b0ezwgN5JeM8`#Q=3y0X0e()@Qfj)lN#?7u>FR0`?9^^<^Jone6Q zvklS*`O?lB%+0?)ss7p!)zYp<{k6m%J4A$EeaYoU1tS3H*{b$6@V{3!c(+6NuZ`+w z1pYMp_w|@c0P40%R_if1jKd((5^W}h39tToPjbKR02QUMZm8S9i!~YNs_@CSe*1sy;O~^ZDTsI@7_{icy zA!K5^OvpigJsJ-AZfx<5dLe4Vg!DDHG~qX93B+m{INfBz1~?R5o_-lxHs{%wb7oN=f!W+sjNhqkheR!uL0!5Vg^C+4kS(*Ac6KbM$> zl>B{UOc#tUD=Th&1~>Jx_bNK;5V- zLz{P?b>~qG_n^JWaKjnr+{A5QX)SB$lvgS#f0hRl!gFCMf;bpNYB|CPL{lKuhr8Ea zt_F~DF7mm}h-SIviS!H^4i{cZ`DIbPE9(q#s#zOFIzVxms}F?XO<9R?+AL89QT36} zO7?;lq@Ez!1LY<4eJr;N+IDW;BIig#6jeVuBaf;qXpJ;zFL@9l?An%B3fobAL0)6K z&d;Uo`jfv?pb=L#Y*(4u9g?dHQtIhPgoW3%#O zCd?qC87Vx|BDGn?U#P9P9o}3D+aJ0Vts^zK& zeHn}(32!*c$#Ng)CsN#OPQHRgUsEcSD*%$h5R9BKRBHx~8i7^Cn$KKz3)osqi6RoQ zhmcw%YM{d93@(b0TSa164Irr4HlAtw&RqY1Wky#3QUA3^(otgE9>5bLIPA>csg20c z87wbfb~sFF#zU7MH-Y+2FDwf7{in^S{A@T)Tb8!lL?9k?ljl{Z$|NKJ!jh_l7}RXU zx*HrW3LjKZ_{T3>lS**(Wi8JT*(>M(5HciV7-f6~WH*msuhgZ{pb*Ti{H$I+nTVQ{ zYLIQLaSF0+Jp5^B^u#9d5Ydch!K1kvY*!pC2X||G?7#^g3+-jLVDyb-a*k!c{W$~- z>?|`B@G?G;{&;14QAN;s3z~u#b7{HcOp8`o5qO#_G!Ft9q7KOzp|RP^_z`Yt_PG4G zNO)9rvpkiMe#2q}#3xXxMAai|Ys3R|deKmRA06L8uipYn>!eE~hd~LA<5{_+tVXl8 z+ytVbunGD~OApDCxCGV759aFxOzfz!w&!3dnFF=I+)Fcj!h8n#Oyfj9qLps0LM}cO zcQ3KRyg!?V%RV6-lmTxo=5K>Ap@UZk>(xcf_qxBAGR(|s?6QM6kB6aLlHl3Bl5#bw z3Xvs1Dkr>xIJ%3Sl2|0);5MC`Hy~X*jIa!={A`zD-yBQEnppv1C! z2k~&6Z=0yTt>t_LcTYDoXnpx2f5`-2O4(ZTTaW;Ly>hO(e9$25dmH#F#c@^cUgP;- zzR}myLC)_VqwNs4V{+4dJKU8wnb~;YnsL-7lEq4#U@#5p**on%UKkir|Ise^-w^-N zE^5w5H^1=jBgw?d2d&&;i0vIW9{6y17M*hVtF#Drp~yjKPp{+#6Uk5c=C3<^IJj#anZJUCR3C9F7!>LLu$!rZ(mr9j^;4sffuQ<<%K z0*NpMAKqBP_q2h1ylhQYh4^`WZ{l+cx3SX@k2PkoUO7S>^+BrQAbaS|3%lrG;AO!R z3@fR zXL1|L)WS^}@39~l@7rAq=K`?kOm<|D7*4Qtb73{uKF7s!Rj_Iep@OTS#WgYQk^iJn zePX&PBip_)=^GH`OsElliFvs=tkj8Wk61+evs4KZIO=BZZ|qYX$kV|v}W9)M?2(4K~qy`p@NpjOe0$LaS z%f8W%5!&A9a4Zi$@dN6X>SEYsJip8Z60s3^hAy>+x`uZ%EHKp_3un(21ec{3|2gSE z(yfQDE~597y^Z9RQ5aQ=v`YmWS(c-kb}#c`Y=BMd+i8kCKF;1&PoZ$$yY?zo2&~ik zoy75u`ELnvL6A@H?-BMWuRof^2vE{3Bo48?ny%(i&wi)ja>NwM>xZl&Ed>w$1i6$4 zAr4Z@xS|-8S7&1mD8!e_gv*pMmuD2^MgO}=B%HX$Lt;^um)>xdgU%@u2tfsb$cT}Q zv~}W}bKK{pi+n!-eX*#+n>+G%4&|CKO|bTvh1EjeKeC+pZ+tI{{2aah`Hil5n;yto zSS*gQEQpkG*qphT_^eqDcY((`kpz3BvH}m%coGGKwgpDN5F$AK6p^Sk1da3_D2$`e z4?|yL2%1=I$CC37bq|)O5Sn3Ovp;aYWVfd6^7o)5czIn`umdXSY2j&p9OhiJgctRD zzm|d}-!nSk&aYRmkQTUd$nd3T|hCDbNXId2&lh1i}++Btc?-I6>r6c)^X`0-kqZ zhMhvtU3|`1S;O5ho?~rK0wZt>eoMH~is{ZK>NK2G4kI+>Ja{3-8}}9W(G!N?{kANF z=SHDyGQJ#!bAEt%Dag+%dlBI=)+5$E-cgd~am8}%1+(#8NVBh$E<_kI?l|^$mXRb_ zhd@j?L3zRZb4e|%Mv_N^4@=RQL}jE#8@z-NzQP!QS71KLm1H+Ci$|7Pf$&}YC1NDG zCnCErjx@_|&KP7E<}`pNG^DIXAIS%m@=SjGDJw5R+S$Q1aH_%mj{?{#S3?L|J!@+z zM(7{u#D`b1TY-!Kj8OJ+@=YNrVKOESLJh8lZu|0ON?DFOo?G;ypIYWwvhNd;;Q7o^ zk-q)`?x~l#7?~(;k!T)5Kkd=b(n9tTxpgK7gWMoOI#zJnby{HO+6Gr8bPUL8MG+K` zVW*>uj3B>_eKNa?1n6QEQ`2JL`GNXHfvyx%{<3gYv_pq3WvB!RC*@-22vTa%gN&*- zcNVWt!tK0|7a6pJoZ-s6HGd(Mc1iFlbE|?-J0Fl2!M3tf^e69KKDJ!iw*_CzFl}!O z;*VMq+~>WtQYghD6JB}6GM~L0Lvl!vR!Iv<-_cw4z@jEupww9@L--x2+7Ydk;5sBK zv^oIma)8(>FrWpR1^R@V7j&#bh5#xI8?>28Gh?!hR z9gT?QcU}iQ-HO!7k?YVbQa_&eC%+}{W^%>aibO7oQD7MM5ZDJL!Kbl_bcX#ynC1pn z!V$cqJcEYg&t3MIX$51*n*V19>3zD9j|MR*ixbr%t+;(xY(N8oAuu%U)lD>Z?$abD zLPgR?`zbt1{^M#-IYYeG2pyt~y~lX*z<6Mfkl4S+-e8iyN1M9f30L zxXcY4stva|C`##gAL6X~Ja+5UKJ`q?Wh0#0{<4&o{P}*H0ND|#J!S!?1#~UNvZ@Em zQ0cd3uU6+rm&EJG5>X?xDVc3afq3GC$O?qmo731>cJT^GJ+aNt;D@Mn1q>D8I4JfL z7FW}Lgaf|&I^>$kaG7OW#Y3&J=7k@M>2;vA(=8YYPaD!FachGcI`jE;_mjeb+@uYp zA&pIuc_^5d_$j|r_Xke==gDq~9nJ0&6}}j_UC7;$ml;`A6X0#d0@(uqKRe!Dcl)zg zd;fx0lVr-tG*47V(eSZ zh=d<(jt;ngT`wofayDffkYh{^!j(D_Rl2y>D z$b%$P4=Cwt7F=xV^*4X8v{37b+2Nx_ex95$Oy? zN=UN+D5VNl)JbUX@}y|CumEF@96aX0`ot>IZI_BLtCA2u!W@Z1;ZO1RpQQ`b=}^ zl(+>%7deo9*aZFLCstWyja)7lAjFHsNxUf0xRXDTh>Jd*`H*@6t5`F$qqGRgD(}8U zLu|Lk-J5dIKt4A@MJw+jq$rodIS0CD@oKWR9C!@;9L9t+)g*g*Lld0}o|60VL~6AU zp}g8AOY!NSHw(j$1jCNE8#__?<%kML%qI%{Ebab*>-7kOV&#DR4(7R0P-20`RK^Ec zPXYIlyoV9Z;p*3l%~U&B9K0Az9Q z)Dnxs{*5!xbfGW0O7HO>>-8Vs<46wtHUXXXb#?wD|BGllT8McA+J3bbsK8^?l95y3 zQ+WW_0-zQuyVvd(fH!6OVI(0t1DvnSju($-5nu_v_Ip(B{OXD$iQv zSI#C&SA}1Y}*j(qW64 zLnOz-QmeiGqf-i#4ndcjwcJ&6C9tX1*Tx)=Qb2Q?0vGuGXm?5~D>LBdIOzshU}9{$ z(w}SM7ZP+ILPYUSd!KFCHECDzWf^2G3zGcNycs2T2@VBE$Y%c8FD zlI{#Ps6%<=h1@-{H4BI;S zlp92nDQn+_#Tn_!{*#&X18RHCAXs(XJO~|$7!sz9zapI7?SUH%_G42o=a_0k; zA9qLwbbxvTI#}NyW^O+Mp+4}aE3{BsW!j#~08qDc#ktY+ABQr(>YyvAn0TX#O`6}3aU1R0b)KeFT+wssl?K7#RiMlwtZhZ*91nv_SCgMDhH?0p@%e;2y{uwfh#+RLub*kr{= zf7h0jVrV?F!zSw?2IJ1UgubAS7r0>TSXC7nv3ijVsLLcC?p!#mx%MBVei&xryJH_E zKG7Ft3I_RbznO!84Yy)d7+;K?pf-h)@*&kic^JA0lIGn}F7VJ0_sM%ZDHnA-IQ<4y z2c4uDRq5*oW?FRGeid|<`2BT6>Pyj#6Dc(ymp(?3A-Z zDkMv6kd(0wRTV5)$EbGYI0Jk4O0O3=6~9cM8`QD^`7o-Sa39;CGWtmbPNM|AyOGba z_34N-p}HQg!3tg<)&>X*lAr5rw1OhkBun7)kCy;TMjQ@M1{s1~KT3f?)lKhi-%bfZ z@2IYva0~3VB9>7$o=)=bbJ{X8#G^@;JT50z#%j2U(!VVBS18a60Xn!{f&(TrFgI3| z#Jy6`Exu3|PeNqcCh0Jiuu)D zt|r6?C7{F*NZR()k+36>#IU&`TcQs*Tz@*V2p#1>v|8;lqfb(?5qLETd!Z?;>|4|pQc{OK3Q^%`&S}~wWTKowm?{=B!$VrvN#9z+)H6fDwl-# zb!EPfx#6g~Y!$tO`ZyF}V9zp9Y%8jW`RDki!wBeXLq88}J0Iy*(~iH#557!F0;Q%t z8Dx=zx13rEVi)K$=Eh~m7;G{!*SFQ-ga=X1>UCJuH7_7~Nt0p+MK2Bh&L$E^Z>}{N z6}OPRvuh?+G17}hxVi3k$*D!yDo2!Y1Nf9&HK^J#N35nA6|4`drQ-SVv zgZd%?iqm`2G~!5Y8eu$0=<#BNVk#2gqAe#z&`U zB34$Zp(j>{5MwO0qcFqdCvg901{^X#^NN!nsi>Iiq}N}C{x!vY<;)TgubSjsr*Mt{ z;k{k`RjkM!eNsw%Qst?AKkii(110A;EP~MhR3C@f7S9eHmwbXa6b^+P365R7vjG~1 zH=o_d^`k=f)V>2Q8BW4D)6#(Fxsv7oUp92pdI6vcI>W#8YdT@weHoz;KAdWGcI+{4 zzpBxd``$l!)*tY`lMw@4sl>cB(oD{aFaijy^Lh8ay);`uynp@RU+47(z+AVOeCylX z=3W2T+xkho*V=X+)_(ohbN2%&O-fBP&JY>Qt9Ns_LYYNoImjSNv3xUj&lLi=I39KM z-HgLA5n;;IHGR@nMONxoN2pjJ^QADReG z63WpZdvpZ!XjMA_Y9+(H09DHQ#(?nmft?RVxevh0mh;Ph$|;z$QZg_*SCaHyD6ED3 zgQ@p*rWEMi%iH?4%GY$ZR0}8CAv8vvQ0N?Qvi=p(N8-bDl*;8UsQ$cL{6N0Ui9-M`q;GYiY5PS0 z$!dU+#j%7*B3G23vD-=FiMd-yOXSw6Pu+X`V{RN8}IUV;=*)lsE3zVFf;aq?|JFhHn^2QrEO}>OLWLmxj*2@nNw6 zVPY0Pxj0}zbbxyT$}Yk`^&zh8cGs}{R@0F0s9m_OfB$eBFS^ZG!q2=3!%>RALM-=p zDTpN+v2r2rsd^oH_ha8yaB6csKX=pctEFE}n`d_iRUR=^MyPBm;5%cNGx4riyCxat-`g{l2*E0Zy$R_Y^lL#ssFLSgf@qbK zSAiZrxC8bs7vi>E48oy482wfHgC#|`VuP5U^3$V~rEAi`78-&z+G{sR*F1lFHWw9r z^zu=wg03S)`I|o={-h0-RBX!wHMy#wvNE*fhoJ*XnEMQRkaI14Bj5-F%F?;LPM1@? zj%1M$LliJ-=+$j;;ncB>BR6+$kWivrptnC%B)!~I1{>SClvg6@+q!ClkHK1dGvsZIR?)HTE>mw^i>e*d1XD>t&^W01K&jj^rQ>~eag=~Zs zo$|cv9gN^A?PWPl zouO41dvj>kALSq7IgLq3-SbNfs8h1mGPkqa1P9+4+r6r6SzXMSXHmlMe~(@r;4~$6 zZ8M8wdf~;WtTf5#Iu4>u`iMdVHEyaRXo2FgS$ij$wp5PcOeh=R+#;MMSLjl-_S#&d zXRiBDDN}l~1$NRb;DRY{(2UdOG=Ec05s*?87h`Mu-GEaU6Nl6Wopb*%h!{n~DOYxM z4XE^;9Cp*Ih&`LXHPW5ZEc~a*Km3zZlz^3B&MJb;>7VuIK-(`p=F6OO@Y$|ezO~J8 z0VMX<&HMb{7OGx%RICF&TA~6SC{KSoaVF7ha)(x?e})#IbS1_}=uidXbds;N8_YB% z!7%Twx!zV&8gJl4JN5g$emb9rZqYs-hTw>2Nql(Wpuci zkN%OlPMtp)u^$hpkCkmUy&UL3W714y>Lx?4TbDiX^K_3fjnR%}8I~IqM`1FdFkFqU zKG~yGgS4Mf`LICst(i$H<$K*)&kD^Q2H12w1o7T%>6U@prMdG6yN}#9KEFoN~;hMLArC(}(KLpFUgIso(%xDp=>HRzNv5RJA zo38?MR42^r58Uu>>zZ_`VqJm8T@#of^()%=^+F58{UbW$qo8kaiw|M;8XeFqsTL7f zUF$1XmD(4bA?i9oqJo|y5<`y(^+AW;{VrQ6TPLr4d%UT^;X(A02QcxeGn?IFFNB_0 z^Kci|j#(yna5ewAvYK$DT=v5cIaKV7_DZ;H86#kp8Z7Tfl6dAzKz>DquI7dVNn(EO z22y;!tO{Q8GyyoBfo@lbAI1-II3vGDj>>QIt6RN`*K9ov?fsv_t&Sks1dV`rB=K%A zY)|-!c7lAKmX3EQ3p=2er|i{{*+|VB%`vT+IEkDJ+=W>k`&f1I;9A!;o)V&~N7 zE7Y$uZylEf=wLX}m?a2(D@!ZKhojYe-Q4e1AsCa}+xjxB7zwm95WsC2gDl`0;2KR- z*Smsuf-O${nZHW6;dHcMH9AYo{IeLGF=_YCUf-uFu*B1J5A-8C2iXmQ?DPcKWwuKH zP5<%;O@-wemBi|u05)PJ8^7EzbPxUUyjv2$Zkm7YulBh*%-0=_65Q9FDQ{?h?AIOW z{IqhQg%+^$VW)z#?i7&SI{4{IdHVU#-#HNxcgk6Wyztmr|FSRW>et*w9m(F-dFd(9 zLjWJH(TWSH)`qgRbjlm|Kwmk^fd`RJT=;QaCEFi`pROHN;cTGV4%dpKP+HfTrlHDM zw8cIJ%&$CrkEP-3jQni_+acHS!o~OUy_N{}xmyNs;QG*v-2En2>aM@RsawW@DPyg0 z$~Nog;oz@uB(FOG?0F)4L;pkUgf$&s#!u1Q?nQ!kV-H}Ru{NQYj1=V|iZ3}S_6Lha zu7@z2->x3IK6#ZsrzyK2ISmGz6IJ|ezCdj zNf17!@a&(A#oBXBMVZS!s$)_b2Ncjs?*S44bVo;X=~JOPjqPgnAW&1#4p?+j`oMa39G^aNjT06$Dk-QHOf<_N@=zB`~=54kR~uFjI=M3b--P7;cWd ztRPATClMKP8z2uKLQK`L<(5DfTO=AJ9}gkwN4&tcQj>-8>mR#bvd+J%BD5)+bN zaybcbw$}G@iTla<+4V+?bjg65_{7dt6*WF45zdZd%0TruvPkAa z5X(}G@4Saw1AQc$&>rZ&i98W$Gjg=L4}tlxAU7fWMX(ji&iZXk78nQ?xZoW;s0HKKeW@Vz!&sJ{84%r=*LMUS@B%3erMro`GYdbLV@3;!=;mvF6 z=yRP-@$#_sp@)4jYgKk_t{(iBwe^95Sd5IptXeBdWUNn`|}jmOSO^ce-f-cMHPY2)=!5w zj|>vJg7W#bKnunyU~exqQb^It=(9y;mT$v7&3Qmwl}(l3S$Y~WWMEn@mMN~zbrx^p z-*Bxr*9nK3?+LjK%JlmPw=)PypJh*Y5|shQ0@tk)*cj(y&Bs%;Ep787n1|V&WI|Hi z8m!1qBX&=fX1{bZ<42gs^HrznF*R09bG}jOse%#DJX`v~JMD)2+Jw+g(GjIUILJWu z*y#iPuxD1R$}t!h+KW^OdnAemGu-`n6ndPyCQ;nXA9ha@t@3wTWu=oCCS`s(GYM;w z9-$WS^6Uld1a!A13MNXnaMqEH0*e^;L>*XO z?kx&gQNNv}LS^so-H!Qt!vhUDXg2oL)BqJyCIYq0n%MM!CA zmoqp_Gw254Gw7R8Dc!iFK)CEHYl*Zbde-3L+GMC7&BGl6Crp>3S3o{a4x`$(HR7Xk z>;CL}TRB26MNwnCH_YNl==?!|%C~0J$q$2QQzW`$HbM3Nb4OYsF$!xArf^x~tHXf;D-Y_0v$<@ue1b&-b-hc_7;7ZyptSbkk4r(spY?(6iyU!$% zL=M}aRd2kaK+2lChPiAMnRAjuP{ z`@0zewaIAru^F@}M_rGp!c?cKstTr1$8G%Y$|srW6i-k!l$R&uBD7cxCQefQ6y6|% z3{EB;J%vPUfOJ8(a&}CY+iKIyJ0twbg-lqPzQXS^?-8_H5-|5op~_&_hBV{oS=IP|PAQV#AVZDyX~W z#64r->DAcej6|d33hm1%!=5`hUN@sy(=;aUh{enyUf$C{e;W>aqfusLaV)cwM&6L9 zq&XNw9~KnSL^crS;5ulYsP>uJXYt{-2BEDCE6PVQsT^e< z34Vm*+#p_RJ2&Pw*AU6qSG>R* z{w)(Z4N?@z(#QxK5TfpXU)IwM&Xg)4(BmPxE8c)%T{$TmO8f3RnQofsTlXY94ecJS zk%vjpKbh30J43tg_y^9MF-o342=kb+|$0`2*hv{@(PZRjv%7Cbnc z_{1WsPJv2r#^Jk1++uCicku@+nG*qQz(;z2!|qrZYz`qQds7q#p8_44JnC`6F?!*;&p+Nn{wa?(k zS4yto>Xy>u)05I8HoENHRxo2z^st)p?gx0eHFQ7zA%8gPZWSSjFS;5X#a+zKAw%Cd zfg~~;m(=x`T3_>Pef)f!`xU&UwNpz$7G^%$HnHFAd$dCxP^AUcCmHP=kzb^`RE!dWpep zWToHI_xu2lms(+~L2hoYp>B~fW=CjI;c!@8yy*w}$!b1JC zHWQezR|}f@pz4?7;=AX@u6|#IBcE?w#JA?>69Vto!yohW>ou0S{OepEf_?Mzve%mh zGVDivH=?eqJKu4r@rUcfA8tQ&*^&8k?a=#EUwA4(yON1PIetvLoK48e+`f3%2_Vv# zn2jYFH4EozGNM{(m}BMWw5BlS*?^5j$lBs%BL*UD41psoc=oAo#fBX0 zm&)V#{8Z%tO#fP(Q*rm$=~YE_M;H?DZwIvey}I0ko*1CcJaQQg1rz~n>R>ESQi>`-Zx?@~+={8a^Yjy@ax*@dVxCrh+ zM@b@13K(lX4E;7!$!+niTqo6^m_uew!(=QSU2`^^{2uR;R$iwnz9%H*5+Xj10QBSn zu6}f(llC5`D@7sv_)2<*XtbR2LTW&RJ}w8k*FTcJIGa?M_o>Jf=l=wH3WfDUDAx!U zBW$EELm5$EAxk;n&^$jevy#r-42e+9s70k-(PXHT5n6>A;x`tj8RYVN8R%(93DPDf zG2iAmyP6E-EhHbHtdF<^8_If;@lU{^Z)n(&bO6&6dSfO_Jh=|fkZRYy{(sk01fMLw zS^FBkbDS0iFa>$fz8%cqKiMcwigjdTIT>y}TS8>u*KWojMl zWhr$w#nO~rPlkDO+-e0I1(JO`jAULWO(+01vd?FJApZ1A>N2CQT+q2E7i0bYJ{ICH zBg16nu0K;;Al2g==XaY}K2FStp!HN2d&*1FtZAMC@J!n{oa@cvxRpqqpQu0Z!MD_= z9eVd5mDLK!3o_imMKOoV*)igM19=($XA<%OavLB1;ko|z>l=abK8q^G*h=>*U6cX) zP0Q2jF%kCJY@sWr>^{;l-3V05hSBC;ZXNyzQudpzqwOD$Yaf(wgXOP%t>ae(T5=G~ z$^tCrSpEpqa8wLDt|MNy#vucvXC=_q# zwoSkxl*}}^K8t6e5h6c7&u%SDmtT=dM`oY6#0HV;gJQJ(72iJV!T5mbMTf5`ES4Gb z+H+WMaMPiX6;}ydZ=Q&ExWz;H2oL9&+mN9gb;V)37Cu>ZEY02-{)g}0A8hX)R{{LQ z>%acB`gwv3XgTA?V21B^|36Fr!|@kCs#_lJ*2ePZKh<`lUFd&Sl8W=6N1bk@|Mc+Z zPJCeb^PhU7-7L<3R*|Nj|I}Kw%~oTxS)Bho_;e%vE2`hPV;l46AL(Uc{cqy=PwQSr zI43=F`ky2JnZOEnY2#-9zp3(Ht6lj2ttJ)n-=j_o%71s_19Rzriu_kC{Qp;yX4wDK znyt-FasSK1PdC#4y{!Io>A&3snx9zz8?D0rcO@wsK~0cHBRe)ym_BmJ&xBOtU|BtO zF&BvsE5l^`KXx`a>;)q{TEvr2dve_|v@Q|DOBK~LWA)-Ck^kp&7HFAb3M>3+* zJo@pETg?QEra?$cI(<=-v^tzuAP3mA-@|<9sfz^nK9ql(`TZ zeyJOwGmce`m0m=m_LP{9E)IqVb8|2}li%!B#!uHczg+2i)%B$$8LuwF5DJ!;87dw3 zv2zLfV1*orFB8}xX1{23U?rbe^hpY1m))n(-;NJsa)D!`SdJ8qv&+&!;z<+e@FW8v z@+f2w;bR6y_)`H%IU5>4oshLfzMih3I6j(XwbQ+@ghv=w8+4YdSh8~quqw9|nAXdBABO29i zo!THo`Ae${PyiyTz6{VN8^2U&sXVi`6walnl-Ag# zpa(?iDFX)JI2>#CjH5jo9GG4!(p(cXe7fjfQll+ znh+2iID)uujOTsYch+F~Bzh=HA%07FxGSl@Z&$~koy03IfQEC3rJV5@w?nn8_=q?h zl!C`;mYp2X03XX}AyFQ|uyhvks|y`9JGNP|^x708u}5Yy6h49(1K`mPBOV((2?=Ct zW-&!XbD3I2Y&lMLDoeRO5=1$ILzJBA;%SHs_%ap)c#Si{ewm)eX5&-1ukXmd?sb06 zqdfHrR0wE%!E^ZcG@6`{-XL%(2GBlx8w-+HIFPT*I3t@?dag5aZj^a%#nf{fqa;Y} zXg=w+jZoM}ev1gS1?aG^P|LD@N`XM42`%y%ojT>p6ahfR4C&c^z)^?Ndl(gOgo#Hh z2lOOGW3;J(Wi`quyR1~cI1N5g1PL_Ra|jSw>@R5}Y>JhTl^q6#imk><)a(w$Iu+OT6mS*Sc;u-RAbb!8egMSka>yxU zNjxT8Gtf97yQF7EXc#EY;g4z++*h`E)=wP2USb3rk|kzBzJzY}YB3$zATubIGqJFe zb2J4)PNOjq0MM7U!~zL}k0xD*P#D45iji(m$Oa4=x(E!Z%}4aaXcPSjhLwh@k3i5v za60U8T~gK)+6u+x&?nIdzDeyvtXPDJhoDTn)K(zFLb3sMQXa;(qQqG)T?%T1#we1A zN5w!$<9A(O1X!Twjw1idJ4>5Zs7qvs#5^n&>M{XKLiBJaZ)KwM#Dl@w%$VgPawA^o z{HO9!#l0a8v~(NG+kZ6Rso4LoBo+GqN1Ya;|MVQ-R(xQ2`;TU)(<$`-t4K5KKRVTV zr_ldDg0v9*XQ}=c#vseve>7^%p z`cH+yMft$;_8;w5wO+`7t4OotKiGk{3;W-PpO&ZpWmo_C^p8I#*8f(cSpQd&(hC@k z_PLW37D&+r1oo=N6YyN+?;{(gf|MgC@u>W33 znj!zUo9$Y&xc}|pryJ@2URM7FP zmvbpcw`^m1`M+Lm7XBZrNrn9XsM7-UpY8%~$p@B~{~N7N5&wN9X}bSswchH~YlZy( z@Y5pe|J_#q1?2zsHTl2YXcX)JD$*17W|}hXY+mou^R0VWpq->XOq%zx!0{wP$?88R__$@-%3&;|2^uo z0R5*z;4S&UE%d)_jQ>^0e_uY$lK)zp&BlvD{(JCg0s6n=>c5En$7KA!TBlanf2<^> z_8&OS1sOiJH2eHVMMN^OKW=XYb_@Bx+ARD(R+9?(|52y8^nWe($MSsO7V>|qQ}}vsuXh4?fMM|2wb#i}-(D^Z#nsi}T-=q*VUbGhUG5V@eCi|6knxYl{D8 ztMLC^Q7YvBN1c|C|8LC)ZXy5I3;)m6q-pYhb91v@ebH$Z@n0T(n!oC2`64KK`HX#i*f09^A)7XSbN diff --git a/test/integration/install.bats b/test/integration/install.bats index 8df966a..d7e975d 100755 --- a/test/integration/install.bats +++ b/test/integration/install.bats @@ -656,7 +656,7 @@ teardown() { [ ! -d ".agents/.dot-agents-backup" ] } -@test "sync preserves legacy singular reference directory ignore" { +@test "sync drops deprecated singular reference ignore but preserves content" { bash "$INSTALL_SCRIPT" --yes mkdir -p .agents/reference/legacy-repo echo "legacy" > .agents/reference/legacy-repo/file.txt @@ -664,10 +664,14 @@ teardown() { run bash "$INSTALL_SCRIPT" --yes assert_success + # Sync never deletes user files; the legacy checkout stays on disk. [ -f ".agents/reference/legacy-repo/file.txt" ] + + # The deprecated singular path is no longer ignored; only references/ is. run cat .agents/.gitignore - assert_output --partial "reference/" - assert_output --partial "references/*" + refute_line "reference/" + assert_line "references/*" + assert_line "!references/.gitkeep" } # ===== Task 1: .gitignore entry tests ===== From 8a0d4a031f53647b8d1ba12a21df439aa12c4f40 Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 22:10:08 +0200 Subject: [PATCH 10/12] Simplify landing page content Amp-Thread-ID: https://ampcode.com/threads/T-019ef0ea-fc52-75a7-b2bc-b0ea7098c804 Co-authored-by: Amp --- site/index.html | 162 +++++----------------- site/style.css | 354 ++++++------------------------------------------ 2 files changed, 77 insertions(+), 439 deletions(-) diff --git a/site/index.html b/site/index.html index 0a5fc9e..eecddce 100644 --- a/site/index.html +++ b/site/index.html @@ -4,19 +4,19 @@ dot-agents — AI-ready agent workspace - + - + - + @@ -29,19 +29,19 @@ -

AI-ready workspace for any project

+

Durable context for AI coding agents

-

Ship faster with structured AI workflows

-

One command to set up durable work items, research, plans, and handoff prompts—so context survives across agent threads.

+

Make AI coding work survive the next thread

+

dot-agents adds a small .agents/ workspace to any repo: durable work items, research notes, plans, and handoff prompts your agents can reuse.

@@ -58,142 +58,50 @@

Ship faster with structured AI workflows

Review first: curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | less

-

Current: v0.3.0. Need Ralph? v0.2.0 is archived.

-

What you get

+

What it adds

your-project/
-├── AGENTS.md           # Customize for your project
+├── AGENTS.md        # project instructions for agents
 └── .agents/
-    ├── work/           # durable work items
-    ├── research/       # reusable findings
-    ├── references/     # local reference repos
-    └── skills/         # adapt, agent-work, planning, research, tmux
+ ├── work/ # durable work items + ├── research/ # reusable findings + ├── references/ # local reference repos + ├── skills/ # adapt, work items, planning, research + └── scripts/ # sync updates safely
-

Using Claude Code? If .claude/ already exists, install/sync links these skills into .claude/skills/ for project skill discovery.

+

Re-run the installer later to update dot-agents while preserving your work items, research, and customized AGENTS.md.

-
-
-
-
-

Instant Setup

-

One command creates .agents/ with work-item guidance, reusable research, references, and skills.

+
+

How it works

+

Use natural-language prompts to create only the context each task needs.

+
+
+ Run adapt + Fill in AGENTS.md with project commands, structure, and conventions.
-
-
📋
-

Durable Work Items

-

Keep context, plans, progress, decisions, and next actions together.

+
+ Create a new work item for ... + Start durable context under .agents/work/<category>/<slug>/.
-
-
🤖
-

Handoff Prompts

-

Generate paste-ready prompts for fresh implementation threads with clear scope and verification.

+
+ Research ... + Capture technical facts only when they are needed.
-
-
🔬
-

Built-in Research

-

Save work-local findings beside the task and reusable knowledge in .agents/research/.

+
+ Create/refine a plan for ... + Turn context into implementation-ready tasks with acceptance criteria.
-
-
- -
-

The workflow

-
-
-
1
-
- Work item - Create durable context under .agents/work/ -
-
-
-
-
2
-
- Context as needed - Research technical unknowns; use a requirements brief only when behavior needs alignment -
-
-
-
-
3
-
- Plan - Break work into implementation-ready tasks -
-
-
-
-
4
-
- Handoff - Paste a scoped prompt into a fresh thread -
-
-
-

Create only the artifacts that help: research for facts, a requirements brief for alignment, a plan for executable tasks, and progress for continuity.

-
- -
-

Get started in 5 steps

-
-
-
1
-
- Install - curl -fsSL .../install.sh | bash -
-
-
-
2
-
- Adapt - Run adapt -
-
-
-
3
-
- Work item - Create a new work item for [feature] -
-
-
-
4
-
- Plan - Create/refine a plan for [work item] -
-
-
-
5
-
- Handoff - Write a handoff prompt for [work item] -
+
+ Write a handoff prompt for ... + Generate a scoped prompt for a fresh implementation thread that records progress as it works.
-
-

Inspiration

-

- A mindset we like: doing the thing is doing the thing — ship, observe, iterate. -

- -
-
Quickstart diff --git a/site/style.css b/site/style.css index 063b468..706e0d5 100644 --- a/site/style.css +++ b/site/style.css @@ -125,6 +125,16 @@ header { margin: 0 auto; } +.hero-desc code { + font-family: "SF Mono", "Fira Code", "Consolas", monospace; + font-size: 1rem; + color: var(--text); + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 4px; + padding: 0.1rem 0.35rem; +} + /* Install section */ .install { margin: 1rem 0 3rem; @@ -244,31 +254,22 @@ header { border: 1px solid var(--border); } -.install-details { - margin-top: 0.5rem; - font-size: 0.875rem; +.section-intro { + max-width: 640px; + margin: 0 auto 1.25rem; color: var(--text-muted); + font-size: 0.9375rem; text-align: center; } -.install-details summary { - cursor: pointer; - color: var(--accent); -} - -.install-details summary:hover { - text-decoration: underline; -} - -.install-details code { - display: block; - margin-top: 0.5rem; +.section-intro code { font-family: "SF Mono", "Fira Code", "Consolas", monospace; - font-size: 0.8125rem; + font-size: 0.875rem; + color: var(--text); background: var(--bg-secondary); - padding: 0.5rem 0.75rem; - border-radius: 4px; border: 1px solid var(--border); + border-radius: 4px; + padding: 0.15rem 0.35rem; } /* What you get */ @@ -297,320 +298,57 @@ header { color: var(--text-muted); } -/* Features */ -.features { +/* How it works */ +.how-it-works { margin: 3rem 0; -} - -.feature-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 1rem; -} - -.feature-card { - background: var(--bg-secondary); - border: 1px solid var(--border); - border-radius: 12px; - padding: 1.5rem; - transition: - transform var(--t-med) var(--ease-out), - border-color var(--t-med) var(--ease-out), - box-shadow var(--t-med) var(--ease-out), - background var(--t-med) var(--ease-out); -} - -.feature-card:hover { - transform: translateY(-2px); - border-color: rgba(0, 217, 255, 0.25); - box-shadow: 0 0 0 1px rgba(0, 217, 255, 0.08), 0 16px 32px rgba(0, 0, 0, 0.35); - background: linear-gradient(180deg, rgba(0, 217, 255, 0.04), transparent 55%); -} - -.feature-icon { - font-size: 1.5rem; - margin-bottom: 0.75rem; - transition: transform var(--t-med) var(--ease-out); -} - -.feature-card:hover .feature-icon { - transform: translateY(-2px); -} - -.feature-card h3 { - font-size: 1rem; - font-weight: 600; - margin-bottom: 0.5rem; -} - -.feature-card p { - font-size: 0.875rem; - color: var(--text-muted); - line-height: 1.5; -} - -.feature-card .term { - font-size: 0.85rem; - font-weight: 400; -} - -.feature-card .term a { - color: var(--accent); - text-decoration: none; -} - -.feature-card .term a:hover { - text-decoration: underline; -} - -/* Workflow - Timeline/Flow style */ -.workflow { - margin: 4rem 0 3rem; text-align: center; } -.workflow h2 { +.how-it-works h2 { font-size: 1.25rem; font-weight: 600; - margin-bottom: 2rem; - color: var(--text-muted); -} - -.workflow-steps { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 1.5rem; - position: relative; - padding: 0 1rem; -} - -/* Connector line behind steps (desktop) */ -.workflow-steps::before { - content: ""; - position: absolute; - left: 4rem; - right: 4rem; - top: 6px; - height: 2px; - background: linear-gradient(90deg, var(--accent), var(--border) 50%, var(--accent)); - opacity: 0.6; -} - -.step { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.75rem; - background: transparent; - border: none; - padding: 0; - position: relative; - z-index: 1; - transition: transform var(--t-med) var(--ease-out); -} - -.step:hover { - transform: translateY(-2px); -} - -.step-num { - width: 14px; - height: 14px; - background: var(--accent); - border-radius: 50%; - font-size: 0; - color: transparent; - box-shadow: 0 0 0 4px rgba(0, 217, 255, 0.15), 0 0 12px rgba(0, 217, 255, 0.3); - flex-shrink: 0; - transition: - box-shadow var(--t-med) var(--ease-out), - transform var(--t-med) var(--ease-out); -} - -.step:hover .step-num { - transform: scale(1.15); - box-shadow: - 0 0 0 6px rgba(0, 217, 255, 0.18), - 0 0 20px rgba(0, 217, 255, 0.5); -} - -.step-content { - display: flex; - flex-direction: column; - text-align: center; - gap: 0.25rem; -} - -.step-content strong { - font-size: 1rem; - font-weight: 600; - color: var(--text); -} - -.step-content span { - font-size: 0.875rem; - color: var(--text-muted); - line-height: 1.5; -} - -.step-arrow { - display: none; -} - -/* Quickstart - Terminal checklist style */ -.quickstart { - margin: 3rem 0; - text-align: center; - padding: 2rem 1.5rem; - border: 1px solid rgba(42, 42, 58, 0.6); - border-radius: 16px; - background: linear-gradient(180deg, rgba(0, 217, 255, 0.04) 0%, transparent 60%); -} - -.quickstart h2 { - font-size: 1.25rem; - font-weight: 600; - margin-bottom: 1.5rem; + margin-bottom: 0.75rem; color: var(--text-muted); } -.quickstart-steps { +.command-list { display: flex; flex-direction: column; gap: 0.6rem; - max-width: 480px; + max-width: 720px; margin: 0 auto; } -.qs-step { - display: flex; - align-items: center; +.command-row { + display: grid; + grid-template-columns: minmax(190px, 240px) 1fr; gap: 1rem; + align-items: start; background: var(--bg-secondary); border: 1px solid var(--border); border-radius: 10px; - padding: 0.9rem 1.25rem; - position: relative; + padding: 0.95rem 1.1rem; text-align: left; - transition: - transform var(--t-med) var(--ease-out), - border-color var(--t-med) var(--ease-out), - box-shadow var(--t-med) var(--ease-out); -} - -.qs-step:hover { - transform: translateY(-2px); - border-color: rgba(0, 217, 255, 0.3); - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); -} - -/* Cyan accent bar on left */ -.qs-step::before { - content: ""; - position: absolute; - left: 0; - top: 10px; - bottom: 10px; - width: 3px; - background: var(--accent); - border-radius: 999px; - opacity: 0.8; - transition: opacity var(--t-med) var(--ease-out), filter var(--t-med) var(--ease-out); } -.qs-step:hover::before { - opacity: 1; - filter: brightness(1.2); -} - -.qs-num { - width: auto; - height: auto; - background: transparent; - color: var(--text-muted); - border: 1px solid var(--border); - border-radius: 999px; - padding: 0.15rem 0.6rem; - font-size: 0.75rem; - font-weight: 600; - flex-shrink: 0; -} - -.qs-content { - display: flex; - flex-direction: column; - gap: 0.35rem; -} - -.qs-content strong { - font-size: 1rem; - font-weight: 600; - color: var(--text); -} - -.qs-content code { +.command-row code { font-family: "SF Mono", "Fira Code", "Consolas", monospace; - font-size: 0.875rem; + font-size: 0.8125rem; color: var(--accent); - background: var(--bg-card); - border: 1px solid var(--border); - padding: 0.25rem 0.5rem; - border-radius: 5px; - display: inline-block; -} - -/* Inspiration */ -.inspiration { - margin: 3rem 0; - text-align: center; - padding: 2rem 1.5rem; - border: 1px solid rgba(42, 42, 58, 0.6); - border-radius: 16px; - background: linear-gradient(180deg, rgba(124, 58, 237, 0.06) 0%, transparent 60%); } -.inspiration h2 { - font-size: 1.25rem; - font-weight: 600; - margin-bottom: 0.75rem; - color: var(--text-muted); -} - -.inspiration-desc { - max-width: 560px; - margin: 0 auto 1rem; +.command-row span { color: var(--text-muted); - font-size: 1rem; + font-size: 0.875rem; + line-height: 1.5; } -.inspiration-desc em { +.command-row span code { color: var(--text); - font-style: italic; -} - -.inspiration-links { - list-style: none; - padding: 0; - margin: 0; -} - -.inspiration-links li { - font-size: 0.9375rem; -} - -.inspiration-links a { - color: var(--accent); - text-decoration: none; - transition: color var(--t-fast); -} - -.inspiration-links a:hover { - text-decoration: underline; -} - -.muted { - color: var(--text-muted); - font-size: 0.875rem; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 4px; + padding: 0.1rem 0.3rem; } /* CTA */ @@ -696,17 +434,9 @@ footer a:hover { font-size: 1rem; } - .feature-grid { + .command-row { grid-template-columns: 1fr; - } - - .workflow-steps { - grid-template-columns: 1fr 1fr; - gap: 1.5rem 1rem; - } - - .workflow-steps::before { - display: none; + gap: 0.5rem; } .code-block pre { From b8e52bd0a82c661f4107c6ac9e7dafb0c269b2e1 Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 22:35:34 +0200 Subject: [PATCH 11/12] Clarify optional work item artifact folders Amp-Thread-ID: https://ampcode.com/threads/T-019ef0fe-663d-76bb-bee9-763282de4934 Co-authored-by: Amp --- .agents/skills/agent-work/SKILL.md | 17 ++++++---- .../skills/agent-work/assets/plan-template.md | 6 ++-- .agents/skills/feature-planning/SKILL.md | 29 ++++++++++-------- .agents/skills/research/SKILL.md | 4 ++- .agents/work/AGENTS.md | 11 ++++--- AGENTS.md | 8 ++--- AGENTS.template.md | 23 +++++++++----- QUICKSTART.md | 2 +- docs/concepts.md | 17 +++++----- docs/skills.md | 4 +-- test/fixtures/sample-archive.tar.gz | Bin 19361 -> 19886 bytes 11 files changed, 71 insertions(+), 50 deletions(-) diff --git a/.agents/skills/agent-work/SKILL.md b/.agents/skills/agent-work/SKILL.md index c90c62f..c3b0e57 100644 --- a/.agents/skills/agent-work/SKILL.md +++ b/.agents/skills/agent-work/SKILL.md @@ -7,7 +7,7 @@ description: "Creates and curates .agents/work/ work items. Use for durable inde Create and maintain work items under `.agents/work///` so context, plans, progress, decisions, and handoff prompts stay together for one piece of multi-session work. -A "work item" is a folder; the entries inside `plan.md` are the executable tasks. +A "work item" is a folder; entries inside `plan.md` or focused files under `plans/` are the executable tasks. ## Workflow @@ -19,13 +19,16 @@ A "work item" is a folder; the entries inside `plan.md` are the executable tasks - Create only `index.md` at first; do not add empty support folders. 3. **Place artifacts deliberately** - Use `research.md` for findings specific to this work item. + - Use `research/` for multiple focused research notes specific to this work item. - Use `.agents/research/` for reusable cross-work findings. - Use `prd.md` as a short requirements brief only when alignment is needed. - - Use `plan.md` for implementation-ready tasks; copy `.agents/skills/agent-work/assets/plan-template.md` as a starting point. + - Use `plan.md` for the primary implementation-ready task plan; copy `.agents/skills/agent-work/assets/plan-template.md` as a starting point. + - Use `plans/` for multiple focused implementation plans when one plan file would be too large or when separate phases need independent handoffs. - Use `progress.md` for implementation notes, verification results, blockers, and next action. - Add `decisions/` only when durable decision records are worth linking. 4. **Keep `index.md` current** - Update `Status:`, `Updated:`, `Artifacts`, `Next Action`, and material `Open Questions` as the work item evolves. + - When `plans/` exists, point `index.md` and handoff prompts to the active plan file. - Keep status in `index.md`; do not move work folders between status directories. 5. **Prepare handoffs when needed** - Use `feature-planning` to refine a stale or ambiguous plan. @@ -40,12 +43,12 @@ A "work item" is a folder; the entries inside `plan.md` are the executable tasks - Required file: `index.md` - Status values: `researching`, `planned`, `in-progress`, `blocked`, `completed` - Optional files: `research.md`, `prd.md`, `plan.md`, `progress.md` -- Optional folders: `research/`, `decisions/` +- Optional folders: `research/`, `plans/`, `decisions/` Status meanings: - `researching`: context exists, but no implementation-ready plan exists yet. -- `planned`: `plan.md` exists and is ready for a handoff prompt or implementation. +- `planned`: `plan.md` or `plans/.md` exists and is ready for a handoff prompt or implementation. - `in-progress`: implementation has started. - `blocked`: progress needs input, access, or plan changes before continuing. - `completed`: implementation and verification are done. @@ -69,9 +72,9 @@ Run commands from the repository root. .agents/skills/agent-work/scripts/list-work.sh --status blocked ``` -## Legacy Plan Migration +## Legacy Plans -Existing legacy plan and PRD documents are user content. Do not auto-migrate or delete them. Retired Ralph guidance/templates in those folders may be backed up and removed by sync. +Existing legacy `.agents/plans/` and `.agents/prds/` documents are user content. Do not auto-migrate or delete them. When the user asks to migrate one legacy plan: @@ -82,6 +85,8 @@ When the user asks to migrate one legacy plan: 5. Update `index.md` with status, artifacts, next action, and open questions. 6. Leave legacy files in place unless the user explicitly asks to delete them. +Full upstream guide: [migration-v0.3](https://github.com/colmarius/dot-agents/blob/main/docs/migration-v0.3.md). + ## Templates - `assets/work-index-template.md`: starting point for `index.md` diff --git a/.agents/skills/agent-work/assets/plan-template.md b/.agents/skills/agent-work/assets/plan-template.md index 94173ad..6b2f80b 100644 --- a/.agents/skills/agent-work/assets/plan-template.md +++ b/.agents/skills/agent-work/assets/plan-template.md @@ -1,6 +1,6 @@ # Plan Template -Use this template when creating `.agents/work///plan.md`. Plans following this format are implementation-ready and easy to hand off to a fresh agent thread. +Use this template when creating `.agents/work///plan.md` or a focused plan under `.agents/work///plans/.md`. Plans following this format are implementation-ready and easy to hand off to a fresh agent thread. ## Template @@ -78,8 +78,8 @@ Split a task if it cannot be described in 2-3 sentences or cannot be reviewed in Before asking for an implementation handoff prompt, confirm: -- [ ] The plan lives at `.agents/work///plan.md`. -- [ ] `index.md` links the active plan and has the correct `Status:`. +- [ ] The plan lives at `.agents/work///plan.md` or `.agents/work///plans/.md`. +- [ ] `index.md` links the active plan file and has the correct `Status:`. - [ ] Every task has `Scope`, `Depends on`, and verifiable `Acceptance`. - [ ] The next task or phase is clear. - [ ] External blockers and human-only steps are explicit. diff --git a/.agents/skills/feature-planning/SKILL.md b/.agents/skills/feature-planning/SKILL.md index 6e35407..bee0384 100644 --- a/.agents/skills/feature-planning/SKILL.md +++ b/.agents/skills/feature-planning/SKILL.md @@ -14,11 +14,11 @@ Work Item → Context as needed → Plan → Refine → Handoff Prompt → Imple ``` 1. **Work item**: Use `agent-work` to create or locate `.agents/work///`. -2. **Context**: Add `research.md` for technical facts or `prd.md` as a short requirements brief only when needed. -3. **Plan**: Create or update `plan.md` with scoped tasks, dependencies, and acceptance criteria. +2. **Context**: Add `research.md` for technical facts, `research/` for multiple focused notes, or `prd.md` as a short requirements brief only when needed. +3. **Plan**: Create or update the active plan file (`plan.md` by default, or `plans/.md` for focused plans) with scoped tasks, dependencies, and acceptance criteria. 4. **Refine**: Validate assumptions against current repo reality before implementation. 5. **Handoff prompt**: Produce a paste-ready prompt for the next implementation thread. -6. **Progress**: The implementation thread updates task checkboxes, `progress.md`, and `index.md`. +6. **Progress**: The implementation thread updates active plan task checkboxes, `progress.md`, and `index.md`. ## Plan Locations @@ -28,9 +28,12 @@ New plans live inside work items: .agents/work/// ├── index.md ├── research.md +├── research/ ├── prd.md ├── plan.md -└── progress.md +├── plans/ +├── progress.md +└── decisions/ ``` Legacy standalone plan and PRD documents are user content. Migrate one at a time into `.agents/work/` only when requested. Retired Ralph guidance/templates may be backed up and removed by sync. @@ -39,7 +42,7 @@ Legacy standalone plan and PRD documents are user content. Migrate one at a time Most work does not need a PRD. Create `prd.md` only when the missing context is requirements alignment: users, behavior, goals, non-goals, acceptance, rollout, or stakeholder decisions. Use the [agent-work requirements brief template](../agent-work/assets/prd-template.md). -Use `research.md` for technical discovery. If acceptance criteria fit naturally in `plan.md`, skip `prd.md`. +Use `research.md` or `research/` for technical discovery. If acceptance criteria fit naturally in the active plan file, skip `prd.md`. ## Plan Guidance @@ -57,12 +60,12 @@ For larger work, prefer an early thin slice that proves the end-to-end path befo Use this before writing a handoff prompt when work is multi-phase, ambiguous, or stale. -1. Read the work item's `index.md` and active `plan.md`. +1. Read the work item's `index.md` and active plan file (`plan.md` or `plans/.md` as linked from `index.md`). 2. Read relevant `research.md`, requirements brief (`prd.md`), and decisions only as needed. 3. Validate key assumptions against current code, dependencies, and test setup. 4. Resolve material open questions with repo evidence where possible; ask the user only for decisions the repo cannot answer. -5. If a planned task is already satisfied, record evidence and update the plan instead of creating no-op work. -6. Update `plan.md`, `progress.md`, and `index.md` when refinement changes the next action or known constraints. +5. If a planned task is already satisfied, record evidence and update the active plan file instead of creating no-op work. +6. Update the active plan file, `progress.md`, and `index.md` when refinement changes the next action or known constraints. Skip the full pass for small, obvious changes where the plan and repo state are already aligned. @@ -77,7 +80,7 @@ The prompt should include: 3. Goal and current state. 4. Exact task, phase, or slice to implement. 5. Scope limits and non-goals. -6. Artifact update contract for `plan.md`, `progress.md`, and `index.md`. +6. Artifact update contract for the active plan file, `progress.md`, and `index.md`. 7. Verification commands or manual checks. 8. Stop conditions. 9. Expected final response format. @@ -91,7 +94,7 @@ You are continuing the work item at: Read first: 1. .agents/work///index.md -2. .agents/work///plan.md +2. //plan.md or .agents/work///plans/.md> 3. Relevant artifacts linked from index.md Goal: @@ -109,7 +112,7 @@ Scope limits: - If the plan is stale, update the plan and explain why before implementing. Progress contract: -- Update completed task checkboxes in plan.md. +- Update completed task checkboxes in the active plan file. - Append or update progress.md with changes, verification, blockers, and next action. - Update index.md Status, Updated, Artifacts, and Next Action when they change. @@ -135,9 +138,9 @@ Use this only when the user explicitly asks to stress-test, grill, or walk decis 1. Inspect the existing PRD, plan, repo docs, and relevant code first. 2. Ask one highest-leverage unresolved question at a time. 3. Provide a recommended default answer and brief rationale for each question. -4. Capture outcomes in `prd.md`, `plan.md`, or `index.md`. +4. Capture outcomes in `prd.md`, the active plan file, or `index.md`. 5. Exit once remaining ambiguity no longer materially changes scope, sequencing, or architecture. ## Definition Of Done -Planning is done when the work item has a current `index.md`, required context artifacts, an implementation-ready `plan.md`, and either a clear next action or a paste-ready handoff prompt. +Planning is done when the work item has a current `index.md`, required context artifacts, an implementation-ready active plan file, and either a clear next action or a paste-ready handoff prompt. diff --git a/.agents/skills/research/SKILL.md b/.agents/skills/research/SKILL.md index 07e50af..d0ed065 100644 --- a/.agents/skills/research/SKILL.md +++ b/.agents/skills/research/SKILL.md @@ -13,7 +13,7 @@ Research a technical question, synthesize reliable evidence, and save findings e Before doing new research: -- If the work belongs to an active work item, read `.agents/work///index.md` and prefer work-local `research.md` for task-specific findings. +- If the work belongs to an active work item, read `.agents/work///index.md` and prefer work-local `research.md` or `research/` for task-specific findings. - Search `.agents/research/` for an existing reusable topic note. - Check repo docs, attached files, and skill `references/` first. - If an existing note already answers the question, update it only when stale or incomplete. @@ -66,6 +66,8 @@ Use work-local `.agents/work///research.md` when: - The findings explain task-specific constraints, alternatives, or plan decisions. - A future agent should find the research beside `plan.md`, `prd.md`, or `progress.md`. +Use work-local `.agents/work///research/.md` when one work item needs multiple focused research notes. + Create or update `.agents/research/.md` when: - Findings are likely to be reused across unrelated work. diff --git a/.agents/work/AGENTS.md b/.agents/work/AGENTS.md index e832501..0400e3f 100644 --- a/.agents/work/AGENTS.md +++ b/.agents/work/AGENTS.md @@ -12,7 +12,7 @@ Each work item lives at: Use work items for multi-session work where context, plans, progress, decisions, and handoff prompts should stay together. Keep `.agents/research/` for reusable cross-work findings. -A work item is a *container of tasks*; the task checklist lives inside `plan.md`. +A work item is a *container of tasks*; task checklists live inside `plan.md` or focused plan files under `plans/`. ## Required Entrypoint @@ -30,7 +30,7 @@ Read `index.md` first when entering a work item, then load only the artifacts ne - Use `researching`, `planned`, `in-progress`, `blocked`, or `completed`: - `researching`: context exists, but no implementation-ready plan exists yet. - - `planned`: `plan.md` exists and is ready for a handoff prompt or implementation. + - `planned`: `plan.md` or `plans/.md` exists and is ready for a handoff prompt or implementation. - `in-progress`: implementation has started. - `blocked`: progress needs input, access, or plan changes before continuing. - `completed`: implementation and verification are done. @@ -43,11 +43,12 @@ Read `index.md` first when entering a work item, then load only the artifacts ne - `research.md`: work-local synthesis when investigation mainly supports this work item. - `research/`: optional indexed folder for multiple focused research notes. - `prd.md`: optional short requirements brief for user-facing, ambiguous, or cross-team work. -- `plan.md`: implementation-ready task plan. +- `plan.md`: primary implementation-ready task plan. +- `plans/`: optional indexed folder for multiple focused implementation plans. - `progress.md`: running implementation log, verification notes, blockers, and next actions. - `decisions/`: optional one-file-per-decision records when a decision should outlive chat context. -Do not create empty support folders by default. Add `research/`, `decisions/`, or other subfolders only when they hold useful files. +Do not create empty support folders by default. Add `research/`, `plans/`, `decisions/`, or other subfolders only when they hold useful files. ## Research Placement @@ -55,7 +56,7 @@ Use work-local `research.md` when findings mainly explain this work item's imple ## Planning And Progress -Work-local plans live at `plan.md` and use the canonical agent-work plan contract. A new implementation thread should update task checkboxes, append to `progress.md`, and refresh `index.md` when status, artifacts, or next action changes. +Work-local plans live at `plan.md` or under `plans/` and use the canonical agent-work plan contract. A new implementation thread should update task checkboxes, append to `progress.md`, and refresh `index.md` when status, artifacts, or next action changes. When `plans/` exists, keep `index.md` pointed at the active plan file. One active implementation thread should own a work item at a time. If `progress.md` conflicts, preserve both entries in chronological order and recompute the current `index.md` summary. diff --git a/AGENTS.md b/AGENTS.md index 240e350..a4b1054 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,8 +16,8 @@ Work Item → Context as needed → Plan → Handoff Prompt → Implement → Re ``` 1. **Work Item:** Create `.agents/work///index.md` as the durable entrypoint. -2. **Context:** Add `research.md` for technical facts or `prd.md` as a short requirements brief only when needed. -3. **Plan:** Break work into implementation-ready tasks in `plan.md`. +2. **Context:** Add `research.md` or `research/` for technical facts, or `prd.md` as a short requirements brief only when needed. +3. **Plan:** Break work into implementation-ready tasks in the active plan file (`plan.md` by default, or `plans/.md` for focused plans). 4. **Handoff Prompt:** Generate a paste-ready prompt for a fresh implementation thread. 5. **Progress:** Implementation threads update `progress.md`, task checkboxes, and `index.md`. @@ -47,7 +47,7 @@ dot-agents/ | `Run adapt` | Analyze project and fill in `AGENTS.md` sections | | `Create a new work item for ...` | Create durable `.agents/work/` context | | `Research ...` | Investigate and save work-local or reusable findings | -| `Create/refine a plan for ...` | Produce implementation-ready `plan.md` tasks | +| `Create/refine a plan for ...` | Produce implementation-ready tasks in the active plan file | | `Write a handoff prompt for ...` | Produce a paste-ready prompt for a new implementation thread | Skills are loaded via natural language. See each skill's `SKILL.md` in `.agents/skills/` for details. @@ -60,7 +60,7 @@ Work items live under: .agents/work/// ``` -Every work item has `index.md` with status, category, updated date, artifact links, next action, and open questions. Optional files include `research.md`, `prd.md`, `plan.md`, `progress.md`, and `decisions/` records. +Every work item has `index.md` with status, category, updated date, artifact links, next action, and open questions. Optional artifacts include `research.md`, `research/`, `prd.md`, `plan.md`, `plans/`, `progress.md`, and `decisions/` records. Legacy `.agents/plans/` and `.agents/prds/` paths may exist in older installs. Preserve legacy plan and PRD documents as user content, but allow sync to retire stale Ralph guidance/templates. Migrate one plan at a time into `.agents/work/` only when requested. diff --git a/AGENTS.template.md b/AGENTS.template.md index af05d03..6a32311 100644 --- a/AGENTS.template.md +++ b/AGENTS.template.md @@ -20,8 +20,8 @@ Work Item → Context as needed → Plan → Handoff Prompt → Implement → Re ``` 1. **Work Item:** Create durable context in `.agents/work///`. -2. **Context:** Add `research.md` for technical facts or `prd.md` as a short requirements brief only when needed. -3. **Plan:** Break work into implementation-ready tasks in `plan.md`. +2. **Context:** Add `research.md` or `research/` for technical facts, or `prd.md` as a short requirements brief only when needed. +3. **Plan:** Break work into implementation-ready tasks in the active plan file (`plan.md` by default, or `plans/.md` for focused plans). 4. **Handoff Prompt:** Generate a paste-ready prompt for a fresh implementation thread. 5. **Progress:** Implementation threads update `progress.md`, task checkboxes, and `index.md`. @@ -34,8 +34,13 @@ project/ │ ├── work/ # Durable work items │ │ └── // │ │ ├── index.md # Required entrypoint -│ │ ├── plan.md # Optional implementation plan -│ │ └── progress.md # Optional implementation log +│ │ ├── research.md # Optional work-specific findings +│ │ ├── research/ # Optional focused research notes +│ │ ├── prd.md # Optional requirements brief +│ │ ├── plan.md # Optional primary implementation plan +│ │ ├── plans/ # Optional focused implementation plans +│ │ ├── progress.md # Optional implementation log +│ │ └── decisions/ # Optional durable decisions │ ├── research/ # Reusable cross-work research notes │ ├── references/ # External repos or docs checkouts (gitignored) │ ├── scripts/ # dot-agents helper scripts @@ -55,7 +60,7 @@ project/ | `Run adapt` | Analyze project and fill in `AGENTS.md` sections | | `Create a new work item for ...` | Create durable `.agents/work/` context | | `Research [topic]` | Investigate and save work-local or reusable findings | -| `Create a plan for ...` | Produce implementation-ready `plan.md` tasks | +| `Create a plan for ...` | Produce implementation-ready tasks in the active plan file | | `Write a handoff prompt for ...` | Produce a paste-ready prompt for a new implementation thread | Skills are loaded via natural language. See each skill's `SKILL.md` in `.agents/skills/` for details. @@ -79,12 +84,14 @@ Updated: YYYY-MM-DD Use optional files only when useful: - `research.md` - work-specific investigation notes +- `research/` - optional indexed folder for multiple focused research notes - `prd.md` - short requirements brief when alignment is needed -- `plan.md` - implementation-ready task checklist +- `plan.md` - primary implementation-ready task checklist +- `plans/` - optional indexed folder for multiple focused plans - `progress.md` - implementation log, verification, blockers, and next action - `decisions/` - durable decision records -Do not create empty support folders by default. +Do not create empty support folders by default. Add `research/`, `plans/`, or `decisions/` only when they hold useful files. ### Task Format @@ -128,7 +135,7 @@ git push After making changes: 1. **Update AGENTS.md** - Keep project commands and conventions current. -2. **Update work items** - Keep `index.md`, `plan.md`, and `progress.md` in sync with implementation state. +2. **Update work items** - Keep `index.md`, the active plan file, and `progress.md` in sync with implementation state. 3. **Update docs** - Reflect user-facing behavior changes. ## Conventions diff --git a/QUICKSTART.md b/QUICKSTART.md index 3213539..cedb167 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -113,7 +113,7 @@ When the plan is ready, ask: Review .agents/work/feature/user-authentication and write a paste-ready handoff prompt for the next implementation thread. ``` -Paste the generated prompt into a fresh agent thread. The new thread should read `index.md`, implement the requested slice, update `plan.md` checkboxes, append to `progress.md`, refresh `index.md`, and report verification results. +Paste the generated prompt into a fresh agent thread. The new thread should read `index.md`, implement the requested slice, update the active plan file, append to `progress.md`, refresh `index.md`, and report verification results. ## 6. Continue Later diff --git a/docs/concepts.md b/docs/concepts.md index bb52107..331c438 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -7,13 +7,13 @@ Work Item → Context as needed → Plan → Handoff Prompt → Implement → Re ``` 1. **Work Item:** Create `.agents/work///index.md` as the durable context entrypoint. -2. **Context:** Add optional context only when it helps: `research.md` for technical facts, or `prd.md` as a short requirements brief when behavior needs alignment. -3. **Plan:** Break work into implementation-ready tasks in `plan.md` with scope, dependencies, and acceptance criteria. +2. **Context:** Add optional context only when it helps: `research.md` or `research/` for technical facts, or `prd.md` as a short requirements brief when behavior needs alignment. +3. **Plan:** Break work into implementation-ready tasks in the active plan file (`plan.md` by default, or `plans/.md` for focused plans) with scope, dependencies, and acceptance criteria. 4. **Handoff Prompt:** Ask an agent to write a paste-ready prompt for a fresh implementation thread. 5. **Implement:** Paste the prompt into the new thread and let that agent do the scoped work. -6. **Record Progress:** Update `progress.md`, task checkboxes, and `index.md` so future threads can resume. +6. **Record Progress:** Update `progress.md`, active plan task checkboxes, and `index.md` so future threads can resume. -Context is optional. Use `research.md` when the question is "what is true?" Use `prd.md` as a requirements brief when the question is "what should be true?" Skip both when the plan can state the goal and acceptance criteria clearly. +Context is optional. Use `research.md` when the question is "what is true?" Use `research/` when multiple focused research notes are useful. Use `prd.md` as a requirements brief when the question is "what should be true?" Skip both when the plan can state the goal and acceptance criteria clearly. ## Work Item Shape @@ -21,13 +21,16 @@ Context is optional. Use `research.md` when the question is "what is true?" Use .agents/work/// ├── index.md # required landing page ├── research.md # optional, work-specific findings +├── research/ # optional focused research notes ├── prd.md # optional requirements brief -├── plan.md # optional implementation-ready tasks +├── plan.md # optional primary implementation-ready tasks +├── plans/ # optional focused implementation plans ├── progress.md # optional implementation log └── decisions/ # optional durable decisions ``` Create optional files only when they hold useful context. The required `index.md` should stay short and point to the current next action. +Create optional folders like `research/`, `plans/`, and `decisions/` only when they contain useful files. ## Handoff Prompts @@ -36,7 +39,7 @@ A handoff prompt is a paste-ready prompt for a new agent thread. It should name: - Work item path and files to read first. - Goal, current state, and exact implementation slice. - Scope limits and non-goals. -- Required updates to `plan.md`, `progress.md`, and `index.md`. +- Required updates to the active plan file, `progress.md`, and `index.md`. - Verification commands and stop conditions. - Expected final response shape. @@ -52,7 +55,7 @@ Older dot-agents installs used `.agents/plans/` and `.agents/prds/`. v0.3.0 pres | --- | --- | | adapt | Skill that analyzes your project and fills in `AGENTS.md` | | work item | Durable folder under `.agents/work///` for one multi-session effort | -| task | Checkbox entry inside `plan.md` | +| task | Checkbox entry inside `plan.md` or a focused plan under `plans/` | | PRD | Optional short requirements brief defining what should be true | | plan | Implementation-ready task list with scope, dependencies, and acceptance criteria | | handoff prompt | Paste-ready prompt for a fresh implementation thread | diff --git a/docs/skills.md b/docs/skills.md index 5875c24..b8a419a 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -47,7 +47,7 @@ Turns work-item context into implementation-ready plans and paste-ready handoff Use it to: - Create or refine a short requirements brief (`prd.md`) only when alignment is needed -- Create or refine `plan.md` +- Create or refine the active plan file - Validate stale assumptions before implementation - Generate a new-thread handoff prompt - Stress-test a plan when explicitly asked @@ -62,7 +62,7 @@ Investigates technical questions using available local, web, and repository evid Research is saved: -- Work-locally at `.agents/work///research.md` when it supports one work item +- Work-locally at `.agents/work///research.md` or `.agents/work///research/.md` when it supports one work item - Reusably at `.agents/research/.md` when it should guide future unrelated work **Invoke:** `Research authentication patterns for this work item` diff --git a/test/fixtures/sample-archive.tar.gz b/test/fixtures/sample-archive.tar.gz index 081f3b87d40b4ff65fc1e8e320b1a6db4f4ca0cc..ad61b71a2cae6697fc03470cbf7ecdc31747bb55 100644 GIT binary patch literal 19886 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 z%0A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 A{{R30 From 0b8c9f8695221345d03488480a98a335d1d8ab2c Mon Sep 17 00:00:00 2001 From: Marius Colacioiu Date: Mon, 22 Jun 2026 22:50:12 +0200 Subject: [PATCH 12/12] Improve docs onboarding examples Amp-Thread-ID: https://ampcode.com/threads/T-019ef111-28df-713f-8499-6869c90e8dea Co-authored-by: Amp --- QUICKSTART.md | 32 ++++++++++++++++++++++++++++++-- README.md | 4 ++++ docs/concepts.md | 28 ++++++++++++++++++++++++++++ site/index.html | 39 +++++++++++++++++++++++++++++++-------- site/style.css | 45 +++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 136 insertions(+), 12 deletions(-) diff --git a/QUICKSTART.md b/QUICKSTART.md index cedb167..0942386 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -17,10 +17,14 @@ Get productive with dot-agents in 5 minutes. ## 1. Install +Run the installer from the root of the repository you want to equip with dot-agents: + ```bash curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash ``` +Fresh installs create `AGENTS.md` and `.agents/`. Re-running the installer later updates dot-agents while preserving work items, research, and your customized `AGENTS.md`. + ### What Gets Installed ```text @@ -60,14 +64,24 @@ Run adapt This analyzes your project and fills in the `AGENTS.md` template with tech stack, commands, and conventions. You can also customize it manually. +If your agent does not auto-discover skills, tell it: + +```text +Read .agents/skills/adapt/SKILL.md and follow it. +``` + ## 3. Create a Work Item +Use work items for multi-session or context-heavy work. For a tiny one-shot edit, you may not need one. + Ask your agent: ```text Create a new work item for user authentication. ``` +If your agent does not auto-discover skills, tell it to read `.agents/skills/agent-work/SKILL.md` first. + Or run the helper directly: ```bash @@ -83,6 +97,16 @@ The work item starts at: .agents/work/feature/user-authentication/index.md ``` +A minimal work item looks like: + +```text +.agents/work/feature/user-authentication/ +├── index.md # status, summary, next action +└── plan.md # added when you ask for a plan +``` + +Future threads start by reading `index.md`, then load only the plan, research, or progress they need. + ## 4. Add Context Only If Needed, Then Plan If the unknowns are technical, ask for work-local research: @@ -125,8 +149,12 @@ List active work: Then ask for a continuation prompt from the next action in the work item. -## Legacy Plans and PRDs +## Outcome + +At the end of the quickstart, you have a work item with a current next action and a paste-ready prompt for a fresh implementation thread. + +## Upgrading from v0.2? -Older dot-agents installs used `.agents/plans/` and `.agents/prds/`. Legacy plan and PRD documents are preserved on sync, while retired Ralph guidance/templates are backed up and removed. Migrate one plan at a time into `.agents/work///` when you need to resume it. +See the [v0.3 migration guide](./docs/migration-v0.3.md) for legacy `.agents/plans/` and `.agents/prds/` projects. **Next:** [Concepts](./docs/concepts.md) · [Skills Reference](./docs/skills.md) · [dot-agents.dev](https://dot-agents.dev) diff --git a/README.md b/README.md index 792d1c0..f950a30 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ AI-ready `.agents/` workspace for any project — durable work items, reusable r ## Install +Run the installer from the root of the repository you want to equip with dot-agents: + ```bash curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.sh | bash ``` @@ -24,6 +26,8 @@ curl -fsSL https://raw.githubusercontent.com/colmarius/dot-agents/main/install.s dot-agents works with any AI coding agent that reads Markdown instructions. When a project already has a `.claude/` directory, install/sync also links dot-agents skills into `.claude/skills/` so Claude Code can discover them as project skills. +If an agent does not auto-discover skills, ask it to read the relevant `.agents/skills//SKILL.md` file before starting that workflow. + ## Next Steps After install: diff --git a/docs/concepts.md b/docs/concepts.md index 331c438..a1bd599 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -13,6 +13,8 @@ Work Item → Context as needed → Plan → Handoff Prompt → Implement → Re 5. **Implement:** Paste the prompt into the new thread and let that agent do the scoped work. 6. **Record Progress:** Update `progress.md`, active plan task checkboxes, and `index.md` so future threads can resume. +Use work items for multi-session or context-heavy work. For a tiny one-shot edit, you may not need one. + Context is optional. Use `research.md` when the question is "what is true?" Use `research/` when multiple focused research notes are useful. Use `prd.md` as a requirements brief when the question is "what should be true?" Skip both when the plan can state the goal and acceptance criteria clearly. ## Work Item Shape @@ -32,6 +34,32 @@ Context is optional. Use `research.md` when the question is "what is true?" Use Create optional files only when they hold useful context. The required `index.md` should stay short and point to the current next action. Create optional folders like `research/`, `plans/`, and `decisions/` only when they contain useful files. +## Example Work Item + +```text +.agents/work/feature/user-authentication/ +├── index.md # status, summary, next action +└── plan.md # implementation tasks, when useful +``` + +```markdown +# User authentication + +Status: planned +Category: feature +Updated: 2026-06-22 + +## Summary + +Add auth flows and session persistence. + +## Next Action + +Implement Task 1 from plan.md. +``` + +New threads start by reading `index.md`, then load only the plan, research, or progress they need. + ## Handoff Prompts A handoff prompt is a paste-ready prompt for a new agent thread. It should name: diff --git a/site/index.html b/site/index.html index eecddce..09ea8eb 100644 --- a/site/index.html +++ b/site/index.html @@ -45,6 +45,7 @@

Make AI coding work survive the next thread
+

Run from your repo root. Fresh installs create AGENTS.md and .agents/; syncs later preserve your work items, research, and customized project instructions.

@@ -72,7 +73,33 @@

What it adds

├── skills/ # adapt, work items, planning, research └── scripts/ # sync updates safely
-

Re-run the installer later to update dot-agents while preserving your work items, research, and customized AGENTS.md.

+

Use work items for multi-session or context-heavy work. Tiny one-shot edits may not need one.

+
+ +
+

Example work item

+

After asking Create a new work item for user authentication, future threads have a durable starting point.

+
+
+
.agents/work/feature/user-authentication/
+├── index.md      # status, summary, next action
+└── plan.md       # implementation tasks, when useful
+
+
+
# User authentication
+
+Status: planned
+Category: feature
+Updated: 2026-06-22
+
+## Summary
+Add auth flows and session persistence.
+
+## Next Action
+Implement Task 1 from plan.md.
+
+
+

A new thread starts by reading index.md, then loads only the plan, research, or progress it needs.

@@ -81,19 +108,15 @@

How it works

Run adapt - Fill in AGENTS.md with project commands, structure, and conventions. + Adapt once by filling AGENTS.md with project commands, structure, and conventions.
Create a new work item for ... Start durable context under .agents/work/<category>/<slug>/.
- Research ... - Capture technical facts only when they are needed. -
-
- Create/refine a plan for ... - Turn context into implementation-ready tasks with acceptance criteria. + Add only needed context + Ask for research, a short requirements brief, or an implementation plan only when it helps.
Write a handoff prompt for ... diff --git a/site/style.css b/site/style.css index 706e0d5..c1881ad 100644 --- a/site/style.css +++ b/site/style.css @@ -140,8 +140,27 @@ header { margin: 1rem 0 3rem; } +.install-note { + max-width: 640px; + margin: 0 auto 1rem; + color: var(--text-muted); + font-size: 0.9375rem; + text-align: center; +} + +.install-note code { + font-family: "SF Mono", "Fira Code", "Consolas", monospace; + font-size: 0.875rem; + color: var(--text); + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 4px; + padding: 0.15rem 0.35rem; +} + .code-block { position: relative; + max-width: 100%; background: var(--bg-secondary); border: 1px solid var(--border); border-radius: 12px; @@ -179,6 +198,7 @@ header { font-size: 0.9rem; line-height: 1.6; overflow-x: auto; + -webkit-overflow-scrolling: touch; } .code-block code { @@ -246,12 +266,15 @@ header { } .install-hint code { + display: inline-block; + max-width: 100%; font-family: "SF Mono", "Fira Code", "Consolas", monospace; font-size: 0.8125rem; background: var(--bg-secondary); padding: 0.2rem 0.4rem; border-radius: 4px; border: 1px solid var(--border); + overflow-wrap: anywhere; } .section-intro { @@ -273,18 +296,27 @@ header { } /* What you get */ -.what-you-get { +.what-you-get, +.example-work-item { margin: 2rem 0 3rem; text-align: center; } -.what-you-get h2 { +.what-you-get h2, +.example-work-item h2 { font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem; color: var(--text-muted); } +.example-grid { + display: grid; + gap: 0.75rem; + max-width: 720px; + margin: 0 auto 1rem; +} + .tree-block { text-align: left; box-shadow: none; @@ -442,4 +474,13 @@ footer a:hover { .code-block pre { font-size: 0.8rem; } + + .tree-comment { + display: none; + } + + .tree-block pre { + padding: 1rem; + font-size: 0.75rem; + } }