From d77a697ceed8d6676a9dc3ad888383a2bcce0862 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sat, 27 Dec 2025 16:07:13 -0800 Subject: [PATCH] feat: add bd admin parent command for cleanup/compact/reset (bd-3u8m) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move cleanup, compact, and reset commands under `bd admin` namespace. Creates hidden aliases for backwards compatibility that show deprecation notice when used. - Create cmd/bd/admin.go with parent command - Create cmd/bd/admin_aliases.go for hidden backwards-compat aliases - Update cleanup.go, compact.go, reset.go to remove rootCmd.AddCommand - Update all documentation to use `bd admin ` syntax 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- cmd/bd/admin.go | 26 +++++++ cmd/bd/admin_aliases.go | 86 ++++++++++++++++++++++++ cmd/bd/cleanup.go | 7 +- cmd/bd/compact.go | 2 +- cmd/bd/reset.go | 7 +- commands/compact.md | 10 +-- docs/CLI_REFERENCE.md | 22 +++--- docs/CONFIG.md | 2 +- docs/DELETIONS.md | 6 +- docs/FAQ.md | 4 +- docs/QUICKSTART.md | 8 +-- docs/TROUBLESHOOTING.md | 6 +- examples/compaction/README.md | 2 +- examples/compaction/auto-compact.sh | 8 +-- examples/compaction/cron-compact.sh | 6 +- examples/compaction/workflow.sh | 10 +-- skills/beads/SKILL.md | 2 +- skills/beads/references/CLI_REFERENCE.md | 22 +++--- 18 files changed, 173 insertions(+), 63 deletions(-) create mode 100644 cmd/bd/admin.go create mode 100644 cmd/bd/admin_aliases.go diff --git a/cmd/bd/admin.go b/cmd/bd/admin.go new file mode 100644 index 00000000..4e802212 --- /dev/null +++ b/cmd/bd/admin.go @@ -0,0 +1,26 @@ +package main + +import ( + "github.com/spf13/cobra" +) + +var adminCmd = &cobra.Command{ + Use: "admin", + GroupID: "advanced", + Short: "Administrative commands for database maintenance", + Long: `Administrative commands for beads database maintenance. + +These commands are for advanced users and should be used carefully: + cleanup Delete closed issues and prune expired tombstones + compact Compact old closed issues to save space + reset Remove all beads data and configuration + +For routine operations, prefer 'bd doctor --fix'.`, +} + +func init() { + rootCmd.AddCommand(adminCmd) + adminCmd.AddCommand(cleanupCmd) + adminCmd.AddCommand(compactCmd) + adminCmd.AddCommand(resetCmd) +} diff --git a/cmd/bd/admin_aliases.go b/cmd/bd/admin_aliases.go new file mode 100644 index 00000000..7cb216e7 --- /dev/null +++ b/cmd/bd/admin_aliases.go @@ -0,0 +1,86 @@ +package main + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/steveyegge/beads/internal/ui" +) + +// Hidden aliases for backwards compatibility. +// These commands forward to their admin subcommand equivalents. +// They are hidden from help output but still work for scripts/muscle memory. + +var cleanupAliasCmd = &cobra.Command{ + Use: "cleanup", + Hidden: true, + Short: "Alias for 'bd admin cleanup' (deprecated)", + Long: cleanupCmd.Long, + Run: func(cmd *cobra.Command, args []string) { + fmt.Fprintln(os.Stderr, ui.RenderMuted("Note: 'bd cleanup' is now 'bd admin cleanup'")) + cleanupCmd.Run(cmd, args) + }, +} + +var compactAliasCmd = &cobra.Command{ + Use: "compact", + Hidden: true, + Short: "Alias for 'bd admin compact' (deprecated)", + Long: compactCmd.Long, + Run: func(cmd *cobra.Command, args []string) { + fmt.Fprintln(os.Stderr, ui.RenderMuted("Note: 'bd compact' is now 'bd admin compact'")) + compactCmd.Run(cmd, args) + }, +} + +var resetAliasCmd = &cobra.Command{ + Use: "reset", + Hidden: true, + Short: "Alias for 'bd admin reset' (deprecated)", + Long: resetCmd.Long, + Run: func(cmd *cobra.Command, args []string) { + fmt.Fprintln(os.Stderr, ui.RenderMuted("Note: 'bd reset' is now 'bd admin reset'")) + resetCmd.Run(cmd, args) + }, +} + +func init() { + // Copy flags from original commands to aliases, binding to same global variables + // This ensures that when the alias command runs, the global flag variables are set correctly + + // Cleanup alias flags - these read from cmd.Flags() in the Run function + cleanupAliasCmd.Flags().BoolP("force", "f", false, "Actually delete (without this flag, shows error)") + cleanupAliasCmd.Flags().Bool("dry-run", false, "Preview what would be deleted without making changes") + cleanupAliasCmd.Flags().Bool("cascade", false, "Recursively delete all dependent issues") + cleanupAliasCmd.Flags().Int("older-than", 0, "Only delete issues closed more than N days ago (0 = all closed issues)") + cleanupAliasCmd.Flags().Bool("hard", false, "Bypass tombstone TTL safety; use --older-than days as cutoff") + cleanupAliasCmd.Flags().Bool("ephemeral", false, "Only delete closed wisps (transient molecules)") + + // Compact alias flags - must bind to same global variables as compactCmd + compactAliasCmd.Flags().BoolVar(&compactDryRun, "dry-run", false, "Preview without compacting") + compactAliasCmd.Flags().IntVar(&compactTier, "tier", 1, "Compaction tier (1 or 2)") + compactAliasCmd.Flags().BoolVar(&compactAll, "all", false, "Process all candidates") + compactAliasCmd.Flags().StringVar(&compactID, "id", "", "Compact specific issue") + compactAliasCmd.Flags().BoolVar(&compactForce, "force", false, "Force compact (bypass checks, requires --id)") + compactAliasCmd.Flags().IntVar(&compactBatch, "batch-size", 10, "Issues per batch") + compactAliasCmd.Flags().IntVar(&compactWorkers, "workers", 5, "Parallel workers") + compactAliasCmd.Flags().BoolVar(&compactStats, "stats", false, "Show compaction statistics") + compactAliasCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format") + compactAliasCmd.Flags().BoolVar(&compactAnalyze, "analyze", false, "Analyze mode: export candidates for agent review") + compactAliasCmd.Flags().BoolVar(&compactApply, "apply", false, "Apply mode: accept agent-provided summary") + compactAliasCmd.Flags().BoolVar(&compactAuto, "auto", false, "Auto mode: AI-powered compaction (legacy)") + compactAliasCmd.Flags().BoolVar(&compactPrune, "prune", false, "Prune mode: remove expired tombstones from issues.jsonl") + compactAliasCmd.Flags().IntVar(&compactOlderThan, "older-than", 0, "Prune tombstones older than N days (default: 30)") + compactAliasCmd.Flags().StringVar(&compactSummary, "summary", "", "Path to summary file (use '-' for stdin)") + compactAliasCmd.Flags().StringVar(&compactActor, "actor", "agent", "Actor name for audit trail") + compactAliasCmd.Flags().IntVar(&compactLimit, "limit", 0, "Limit number of candidates (0 = no limit)") + + // Reset alias flags - these read from cmd.Flags() in the Run function + resetAliasCmd.Flags().Bool("force", false, "Actually perform the reset (required)") + + // Register hidden aliases on root command + rootCmd.AddCommand(cleanupAliasCmd) + rootCmd.AddCommand(compactAliasCmd) + rootCmd.AddCommand(resetAliasCmd) +} diff --git a/cmd/bd/cleanup.go b/cmd/bd/cleanup.go index dd7fe371..9ccca95a 100644 --- a/cmd/bd/cleanup.go +++ b/cmd/bd/cleanup.go @@ -26,9 +26,8 @@ func showCleanupDeprecationHint() { } var cleanupCmd = &cobra.Command{ - Use: "cleanup", - GroupID: "maint", - Short: "Delete closed issues and prune expired tombstones", + Use: "cleanup", + Short: "Delete closed issues and prune expired tombstones", Long: `Delete closed issues and prune expired tombstones to reduce database size. This command: @@ -271,5 +270,5 @@ func init() { cleanupCmd.Flags().Int("older-than", 0, "Only delete issues closed more than N days ago (0 = all closed issues)") cleanupCmd.Flags().Bool("hard", false, "Bypass tombstone TTL safety; use --older-than days as cutoff") cleanupCmd.Flags().Bool("ephemeral", false, "Only delete closed wisps (transient molecules)") - rootCmd.AddCommand(cleanupCmd) + // Note: cleanupCmd is added to adminCmd in admin.go } diff --git a/cmd/bd/compact.go b/cmd/bd/compact.go index 69c5edac..402b379c 100644 --- a/cmd/bd/compact.go +++ b/cmd/bd/compact.go @@ -1195,5 +1195,5 @@ func init() { compactCmd.Flags().StringVar(&compactActor, "actor", "agent", "Actor name for audit trail") compactCmd.Flags().IntVar(&compactLimit, "limit", 0, "Limit number of candidates (0 = no limit)") - rootCmd.AddCommand(compactCmd) + // Note: compactCmd is added to adminCmd in admin.go } diff --git a/cmd/bd/reset.go b/cmd/bd/reset.go index 24e6fc4f..d442e34e 100644 --- a/cmd/bd/reset.go +++ b/cmd/bd/reset.go @@ -15,9 +15,8 @@ import ( ) var resetCmd = &cobra.Command{ - Use: "reset", - GroupID: "advanced", - Short: "Remove all beads data and configuration", + Use: "reset", + Short: "Remove all beads data and configuration", Long: `Reset beads to an uninitialized state, removing all local data. This command removes: @@ -37,7 +36,7 @@ Examples: func init() { resetCmd.Flags().Bool("force", false, "Actually perform the reset (required)") - rootCmd.AddCommand(resetCmd) + // Note: resetCmd is added to adminCmd in admin.go } func runReset(cmd *cobra.Command, args []string) { diff --git a/commands/compact.md b/commands/compact.md index 29f6d3d4..60bb20ea 100644 --- a/commands/compact.md +++ b/commands/compact.md @@ -12,11 +12,11 @@ Reduce database size by summarizing closed issues no longer actively referenced. ## Usage -- **Preview candidates**: `bd compact --dry-run` -- **Compact all eligible**: `bd compact --all` -- **Compact specific issue**: `bd compact --id bd-42` -- **Force compact**: `bd compact --id bd-42 --force` (bypass age checks) -- **View statistics**: `bd compact --stats` +- **Preview candidates**: `bd admin compact --dry-run` +- **Compact all eligible**: `bd admin compact --all` +- **Compact specific issue**: `bd admin compact --id bd-42` +- **Force compact**: `bd admin compact --id bd-42 --force` (bypass age checks) +- **View statistics**: `bd admin compact --stats` ## Options diff --git a/docs/CLI_REFERENCE.md b/docs/CLI_REFERENCE.md index a5041ccf..c1299bd9 100644 --- a/docs/CLI_REFERENCE.md +++ b/docs/CLI_REFERENCE.md @@ -296,10 +296,10 @@ bd --actor alice ```bash # Clean up closed issues (bulk deletion) -bd cleanup --force --json # Delete ALL closed issues -bd cleanup --older-than 30 --force --json # Delete closed >30 days ago -bd cleanup --dry-run --json # Preview what would be deleted -bd cleanup --older-than 90 --cascade --force --json # Delete old + dependents +bd admin cleanup --force --json # Delete ALL closed issues +bd admin cleanup --older-than 30 --force --json # Delete closed >30 days ago +bd admin cleanup --dry-run --json # Preview what would be deleted +bd admin cleanup --older-than 90 --cascade --force --json # Delete old + dependents ``` ### Duplicate Detection & Merging @@ -319,15 +319,15 @@ bd merge bd-42 bd-43 --into bd-41 --dry-run # Preview merge ```bash # Agent-driven compaction -bd compact --analyze --json # Get candidates for review -bd compact --analyze --tier 1 --limit 10 --json # Limited batch -bd compact --apply --id bd-42 --summary summary.txt # Apply compaction -bd compact --apply --id bd-42 --summary - < summary.txt # From stdin -bd compact --stats --json # Show statistics +bd admin compact --analyze --json # Get candidates for review +bd admin compact --analyze --tier 1 --limit 10 --json # Limited batch +bd admin compact --apply --id bd-42 --summary summary.txt # Apply compaction +bd admin compact --apply --id bd-42 --summary - < summary.txt # From stdin +bd admin compact --stats --json # Show statistics # Legacy AI-powered compaction (requires ANTHROPIC_API_KEY) -bd compact --auto --dry-run --all # Preview -bd compact --auto --all --tier 1 # Auto-compact tier 1 +bd admin compact --auto --dry-run --all # Preview +bd admin compact --auto --all --tier 1 # Auto-compact tier 1 # Restore compacted issue from git history bd restore # View full history at time of compaction diff --git a/docs/CONFIG.md b/docs/CONFIG.md index f4204a39..07a3fc82 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -576,7 +576,7 @@ jira_project = get_config("jira.project") Some bd commands automatically use configuration: -- `bd compact` uses `compact_tier1_days`, `compact_tier1_dep_levels`, etc. +- `bd admin compact` uses `compact_tier1_days`, `compact_tier1_dep_levels`, etc. - `bd init` sets `issue_prefix` External integration scripts can read configuration to sync with Jira, Linear, GitHub, etc. diff --git a/docs/DELETIONS.md b/docs/DELETIONS.md index 4fd55d97..9ba41d25 100644 --- a/docs/DELETIONS.md +++ b/docs/DELETIONS.md @@ -66,7 +66,7 @@ Tombstones expire after a configurable TTL (default: 30 days). This prevents unb ### How Expiration Works 1. Tombstones older than TTL + 1 hour grace period are eligible for pruning -2. `bd compact` removes expired tombstones from `issues.jsonl` +2. `bd admin compact` removes expired tombstones from `issues.jsonl` 3. Git history fallback handles edge cases where pruned tombstones are needed ### Configuration @@ -85,7 +85,7 @@ bd config set tombstone.ttl_days 60 ### Manual Pruning ```bash -bd compact # Prune expired tombstones (and other compaction) +bd admin compact # Prune expired tombstones (and other compaction) ``` ## Conflict Resolution @@ -163,7 +163,7 @@ If you have many old tombstones: bd list --status=tombstone | wc -l # Prune expired tombstones -bd compact +bd admin compact ``` ## Design Rationale diff --git a/docs/FAQ.md b/docs/FAQ.md index 90457f1d..360416fa 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -333,10 +333,10 @@ Use compaction to remove old closed issues: ```bash # Preview what would be compacted -bd compact --dry-run --all +bd admin compact --dry-run --all # Compact issues closed more than 90 days ago -bd compact --days 90 +bd admin compact --days 90 ``` Or split your project into multiple databases: diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 36651fac..dc82464d 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -178,16 +178,16 @@ As your project accumulates closed issues, the database grows. Manage size with ```bash # View compaction statistics -bd compact --stats +bd admin compact --stats # Preview compaction candidates (30+ days closed) -bd compact --analyze --json --no-daemon +bd admin compact --analyze --json --no-daemon # Apply agent-generated summary -bd compact --apply --id bd-42 --summary summary.txt --no-daemon +bd admin compact --apply --id bd-42 --summary summary.txt --no-daemon # Immediately delete closed issues (CAUTION: permanent!) -bd cleanup --force +bd admin cleanup --force ``` **When to compact:** diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 55c2e684..241dfba1 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -486,10 +486,10 @@ Check database size and consider compaction: bd stats # Preview compaction candidates -bd compact --dry-run --all +bd admin compact --dry-run --all # Compact old closed issues -bd compact --days 90 +bd admin compact --days 90 ``` ### Large JSONL files @@ -501,7 +501,7 @@ If `.beads/issues.jsonl` is very large: ls -lh .beads/issues.jsonl # Remove old closed issues -bd compact --days 90 +bd admin compact --days 90 # Or split into multiple projects cd ~/project/component1 && bd init --prefix comp1 diff --git a/examples/compaction/README.md b/examples/compaction/README.md index 428fc3ed..f69b8cf7 100644 --- a/examples/compaction/README.md +++ b/examples/compaction/README.md @@ -171,7 +171,7 @@ Track compaction costs: ```bash # Show stats after compaction -bd compact --stats +bd admin compact --stats # Estimate monthly cost # (issues_compacted / 1000) * $1.00 diff --git a/examples/compaction/auto-compact.sh b/examples/compaction/auto-compact.sh index 6e0fed87..55c18583 100755 --- a/examples/compaction/auto-compact.sh +++ b/examples/compaction/auto-compact.sh @@ -46,7 +46,7 @@ fi # Check eligible issues echo "Checking eligible issues (Tier $TIER)..." -ELIGIBLE=$(bd compact --dry-run --all --tier "$TIER" --json 2>/dev/null | jq '. | length' || echo "0") +ELIGIBLE=$(bd admin compact --dry-run --all --tier "$TIER" --json 2>/dev/null | jq '. | length' || echo "0") if [ -z "$ELIGIBLE" ] || [ "$ELIGIBLE" = "null" ]; then ELIGIBLE=0 @@ -61,18 +61,18 @@ fi if [ "$DRY_RUN" = true ]; then echo "🔍 Dry run mode - showing candidates:" - bd compact --dry-run --all --tier "$TIER" + bd admin compact --dry-run --all --tier "$TIER" exit 0 fi # Run compaction echo "🗜️ Compacting $ELIGIBLE issues (Tier $TIER)..." -bd compact --all --tier "$TIER" +bd admin compact --all --tier "$TIER" # Show stats echo echo "📊 Statistics:" -bd compact --stats +bd admin compact --stats echo echo "✅ Auto-compaction complete" diff --git a/examples/compaction/cron-compact.sh b/examples/compaction/cron-compact.sh index 7fc592c0..827e3980 100755 --- a/examples/compaction/cron-compact.sh +++ b/examples/compaction/cron-compact.sh @@ -48,17 +48,17 @@ git pull origin main 2>&1 | tee -a "$LOG_FILE" # Tier 1 compaction log "Running Tier 1 compaction..." -TIER1_COUNT=$(bd compact --all --json 2>&1 | jq '. | length' || echo "0") +TIER1_COUNT=$(bd admin compact --all --json 2>&1 | jq '. | length' || echo "0") log "Compacted $TIER1_COUNT Tier 1 issues" # Tier 2 compaction log "Running Tier 2 compaction..." -TIER2_COUNT=$(bd compact --all --tier 2 --json 2>&1 | jq '. | length' || echo "0") +TIER2_COUNT=$(bd admin compact --all --tier 2 --json 2>&1 | jq '. | length' || echo "0") log "Compacted $TIER2_COUNT Tier 2 issues" # Show statistics log "Compaction statistics:" -bd compact --stats 2>&1 | tee -a "$LOG_FILE" +bd admin compact --stats 2>&1 | tee -a "$LOG_FILE" # Commit and push if changes exist if git diff --quiet .beads/issues.jsonl issues.db 2>/dev/null; then diff --git a/examples/compaction/workflow.sh b/examples/compaction/workflow.sh index 396d72cb..29d0af27 100755 --- a/examples/compaction/workflow.sh +++ b/examples/compaction/workflow.sh @@ -30,14 +30,14 @@ fi # Preview candidates echo "--- Preview Tier 1 Candidates ---" -bd compact --dry-run --all +bd admin compact --dry-run --all echo read -p "Proceed with Tier 1 compaction? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then echo "--- Running Tier 1 Compaction ---" - bd compact --all + bd admin compact --all echo "✅ Tier 1 compaction complete" else echo "⏭️ Skipping Tier 1" @@ -46,14 +46,14 @@ fi # Preview Tier 2 echo echo "--- Preview Tier 2 Candidates ---" -bd compact --dry-run --all --tier 2 +bd admin compact --dry-run --all --tier 2 echo read -p "Proceed with Tier 2 compaction? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then echo "--- Running Tier 2 Compaction ---" - bd compact --all --tier 2 + bd admin compact --all --tier 2 echo "✅ Tier 2 compaction complete" else echo "⏭️ Skipping Tier 2" @@ -62,7 +62,7 @@ fi # Show stats echo echo "--- Final Statistics ---" -bd compact --stats +bd admin compact --stats echo echo "=== Compaction Complete ===" diff --git a/skills/beads/SKILL.md b/skills/beads/SKILL.md index dd138c10..966f96dd 100644 --- a/skills/beads/SKILL.md +++ b/skills/beads/SKILL.md @@ -434,7 +434,7 @@ Shows: | `bd daemon` | Background sync manager | "Start auto-sync daemon" | | **CLEANUP COMMANDS** | | | | `bd delete ` | Delete issues | "Delete test task" (requires --force) | -| `bd compact` | Archive old closed tasks | "Compress database" | +| `bd admin compact` | Archive old closed tasks | "Compress database" | | **REPORTING COMMANDS** | | | | `bd stats` | Project metrics | "Show project health" | | `bd audit record` | Log interactions | "Record this LLM call" | diff --git a/skills/beads/references/CLI_REFERENCE.md b/skills/beads/references/CLI_REFERENCE.md index 91843f0c..78612b8c 100644 --- a/skills/beads/references/CLI_REFERENCE.md +++ b/skills/beads/references/CLI_REFERENCE.md @@ -285,10 +285,10 @@ bd --actor alice ```bash # Clean up closed issues (bulk deletion) -bd cleanup --force --json # Delete ALL closed issues -bd cleanup --older-than 30 --force --json # Delete closed >30 days ago -bd cleanup --dry-run --json # Preview what would be deleted -bd cleanup --older-than 90 --cascade --force --json # Delete old + dependents +bd admin cleanup --force --json # Delete ALL closed issues +bd admin cleanup --older-than 30 --force --json # Delete closed >30 days ago +bd admin cleanup --dry-run --json # Preview what would be deleted +bd admin cleanup --older-than 90 --cascade --force --json # Delete old + dependents ``` ### Duplicate Detection & Merging @@ -308,15 +308,15 @@ bd merge bd-42 bd-43 --into bd-41 --dry-run # Preview merge ```bash # Agent-driven compaction -bd compact --analyze --json # Get candidates for review -bd compact --analyze --tier 1 --limit 10 --json # Limited batch -bd compact --apply --id bd-42 --summary summary.txt # Apply compaction -bd compact --apply --id bd-42 --summary - < summary.txt # From stdin -bd compact --stats --json # Show statistics +bd admin compact --analyze --json # Get candidates for review +bd admin compact --analyze --tier 1 --limit 10 --json # Limited batch +bd admin compact --apply --id bd-42 --summary summary.txt # Apply compaction +bd admin compact --apply --id bd-42 --summary - < summary.txt # From stdin +bd admin compact --stats --json # Show statistics # Legacy AI-powered compaction (requires ANTHROPIC_API_KEY) -bd compact --auto --dry-run --all # Preview -bd compact --auto --all --tier 1 # Auto-compact tier 1 +bd admin compact --auto --dry-run --all # Preview +bd admin compact --auto --all --tier 1 # Auto-compact tier 1 # Restore compacted issue from git history bd restore # View full history at time of compaction