From 2f91667b83a89fbdae72059fb310faa0fcdaeed5 Mon Sep 17 00:00:00 2001 From: marcusquinn <6428977+marcusquinn@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:43:09 +0000 Subject: [PATCH 1/3] feat: add three-tier agent lifecycle (draft, private, shared) Add support for user-created agents with three tiers: - Draft (draft/): R&D and orchestration-created agents for review - Custom (custom/): User's permanent private agents - Shared (.agents/): Open-source agents submitted via PR Key changes: - build-agent.md: Agent Lifecycle Tiers section with placement prompt, draft conventions, promotion workflow, and guidance for orchestration agents to create reusable draft agents - setup.sh: Preserve custom/ and draft/ during deployment (both clean mode and rsync exclusion) - AGENTS.md: Agent tiers reference and updated working dirs - headless-dispatch.md: Cross-reference to draft agents for parallel worker context reuse - ai-orchestration/overview.md: Cross-reference to draft agents --- .agents/AGENTS.md | 25 +++- .../tools/ai-assistants/headless-dispatch.md | 2 + .agents/tools/ai-orchestration/overview.md | 2 + .agents/tools/build-agent/build-agent.md | 134 ++++++++++++++++++ setup.sh | 26 +++- 5 files changed, 180 insertions(+), 9 deletions(-) diff --git a/.agents/AGENTS.md b/.agents/AGENTS.md index 811533b6..2d1cd387 100644 --- a/.agents/AGENTS.md +++ b/.agents/AGENTS.md @@ -213,6 +213,16 @@ See `subagent-index.toon` for complete listing of agents, subagents, workflows, **Strategy**: Read subagents on-demand when tasks require domain expertise. This keeps context focused. +**Agent tiers** (user-created agents survive `aidevops update`): + +| Tier | Location | Purpose | +|------|----------|---------| +| **Draft** | `~/.aidevops/agents/draft/` | R&D, experimental, auto-created by orchestration tasks | +| **Custom** | `~/.aidevops/agents/custom/` | User's permanent private agents | +| **Shared** | `.agents/` in repo | Open-source, distributed to all users | + +Orchestration agents can create drafts in `draft/` for reusable parallel processing context. See `tools/build-agent/build-agent.md` for the full lifecycle and promotion workflow. + **Progressive disclosure by domain**: | Domain | Read | @@ -293,11 +303,16 @@ Import community skills: `aidevops skill add ` (→ `*-skill.md` suffix) ## Working Directories ```text -~/.aidevops/.agent-workspace/ -├── work/[project]/ # Persistent project files -├── tmp/session-*/ # Temporary session files -├── mail/ # Inter-agent mailbox (SQLite: mailbox.db) -└── memory/ # Cross-session patterns (SQLite FTS5) +~/.aidevops/ +├── agents/ # Deployed agent files +│ ├── custom/ # User's private agents (survives updates) +│ ├── draft/ # Experimental/R&D agents (survives updates) +│ └── ... # Shared agents (deployed from repo) +└── .agent-workspace/ + ├── work/[project]/ # Persistent project files + ├── tmp/session-*/ # Temporary session files + ├── mail/ # Inter-agent mailbox (SQLite: mailbox.db) + └── memory/ # Cross-session patterns (SQLite FTS5) ``` ## Browser Automation diff --git a/.agents/tools/ai-assistants/headless-dispatch.md b/.agents/tools/ai-assistants/headless-dispatch.md index 12785af4..6b873733 100644 --- a/.agents/tools/ai-assistants/headless-dispatch.md +++ b/.agents/tools/ai-assistants/headless-dispatch.md @@ -39,6 +39,8 @@ tools: - Tasks requiring human-in-the-loop decisions mid-execution - Single quick questions (just use `opencode run` without server overhead) +**Draft agents for reusable context**: When parallel workers share domain-specific instructions, create a draft agent in `~/.aidevops/agents/draft/` instead of duplicating prompts. Subsequent dispatches can reference the draft. See `tools/build-agent/build-agent.md` "Agent Lifecycle Tiers" for details. + ## Architecture diff --git a/.agents/tools/ai-orchestration/overview.md b/.agents/tools/ai-orchestration/overview.md index be35b3bc..726a4cd9 100644 --- a/.agents/tools/ai-orchestration/overview.md +++ b/.agents/tools/ai-orchestration/overview.md @@ -52,6 +52,8 @@ git clone https://github.com/openprose/prose.git ~/.config/opencode/skill/open-p **Port Conflict Resolution**: All helper scripts integrate with `localhost-helper.sh` for automatic port management. If a port is in use, an alternative is automatically selected. +**Draft agents**: Orchestration tasks that discover reusable patterns should create draft agents in `~/.aidevops/agents/draft/`. These can be promoted to private (`custom/`) or shared (`.agents/`) after review. See `tools/build-agent/build-agent.md` "Agent Lifecycle Tiers". + ## Decision Matrix diff --git a/.agents/tools/build-agent/build-agent.md b/.agents/tools/build-agent/build-agent.md index 8ecb731b..b1f365af 100644 --- a/.agents/tools/build-agent/build-agent.md +++ b/.agents/tools/build-agent/build-agent.md @@ -823,6 +823,140 @@ Main agents provide overview and point to subagents for details (progressive dis | `server-patterns.md` | Registering tools, resources | ```text +### Agent Lifecycle Tiers + +When creating an agent, determine which tier it belongs to. This affects where it lives, whether it survives updates, and whether it gets shared. + +| Tier | Location | Survives `setup.sh` | Git Tracked | Purpose | +|------|----------|---------------------|-------------|---------| +| **Draft** | `~/.aidevops/agents/draft/` | Yes | No | R&D, experimental, auto-created by orchestration | +| **Custom** | `~/.aidevops/agents/custom/` | Yes | No | User's permanent private agents | +| **Shared** | `.agents/` in repo | Yes (deployed) | Yes | Open-source, submitted via PR | + +**When creating an agent, ask the user:** + +```text +Where should this agent live? +1. Draft - Experimental, for review later (draft/) +2. Custom - Private, stays on your machine (custom/) +3. Shared - Add to aidevops for everyone (PR to .agents/) +``` + +#### Draft Agents + +Draft agents are created during R&D, orchestration tasks, or exploratory work. They are intentionally rough and expected to evolve. + +**When to create a draft:** +- An orchestration task needs a reusable subagent for parallel processing +- Exploring a new domain and capturing patterns as you go +- A Task tool subagent would benefit from persistent instructions across sessions + +**Draft conventions:** +- Place in `~/.aidevops/agents/draft/` +- Include `status: draft` and `created` date in frontmatter +- Use descriptive filenames: `draft/{domain}-{purpose}.md` + +```yaml +--- +description: Experimental agent for X +mode: subagent +status: draft +created: 2026-02-07 +tools: + read: true + write: false + edit: false + bash: false + glob: true + grep: true +--- +``` + +**Promotion workflow:** + +After a draft proves useful, log a TODO item for review: + +```text +- [ ] tXXX Review draft agent: {name} - promote to custom/ or .agents/ #agent-review +``` + +Then decide: + +1. **Promote to Custom** -- Move to `~/.aidevops/agents/custom/`, remove `status: draft` +2. **Promote to Shared** -- Move to `.agents/` in the repo, refine to framework standards, submit PR +3. **Discard** -- Delete from `draft/` if no longer useful + +#### Custom (Private) Agents + +Custom agents are the user's permanent private agents. They are never shared and never overwritten by `setup.sh`. + +**When to use custom:** +- Business-specific workflows (your company's deploy process) +- Personal preferences (your coding style agent) +- Client-specific agents (per-project orchestration) +- Agents containing proprietary knowledge + +**Custom conventions:** +- Place in `~/.aidevops/agents/custom/` +- Follow the same structure as shared agents (frontmatter, AI-CONTEXT blocks) +- Organize with subdirectories if needed: `custom/mycompany/`, `custom/clients/` + +#### Shared Agents + +Shared agents live in `.agents/` in the aidevops repository and are distributed to all users via `setup.sh`. + +**When to share:** +- The agent solves a general problem others would face +- It follows framework conventions (frontmatter, quality standards) +- It doesn't contain proprietary or personal information + +**Submission process:** +1. Create a feature branch: `wt switch -c feature/agent-{name}` +2. Place the agent in the appropriate `.agents/` location +3. Follow the Agent Design Checklist (see above) +4. Submit a PR to the aidevops repository + +#### Orchestration and Task Agents Creating Drafts + +Agents running orchestration tasks (via the Task tool, Ralph loop, or parallel dispatch) **can and should** create draft agents when they identify reusable patterns. This is a key mechanism for the framework to evolve. + +**When an orchestration agent should create a draft:** +- A subtask requires domain-specific instructions that would be reused +- Parallel workers need shared context that doesn't fit in a single prompt +- A complex workflow has emerged that should be captured as a repeatable agent +- The same Task tool prompt is being duplicated across multiple invocations + +**How orchestration agents create drafts:** + +```bash +# Write the draft agent +cat > ~/.aidevops/agents/draft/data-migration-validator.md << 'AGENT' +--- +description: Validates data migration between PostgreSQL schemas +mode: subagent +status: draft +created: 2026-02-07 +source: auto-created by orchestration task +tools: + read: true + bash: true + glob: true + grep: true +--- + +# Data Migration Validator + +[Agent instructions captured from the orchestration context...] +AGENT +``` + +**After creating a draft, the orchestration agent should:** +1. Log a TODO item: `- [ ] tXXX Review draft agent: data-migration-validator #agent-review` +2. Reference the draft in subsequent Task tool calls instead of repeating instructions +3. Note the draft's existence in its completion summary + +This creates a natural feedback loop: orchestration discovers patterns, drafts capture them, humans review and promote the useful ones. + ### Deployment Sync Agent changes in `.agents/` require `setup.sh` to deploy to `~/.aidevops/agents/`: diff --git a/setup.sh b/setup.sh index dd4f9eb3..6bb1769d 100755 --- a/setup.sh +++ b/setup.sh @@ -2093,19 +2093,37 @@ deploy_aidevops_agents() { # Create target directory and copy agents mkdir -p "$target_dir" - # If clean mode, remove stale files first + # If clean mode, remove stale files first (preserving user directories) if [[ "$CLEAN_MODE" == "true" ]]; then - print_info "Clean mode: removing stale files from $target_dir" + print_info "Clean mode: removing stale files from $target_dir (preserving custom/, draft/)" + # Preserve user-managed directories before clean + local preserved_dirs=("custom" "draft") + local tmp_preserve + tmp_preserve=$(mktemp -d) + for pdir in "${preserved_dirs[@]}"; do + if [[ -d "$target_dir/$pdir" ]]; then + cp -R "$target_dir/$pdir" "$tmp_preserve/$pdir" + fi + done rm -rf "${target_dir:?}"/* + # Restore preserved directories + for pdir in "${preserved_dirs[@]}"; do + if [[ -d "$tmp_preserve/$pdir" ]]; then + cp -R "$tmp_preserve/$pdir" "$target_dir/$pdir" + fi + done + rm -rf "$tmp_preserve" fi # Copy all agent files and folders, excluding: # - loop-state/ (local runtime state, not agents) + # - custom/ (user's private agents, never overwritten) + # - draft/ (user's experimental agents, never overwritten) # Use rsync for selective exclusion if command -v rsync &>/dev/null; then - rsync -a --exclude='loop-state/' "$source_dir/" "$target_dir/" + rsync -a --exclude='loop-state/' --exclude='custom/' --exclude='draft/' "$source_dir/" "$target_dir/" else - # Fallback: copy then remove loop-state + # Fallback: copy then remove excluded dirs cp -R "$source_dir"/* "$target_dir/" rm -rf "$target_dir/loop-state" 2>/dev/null || true fi From e6c704d593028cf2363eb4568bc179680bbc460b Mon Sep 17 00:00:00 2001 From: marcusquinn <6428977+marcusquinn@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:47:35 +0000 Subject: [PATCH 2/3] fix: use tar fallback with exclusions matching rsync behavior Address Gemini review: cp -R fallback didn't exclude custom/ and draft/ directories. Replace with tar pipe that correctly excludes loop-state/, custom/, and draft/ on both BSD and GNU tar. --- setup.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index 6bb1769d..4e584652 100755 --- a/setup.sh +++ b/setup.sh @@ -2123,9 +2123,8 @@ deploy_aidevops_agents() { if command -v rsync &>/dev/null; then rsync -a --exclude='loop-state/' --exclude='custom/' --exclude='draft/' "$source_dir/" "$target_dir/" else - # Fallback: copy then remove excluded dirs - cp -R "$source_dir"/* "$target_dir/" - rm -rf "$target_dir/loop-state" 2>/dev/null || true + # Fallback: use tar with exclusions to match rsync behavior + (cd "$source_dir" && tar cf - --exclude='loop-state' --exclude='custom' --exclude='draft' .) | (cd "$target_dir" && tar xf -) fi if [[ $? -eq 0 ]]; then From 7709afd05410323059c4fb544d855f4843c4f9c7 Mon Sep 17 00:00:00 2001 From: marcusquinn <6428977+marcusquinn@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:51:24 +0000 Subject: [PATCH 3/3] fix: guard clean mode backup against mktemp/cp failure Address CodeRabbit review: abort clean if temp dir creation or directory preservation fails, preventing data loss of user's custom/ and draft/ agents. Use local var=$() pattern. --- setup.sh | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/setup.sh b/setup.sh index 4e584652..fe2352f6 100755 --- a/setup.sh +++ b/setup.sh @@ -2097,14 +2097,25 @@ deploy_aidevops_agents() { if [[ "$CLEAN_MODE" == "true" ]]; then print_info "Clean mode: removing stale files from $target_dir (preserving custom/, draft/)" # Preserve user-managed directories before clean - local preserved_dirs=("custom" "draft") - local tmp_preserve - tmp_preserve=$(mktemp -d) + local -a preserved_dirs=("custom" "draft") + local tmp_preserve="$(mktemp -d)" + if [[ -z "$tmp_preserve" || ! -d "$tmp_preserve" ]]; then + print_error "Failed to create temp dir for preserving custom/draft agents" + return 1 + fi + local preserve_failed=false for pdir in "${preserved_dirs[@]}"; do if [[ -d "$target_dir/$pdir" ]]; then - cp -R "$target_dir/$pdir" "$tmp_preserve/$pdir" + if ! cp -R "$target_dir/$pdir" "$tmp_preserve/$pdir"; then + preserve_failed=true + fi fi done + if [[ "$preserve_failed" == "true" ]]; then + print_error "Failed to preserve custom/draft agents; aborting clean" + rm -rf "$tmp_preserve" + return 1 + fi rm -rf "${target_dir:?}"/* # Restore preserved directories for pdir in "${preserved_dirs[@]}"; do