Snapshots YAML template content in a new `plan_template_versions` table
whenever a plan is created from a template. Plans reference their version
via `template_version_id` so existing plans are unaffected by future
template file edits.
Key changes:
- Migration 0006: create `plan_template_versions` table (slug, version,
name, content JSON, content_hash SHA-256); add nullable FK
`template_version_id` to `agent_plans`
- Model `PlanTemplateVersion`: `findOrCreateFromTemplate()` deduplicates
identical content by hash; `historyFor()` returns versions newest-first
- `AgentPlan`: add `template_version_id` fillable and `templateVersion()`
relationship
- `PlanTemplateService::createPlan()`: snapshot raw template before
variable substitution; store version id and version number in metadata;
add `getVersionHistory()` and `getVersion()` public methods
- Tests: `TemplateVersionManagementTest` covering model behaviour, plan
creation snapshotting, deduplication, history ordering, and service
methods
Closes#35
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add `agentic.plan_retention_days` config (default 90 days via AGENTIC_PLAN_RETENTION_DAYS env)
- Add SoftDeletes and `archived_at` timestamp to AgentPlan model
- Add migration for `deleted_at` and `archived_at` columns on agent_plans
- Create `agentic:plan-cleanup` command with --dry-run and --days options
- Schedule retention cleanup to run daily via service provider
- Register PlanRetentionCommand in ConsoleBooting handler
- Add PlanRetentionTest feature test suite covering all retention scenarios
- Fix archive() to store archived_at as dedicated column (not metadata string)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Verify agent_sessions.session_id: unique() constraint creates an
implicit unique index (agent_sessions_session_id_unique) which is
sufficient for string lookups; no additional index required
- Drop redundant agent_plans_slug_index: the unique() constraint on
slug already provides agent_plans_slug_unique covering all lookups
- Add compound (workspace_id, slug) index on agent_plans for the
common routing pattern WHERE workspace_id = ? AND slug = ?
- Verify agent_workspace_states.key: already indexed via ->index('key')
in migration 000003; no additional index required
- Mark DB-002 as resolved in TODO.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Feature test covering PromptVersion creation, relationships (prompt,
creator), restore() rollback method, and version history tracking. Also
add idempotent migration for prompts and prompt_versions tables required
by the test suite.
Closes#15
- All package migrations now guarded with hasTable()/hasColumn()
so they coexist with the consolidated app-level migration
- Migration 000001: aligned agent_api_keys and agent_sessions
schemas with current model expectations (key not key_hash,
session_id not uuid, etc.)
- Migration 000002: hasColumn guards for ALTER TABLE safety
- Migration 000003: hasTable guards for all CREATE TABLE calls
- Dashboard: wrap all queries in try/catch so /hub/agents loads
even when tables haven't been migrated yet
Co-Authored-By: Virgil <virgil@lethean.io>
P2 Items Completed (P2-062 to P2-068):
- Switch AgentApiKey from SHA-256 to Argon2id hashing
- Add 200+ tests for models, services, and AI providers
- Create agent_plans migration with phases and workspace states
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>