Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    willsigmon

    knack-devops

    willsigmon/knack-devops
    Productivity
    5
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Manages automated build, deployment, environment sync, and monitoring for HTI's Knack-Vercel integration. Ensures dashboard uptime, data sync relia...

    SKILL.md

    Knack DevOps

    Purpose

    Manages automated build, deployment, environment sync, and monitoring for HTI's Knack-Vercel integration. Ensures dashboard uptime, data sync reliability, and performance optimization.

    Core Functions

    trigger_vercel_build

    Purpose: Programmatically deploy updated dashboard code

    Parameters:

    • vercel_url (string, optional): Deployment URL (default: production)
    • trigger (string, optional): "push" | "webhook" | "api" (default: "api")

    Example:

    const deployment = await trigger_vercel_build({
      vercel_url: process.env.VERCEL_PROJECT_URL,
      trigger: "api"
    });
    
    // Output:
    // {
    //   deployment_id: "dpl_abc123",
    //   status: "building",
    //   url: "https://hubdash-git-main.vercel.app",
    //   estimated_completion: "2025-04-15T14:35:00Z"
    // }
    

    Implementation:

    import { Vercel } from '@vercel/sdk';
    
    async function trigger_vercel_build({ vercel_url }) {
      const vercel = new Vercel({ bearerToken: process.env.VERCEL_TOKEN });
    
      const deployment = await vercel.deployments.create({
        name: 'hubdash',
        gitSource: {
          type: 'github',
          ref: 'main'
        }
      });
    
      return {
        deployment_id: deployment.id,
        status: deployment.status,
        url: deployment.url
      };
    }
    

    monitor_latency

    Purpose: Track API and dashboard response times

    Parameters:

    • api_url (string, required): Endpoint to monitor
    • interval_seconds (integer, optional): Check frequency (default: 300 = 5 min)
    • alert_threshold_ms (integer, optional): Latency threshold for alerts (default: 2000)

    Example:

    const monitor = await monitor_latency({
      api_url: "https://hubdash.vercel.app/api/metrics",
      interval_seconds: 300,
      alert_threshold_ms: 2000
    });
    

    Implementation:

    import axios from 'axios';
    
    async function monitor_latency({ api_url, interval_seconds, alert_threshold_ms }) {
      setInterval(async () => {
        const start = Date.now();
    
        try {
          await axios.get(api_url);
          const latency = Date.now() - start;
    
          console.log(`Latency: ${latency}ms`);
    
          if (latency > alert_threshold_ms) {
            await alert_team({
              severity: "warning",
              message: `Dashboard latency high: ${latency}ms (threshold: ${alert_threshold_ms}ms)`
            });
          }
    
          // Log to metrics system
          await log_metric({
            metric: "api_latency",
            value: latency,
            timestamp: new Date()
          });
        } catch (error) {
          await alert_team({
            severity: "critical",
            message: `Dashboard unreachable: ${api_url}`,
            error: error.message
          });
        }
      }, interval_seconds * 1000);
    }
    

    sync_environment

    Purpose: Keep Knack credentials and config in sync across environments

    Environments:

    • Development: Local testing with sandbox Knack instance
    • Staging: Pre-production testing with production data copy
    • Production: Live HTI dashboard with real grant data

    Example:

    await sync_environment({
      source: "production",
      target: "staging",
      include: ["knack_credentials", "api_endpoints"],
      exclude: ["user_tokens", "sensitive_keys"]
    });
    

    Implementation:

    async function sync_environment({ source, target, include, exclude }) {
      // Fetch config from source
      const source_config = await get_env_config(source);
    
      // Filter based on include/exclude
      const filtered_config = Object.keys(source_config)
        .filter(key => include.includes(key) && !exclude.includes(key))
        .reduce((obj, key) => {
          obj[key] = source_config[key];
          return obj;
        }, {});
    
      // Apply to target environment
      await update_env_config(target, filtered_config);
    
      return {
        synced_keys: Object.keys(filtered_config),
        source: source,
        target: target
      };
    }
    

    automated_backup

    Purpose: Regular backups of Knack data for disaster recovery

    Example:

    // Daily backup of all Knack objects
    cron.schedule('0 2 * * *', async () => {
      const backup = await automated_backup({
        objects: ["object_1", "object_2", "object_training"],
        destination: "s3://hti-backups/knack",
        retention_days: 90
      });
    
      console.log(`Backup complete: ${backup.records_backed_up} records`);
    });
    

    Implementation:

    import AWS from 'aws-sdk';
    
    async function automated_backup({ objects, destination, retention_days }) {
      const s3 = new AWS.S3();
      const timestamp = new Date().toISOString().split('T')[0];
      let total_records = 0;
    
      for (const object_key of objects) {
        // Fetch all records
        const records = await fetch_all_pages(object_key);
        total_records += records.length;
    
        // Save to S3
        await s3.putObject({
          Bucket: 'hti-backups',
          Key: `knack/${object_key}_${timestamp}.json`,
          Body: JSON.stringify(records, null, 2),
          ContentType: 'application/json'
        }).promise();
      }
    
      // Clean up old backups (>90 days)
      await cleanup_old_backups({ bucket: 'hti-backups', retention_days });
    
      return { records_backed_up: total_records, timestamp };
    }
    

    CI/CD Pipeline

    GitHub Actions Workflow

    # .github/workflows/deploy.yml
    name: Deploy HTI Dashboard
    
    on:
      push:
        branches: [main]
      workflow_dispatch:
    
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
    
          - name: Setup Node.js
            uses: actions/setup-node@v3
            with:
              node-version: '18'
    
          - name: Install dependencies
            run: npm ci
    
          - name: Run tests
            run: npm test
    
          - name: Validate Knack connection
            run: npm run test:knack-api
            env:
              KNACK_APP_ID: ${{ secrets.KNACK_APP_ID }}
              KNACK_API_KEY: ${{ secrets.KNACK_API_KEY }}
    
      deploy:
        needs: test
        runs-on: ubuntu-latest
        steps:
          - name: Deploy to Vercel
            uses: amondnet/vercel-action@v25
            with:
              vercel-token: ${{ secrets.VERCEL_TOKEN }}
              vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
              vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
              vercel-args: '--prod'
    
          - name: Notify deployment
            run: |
              curl -X POST https://hooks.slack.com/services/${{ secrets.SLACK_WEBHOOK }} \
              -d '{"text": "✅ HTI Dashboard deployed to production"}'
    

    Pre-Deployment Checks

    async function pre_deployment_checks() {
      const checks = {
        knack_api: await test_knack_connection(),
        data_integrity: await validate_production_data(),
        cache_warm: await warm_cache(),
        env_vars: await verify_env_vars(),
        build_size: await check_bundle_size()
      };
    
      const all_passed = Object.values(checks).every(c => c.passed);
    
      if (!all_passed) {
        throw new Error(`Pre-deployment checks failed: ${JSON.stringify(checks)}`);
      }
    
      return checks;
    }
    
    // Run before every production deploy
    async function test_knack_connection() {
      try {
        const response = await get_records("object_1", { rows_per_page: 1 });
        return { passed: true, message: "Knack API accessible" };
      } catch (error) {
        return { passed: false, message: `Knack API error: ${error.message}` };
      }
    }
    

    Monitoring & Alerting

    Uptime Monitoring

    // Use Vercel Analytics or external service (Pingdom, UptimeRobot)
    async function setup_uptime_monitoring() {
      // Vercel Analytics (automatic)
      // https://vercel.com/docs/analytics
    
      // Or external monitoring
      const monitor = await createUptimeCheck({
        url: "https://hubdash.vercel.app",
        interval: 300, // 5 minutes
        alert_contacts: ["admin@hubzonetech.org"]
      });
    
      return monitor;
    }
    

    Error Tracking

    // Sentry integration
    import * as Sentry from "@sentry/nextjs";
    
    Sentry.init({
      dsn: process.env.SENTRY_DSN,
      environment: process.env.NODE_ENV,
      tracesSampleRate: 1.0,
    
      beforeSend(event) {
        // Don't send test data errors
        if (event.request?.url?.includes('localhost')) {
          return null;
        }
        return event;
      }
    });
    
    // Log Knack API errors
    try {
      await get_records("object_1");
    } catch (error) {
      Sentry.captureException(error, {
        tags: { service: "knack_api" },
        extra: { object_key: "object_1" }
      });
    }
    

    Performance Monitoring

    // Web Vitals tracking
    import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
    
    function send_to_analytics(metric) {
      const body = JSON.stringify({
        name: metric.name,
        value: metric.value,
        id: metric.id
      });
    
      fetch('/api/analytics', { method: 'POST', body });
    }
    
    getCLS(send_to_analytics);
    getFID(send_to_analytics);
    getFCP(send_to_analytics);
    getLCP(send_to_analytics);
    getTTFB(send_to_analytics);
    

    Environment Management

    Development Environment

    # .env.development
    KNACK_APP_ID=dev_app_id
    KNACK_API_KEY=dev_api_key
    VERCEL_ENV=development
    CACHE_TTL=30 # Shorter cache for testing
    DEBUG_MODE=true
    

    Production Environment

    # .env.production (in Vercel dashboard)
    KNACK_APP_ID=prod_app_id
    KNACK_API_KEY=prod_api_key
    VERCEL_ENV=production
    CACHE_TTL=300 # 5 minutes
    DEBUG_MODE=false
    SENTRY_DSN=https://...
    

    Secrets Management

    // Store secrets in Vercel Environment Variables
    // Never commit secrets to Git
    
    // Access in code:
    const knack_api_key = process.env.KNACK_API_KEY;
    
    // Rotate secrets quarterly (align with grant reporting)
    async function rotate_secrets() {
      // 1. Generate new API key in Knack dashboard
      // 2. Update Vercel environment variables
      // 3. Trigger redeployment
      // 4. Verify new keys work
      // 5. Revoke old keys
    }
    

    Performance Optimization

    Bundle Size Analysis

    // Run during CI/CD
    import { readFileSync } from 'fs';
    
    async function check_bundle_size() {
      const bundle_stats = JSON.parse(readFileSync('.next/analyze/client.json'));
    
      const total_size = bundle_stats.reduce((sum, bundle) => sum + bundle.size, 0);
      const max_size = 1_000_000; // 1MB
    
      if (total_size > max_size) {
        console.warn(`Bundle size ${total_size} exceeds ${max_size}`);
        return { passed: false, size: total_size };
      }
    
      return { passed: true, size: total_size };
    }
    

    Cache Warming

    // Warm cache after deployment
    async function warm_cache() {
      const critical_endpoints = [
        "/api/metrics",
        "/api/county-breakdown",
        "/api/quarterly-report"
      ];
    
      for (const endpoint of critical_endpoints) {
        await fetch(`https://hubdash.vercel.app${endpoint}`);
      }
    
      return { warmed: critical_endpoints.length };
    }
    

    Disaster Recovery

    Database Recovery

    async function restore_from_backup({ backup_date, objects }) {
      const s3 = new AWS.S3();
    
      for (const object_key of objects) {
        // Fetch backup
        const backup = await s3.getObject({
          Bucket: 'hti-backups',
          Key: `knack/${object_key}_${backup_date}.json`
        }).promise();
    
        const records = JSON.parse(backup.Body.toString());
    
        // Restore to Knack (batch insert)
        console.log(`Restoring ${records.length} records to ${object_key}`);
        // Implementation depends on Knack's batch API
      }
    }
    

    Rollback Procedure

    // Rollback to previous Vercel deployment
    async function rollback_deployment() {
      const vercel = new Vercel({ bearerToken: process.env.VERCEL_TOKEN });
    
      // Get previous deployment
      const deployments = await vercel.deployments.list({
        projectId: process.env.VERCEL_PROJECT_ID,
        limit: 2
      });
    
      const previous = deployments[1];
    
      // Promote to production
      await vercel.deployments.update(previous.id, {
        target: 'production'
      });
    
      console.log(`Rolled back to ${previous.id}`);
    }
    

    Integration Points

    • knack_reader: Monitor API health
    • knack_cache_optimizer: Cache invalidation on deploy
    • knack_realtime: Webhook endpoint health checks
    • knack_reporting_sync: Automated report generation triggers
    • knack_dashboard_ai: Performance metrics collection

    Best Practices

    1. Automate everything: No manual deployments
    2. Test before deploy: CI/CD checks gate production
    3. Monitor continuously: Uptime + performance + errors
    4. Backup daily: 90-day retention
    5. Document runbooks: Incident response procedures
    6. Rotate secrets quarterly: Align with grant reporting cycle

    Incident Response

    Runbook: Dashboard Down

    1. Check Vercel status page
    2. Verify Knack API connectivity
    3. Review recent deployments
    4. Check error logs in Sentry
    5. If needed, rollback deployment
    6. Notify stakeholders
    7. Post-incident review

    Runbook: Slow Dashboard

    1. Check API latency metrics
    2. Review cache hit rates
    3. Analyze bundle size
    4. Check Knack rate limits
    5. Optimize queries if needed
    6. Consider CDN configuration
    Repository
    willsigmon/sigstack
    Files