claude-flow-novice
Version:
Claude Flow Novice - Advanced orchestration platform for multi-agent AI workflows with CFN Loop architecture Includes Local RuVector Accelerator and all CFN skills for complete functionality.
734 lines (540 loc) • 18.3 kB
Markdown
# Artifact Registry Adoption Guide
**Version:** 1.0.0
**Last Updated:** 2025-11-15
**Integration Point:** 2.11 - Artifact Registry
## Table of Contents
1. [Overview](#overview)
2. [Quick Start](#quick-start)
3. [API Reference](#api-reference)
4. [Query Patterns](#query-patterns)
5. [TTL and Retention Policies](#ttl-and-retention-policies)
6. [Cleanup Automation](#cleanup-automation)
7. [Migration Guide](#migration-guide)
8. [Best Practices](#best-practices)
9. [Troubleshooting](#troubleshooting)
## Overview
The Artifact Registry provides centralized management for all project artifacts with automatic TTL-based cleanup, comprehensive querying, and audit trails.
### Key Features
- **Centralized Storage**: All artifacts in `artifacts/registry/` with organized subdirectories
- **Automatic TTL Cleanup**: Policy-based expiration and archival (ephemeral, standard, permanent)
- **Comprehensive Metadata**: Tags, versioning, lineage tracking, checksums
- **Query Interface**: Flexible filtering by type, status, tags, dates
- **Concurrent Safety**: WAL mode for safe concurrent access
- **Audit Trail**: Complete lifecycle tracking (created, updated, archived, deleted)
### Artifact Types
- `code` - Source code files
- `documentation` - Markdown, PDFs, text files
- `test` - Test files and reports
- `config` - Configuration files
- `binary` - Compiled binaries and executables
- `data` - Data files (CSV, JSON, databases)
- `model` - Machine learning models
- `report` - Generated reports and analytics
- `other` - Miscellaneous artifacts
## Quick Start
### 1. Installation
```typescript
import { ArtifactRegistry } from '../src/lib/artifact-registry';
// Initialize registry (creates database if needed)
const registry = new ArtifactRegistry('./artifacts/database/registry.db');
// Or use singleton pattern
const registry = ArtifactRegistry.getInstance('./artifacts/database/registry.db');
```
### 2. Create Your First Artifact
```typescript
import { ArtifactMetadata } from '../src/lib/artifact-registry';
const metadata: ArtifactMetadata = {
name: 'api-server.ts',
type: 'code',
format: 'typescript',
storage_location: './artifacts/registry/codes/api-server.ts',
tags: ['backend', 'api'],
retention_policy: 'standard', // 30 days retention
metadata: {
author: 'backend-developer-agent',
purpose: 'REST API implementation'
}
};
const artifact = registry.createArtifact(metadata);
console.log(`Created artifact: ${artifact.id}`);
```
### 3. Query Artifacts
```typescript
// Find all code artifacts
const codeArtifacts = registry.listArtifacts({ type: 'code' });
// Find artifacts by tags
const backendArtifacts = registry.listArtifacts({ tags: ['backend'] });
// Find expired artifacts
const expired = registry.findExpiredArtifacts();
```
### 4. Archive and Delete
```typescript
// Archive an artifact (mark as archived)
const archived = registry.archiveArtifact(artifact.id);
// Delete an artifact (soft delete)
const deleted = registry.deleteArtifact(artifact.id);
```
## API Reference
### ArtifactRegistry Class
#### Constructor
```typescript
constructor(dbPath: string)
```
Creates new registry instance and initializes database schema.
**Parameters:**
- `dbPath` (string) - Path to SQLite database file
**Example:**
```typescript
const registry = new ArtifactRegistry('./artifacts/database/registry.db');
```
#### createArtifact(metadata)
Creates new artifact with metadata.
**Parameters:**
- `metadata` (ArtifactMetadata) - Artifact metadata
**Returns:** `Artifact` - Created artifact with generated ID
**Throws:**
- `ArtifactValidationError` - Invalid metadata
- `ArtifactDatabaseError` - Database operation failed
**Example:**
```typescript
const artifact = registry.createArtifact({
name: 'test-report.pdf',
type: 'report',
storage_location: './artifacts/registry/reports/test-report.pdf',
retention_policy: 'ephemeral', // 7 days
tags: ['testing', 'qa']
});
```
#### getArtifact(id)
Retrieves artifact by ID.
**Parameters:**
- `id` (string) - Artifact ID
**Returns:** `Artifact | null` - Found artifact or null
**Example:**
```typescript
const artifact = registry.getArtifact('artifact-1731939872-abc123');
if (artifact) {
console.log(`Found: ${artifact.name}`);
}
```
#### listArtifacts(filters?)
Lists artifacts with optional filters.
**Parameters:**
- `filters` (ArtifactFilters, optional) - Query filters
**Returns:** `Artifact[]` - Array of matching artifacts
**Example:**
```typescript
// Filter by multiple criteria
const artifacts = registry.listArtifacts({
type: 'code',
status: 'active',
tags: ['frontend'],
created_after: new Date('2025-01-01'),
limit: 10
});
```
#### archiveArtifact(id)
Archives an artifact (marks as archived, not deleted).
**Parameters:**
- `id` (string) - Artifact ID
**Returns:** `Artifact` - Updated artifact
**Throws:**
- `ArtifactNotFoundError` - Artifact not found
- `ArtifactValidationError` - Cannot archive deleted artifact
**Example:**
```typescript
const archived = registry.archiveArtifact('artifact-1731939872-abc123');
console.log(`Archived at: ${archived.archived_at}`);
```
#### deleteArtifact(id)
Soft deletes an artifact (marks as deleted, preserves record).
**Parameters:**
- `id` (string) - Artifact ID
**Returns:** `Artifact` - Updated artifact
**Throws:**
- `ArtifactNotFoundError` - Artifact not found
**Example:**
```typescript
const deleted = registry.deleteArtifact('artifact-1731939872-abc123');
console.log(`Deleted at: ${deleted.deleted_at}`);
```
#### getStatsByRetentionPolicy()
Gets artifact statistics grouped by retention policy.
**Returns:** `Record<RetentionPolicy, ArtifactStats>`
**Example:**
```typescript
const stats = registry.getStatsByRetentionPolicy();
console.log(`Standard policy: ${stats.standard.total} total, ${stats.standard.active} active`);
```
#### findExpiredArtifacts()
Finds all expired artifacts eligible for archival.
**Returns:** `Artifact[]` - Array of expired artifacts
**Example:**
```typescript
const expired = registry.findExpiredArtifacts();
console.log(`Found ${expired.length} expired artifacts`);
```
## Query Patterns
### Filter Options
```typescript
interface ArtifactFilters {
type?: ArtifactType; // Filter by artifact type
status?: ArtifactStatus; // 'active', 'archived', 'deleted'
retention_policy?: RetentionPolicy; // 'ephemeral', 'standard', 'permanent', 'custom'
swarm_id?: string; // Filter by swarm
agent_id?: string; // Filter by agent
task_id?: string; // Filter by task
tags?: string[]; // Filter by tags (AND logic)
cleanup_eligible?: boolean; // Only cleanup-eligible artifacts
created_after?: Date; // Created after date
created_before?: Date; // Created before date
expires_before?: Date; // Expires before date
limit?: number; // Pagination limit
offset?: number; // Pagination offset
}
```
### Common Query Examples
#### Find All Active Code Artifacts
```typescript
const activeCode = registry.listArtifacts({
type: 'code',
status: 'active'
});
```
#### Find Recent Documentation
```typescript
const recentDocs = registry.listArtifacts({
type: 'documentation',
created_after: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last 7 days
limit: 20
});
```
#### Find Artifacts by Multiple Tags
```typescript
const backendTests = registry.listArtifacts({
type: 'test',
tags: ['backend', 'integration']
});
```
#### Find Expiring Soon
```typescript
const expiringSoon = registry.listArtifacts({
status: 'active',
expires_before: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // Next 7 days
});
```
#### Paginate Through All Artifacts
```typescript
const pageSize = 50;
let offset = 0;
let hasMore = true;
while (hasMore) {
const page = registry.listArtifacts({ limit: pageSize, offset });
// Process page
page.forEach(artifact => {
console.log(`${artifact.name} - ${artifact.type}`);
});
offset += pageSize;
hasMore = page.length === pageSize;
}
```
#### Find Artifacts by Agent
```typescript
const agentArtifacts = registry.listArtifacts({
agent_id: 'backend-developer-1731939872',
status: 'active'
});
```
## TTL and Retention Policies
### Retention Policy Types
| Policy | Retention Period | Use Case |
|--------|-----------------|----------|
| `ephemeral` | 7 days | Temporary files, debug logs, cache |
| `standard` | 30 days | Most artifacts, work products |
| `permanent` | Never expires | Critical artifacts, compliance docs |
| `custom` | User-defined | Flexible retention needs |
### Retention Policy Configuration
```typescript
// Ephemeral (7 days)
const tempArtifact = registry.createArtifact({
name: 'debug.log',
type: 'other',
storage_location: './artifacts/registry/other/debug.log',
retention_policy: 'ephemeral'
});
// Standard (30 days) - default
const standardArtifact = registry.createArtifact({
name: 'api.ts',
type: 'code',
storage_location: './artifacts/registry/codes/api.ts',
retention_policy: 'standard'
});
// Permanent (never expires)
const permanentArtifact = registry.createArtifact({
name: 'license.pdf',
type: 'documentation',
storage_location: './artifacts/registry/documentation/license.pdf',
retention_policy: 'permanent'
});
// Custom retention
const customArtifact = registry.createArtifact({
name: 'quarterly-report.pdf',
type: 'report',
storage_location: './artifacts/registry/reports/quarterly-report.pdf',
retention_policy: 'custom',
retention_days: 90 // 90 days
});
```
### Automatic Expiration
The database automatically calculates `expires_at` using triggers:
```sql
expires_at = created_at + retention_days
```
**Example:**
- Created: 2025-01-01 00:00:00
- Retention: 30 days (standard)
- Expires: 2025-01-31 00:00:00
## Cleanup Automation
### Cleanup Script Usage
The `artifact-cleanup.sh` script automates TTL-based cleanup:
```bash
# Dry run (preview what would be cleaned)
./scripts/artifact-cleanup.sh --dry-run
# Production cleanup
./scripts/artifact-cleanup.sh
# Cleanup specific retention policy
./scripts/artifact-cleanup.sh --policy ephemeral
# Custom archive retention (default 90 days)
./scripts/artifact-cleanup.sh --archive-days 180
# Verbose logging
./scripts/artifact-cleanup.sh --verbose
# Custom database and log paths
./scripts/artifact-cleanup.sh \
--db-path ./artifacts/database/registry.db \
--log-file ./artifacts/logs/cleanup.log
```
### Cleanup Process
1. **Find Expired Active Artifacts**
- Query: `status = 'active' AND datetime('now') >= expires_at`
- Action: Archive (set `status = 'archived'`, `archived_at = now`)
2. **Find Old Archived Artifacts**
- Query: `status = 'archived' AND datetime('now') >= archived_at + archive_days`
- Action: Delete (set `status = 'deleted'`, `deleted_at = now`)
### Cron Configuration
Set up automatic cleanup with cron:
```bash
# Edit crontab
crontab -e
# Run cleanup daily at 2 AM
0 2 * * * /path/to/claude-flow-novice/scripts/artifact-cleanup.sh >> /path/to/cleanup-cron.log 2>&1
# Run cleanup weekly on Sunday at 3 AM
0 3 * * 0 /path/to/claude-flow-novice/scripts/artifact-cleanup.sh >> /path/to/cleanup-cron.log 2>&1
```
### Monitoring Cleanup
```bash
# View cleanup logs
tail -f ./artifacts/logs/cleanup.log
# Check statistics before cleanup
./scripts/artifact-cleanup.sh --dry-run
# View database statistics
sqlite3 ./artifacts/database/registry.db <<EOF
SELECT
retention_policy,
COUNT(*) as total,
SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active,
SUM(CASE WHEN status = 'archived' THEN 1 ELSE 0 END) as archived,
SUM(CASE WHEN status = 'deleted' THEN 1 ELSE 0 END) as deleted
FROM artifacts
GROUP BY retention_policy;
EOF
```
## Migration Guide
### Migrating Scattered Artifacts
Use the migration script to consolidate scattered artifacts:
```bash
# Dry run to preview migration
./scripts/migrate-artifacts.sh \
--dry-run \
--source-dirs "/tmp,docs,artifacts" \
--auto-detect-type \
--verbose
# Production migration
./scripts/migrate-artifacts.sh \
--source-dirs "/tmp,docs,artifacts,legacy" \
--auto-detect-type \
--registry-path ./artifacts/registry \
--db-path ./artifacts/database/registry.db
```
### Migration Options
```bash
--source-dirs <dirs> # Comma-separated directories to scan
--registry-path <path> # Centralized registry location
--db-path <path> # Database path
--exclude-patterns <pat> # Exclude file patterns (comma-separated)
--auto-detect-type # Auto-detect artifact type from extension
--dry-run # Preview without changes
--verbose # Detailed logging
```
### Manual Migration Example
```typescript
import { ArtifactRegistry } from '../src/lib/artifact-registry';
import { readdirSync, copyFileSync } from 'fs';
import { join } from 'path';
const registry = new ArtifactRegistry('./artifacts/database/registry.db');
// Find scattered files
const scatteredFiles = readdirSync('/tmp/scattered-artifacts');
for (const file of scatteredFiles) {
const sourcePath = join('/tmp/scattered-artifacts', file);
const destPath = join('./artifacts/registry/other', file);
// Copy file to registry
copyFileSync(sourcePath, destPath);
// Register in database
registry.createArtifact({
name: file,
type: 'other',
storage_location: destPath,
retention_policy: 'standard'
});
console.log(`Migrated: ${file}`);
}
```
## Best Practices
### 1. Choose Appropriate Retention Policies
- **Ephemeral**: Debug logs, temp files, cache
- **Standard**: Code, tests, documentation
- **Permanent**: Licenses, compliance docs, contracts
- **Custom**: Quarterly reports, backups
### 2. Use Meaningful Tags
```typescript
// Good: Specific, searchable tags
tags: ['backend', 'authentication', 'jwt', 'v2.0']
// Avoid: Generic or redundant tags
tags: ['file', 'artifact', 'thing']
```
### 3. Include Rich Metadata
```typescript
metadata: {
author: 'backend-developer-agent',
purpose: 'JWT authentication implementation',
dependencies: ['jsonwebtoken', 'bcrypt'],
build_info: {
commit: 'abc123',
timestamp: '2025-11-15T10:30:00Z'
}
}
```
### 4. Use Lineage Tracking
```typescript
// Track artifact versions and lineage
const v2Artifact = registry.createArtifact({
name: 'api-v2.ts',
type: 'code',
storage_location: './artifacts/registry/codes/api-v2.ts',
version: 2,
parent_artifact_id: v1Artifact.id,
artifact_chain: [v0Id, v1Id] // Full lineage
});
```
### 5. Centralize All Artifacts
**DO:**
```typescript
storage_location: './artifacts/registry/codes/api.ts'
storage_location: './artifacts/registry/reports/test-report.pdf'
```
**DON'T:**
```typescript
storage_location: '/tmp/api.ts' // Scattered
storage_location: './docs/random.md' // Not centralized
```
### 6. Regular Cleanup Monitoring
```bash
# Weekly review of cleanup operations
grep "Cleanup Summary" ./artifacts/logs/cleanup.log | tail -10
# Alert on high error counts
ERRORS=$(grep "Errors:" ./artifacts/logs/cleanup.log | tail -1 | awk '{print $NF}')
if [ "$ERRORS" -gt 0 ]; then
echo "Cleanup errors detected: $ERRORS"
fi
```
### 7. Database Backup
```bash
# Backup before cleanup
cp ./artifacts/database/registry.db ./artifacts/database/registry.db.backup
# Automated backup in cleanup script
./scripts/artifact-cleanup.sh --backup
```
## Troubleshooting
### Issue: Database locked error
**Cause:** Concurrent access without WAL mode
**Solution:**
```typescript
// WAL mode is enabled by default in ArtifactRegistry constructor
this.db.pragma('journal_mode = WAL');
```
### Issue: Artifacts not expiring
**Cause:** Permanent retention policy or missing expires_at
**Check:**
```sql
SELECT id, name, retention_policy, retention_days, expires_at
FROM artifacts
WHERE status = 'active' AND retention_policy != 'permanent';
```
**Fix:**
```sql
-- Manually set expires_at if missing
UPDATE artifacts
SET expires_at = datetime(created_at, '+' || retention_days || ' days')
WHERE expires_at IS NULL AND retention_policy != 'permanent';
```
### Issue: Migration script skipping files
**Cause:** Files match exclusion patterns or already in registry
**Debug:**
```bash
./scripts/migrate-artifacts.sh \
--dry-run \
--verbose \
--exclude-patterns ".git,.DS_Store"
```
### Issue: Cleanup script reports errors
**Check logs:**
```bash
tail -50 ./artifacts/logs/cleanup.log
```
**Common causes:**
- Database permission issues
- Missing artifacts table
- Invalid retention policy values
### Issue: Query performance slow
**Solution:** Ensure indexes exist
```sql
-- Check indexes
SELECT name FROM sqlite_master WHERE type = 'index' AND tbl_name = 'artifacts';
-- Add missing indexes
CREATE INDEX IF NOT EXISTS idx_artifacts_status ON artifacts(status);
CREATE INDEX IF NOT EXISTS idx_artifacts_expires_at ON artifacts(expires_at);
```
## Support
For issues, questions, or feature requests:
1. Check [Troubleshooting](#troubleshooting) section
2. Review [Best Practices](#best-practices)
3. Consult [API Reference](#api-reference)
4. File an issue in the project repository
**End of Guide**