Skip to content

Agent Design

John Williams edited this page Mar 16, 2026 · 1 revision

Agent Design

Agent Interface Contract

Every Last Mile agent implements the same interface:

interface Agent {
  name: string;
  rules: Rule[];
  analyze(files: SourceFile[], config: ScanConfig): Finding[];
}

interface Rule {
  id: string;
  severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
  cwe?: string;
  description: string;
  check(file: SourceFile): Finding | null;
  fix?(finding: Finding): Patch;
}

interface Finding {
  ruleId: string;
  severity: string;
  file: string;
  line: number;
  message: string;
  cwe?: string;
  fix?: string;
}

This contract ensures:

  • Agents are interchangeable and independently deployable
  • Rules are self-documenting with CWE mappings
  • Fix suggestions are optional but encouraged
  • Results are structured for consistent aggregation

The Agent Loop

Adapted from the Nanobot pattern (reason → act → observe → repeat):

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  REASON  │────▶│   ACT    │────▶│ OBSERVE  │────▶│  REPORT  │
│          │     │          │     │          │     │          │
│ Select   │     │ Run rule │     │ Collect  │     │ Emit     │
│ next     │     │ against  │     │ findings │     │ findings │
│ rule     │     │ files    │     │ per file │     │ to queue │
└──────────┘     └──────────┘     └──────────┘     └──────────┘
     ▲                                                   │
     └───────────────────────────────────────────────────┘
                    (next rule, until all rules exhausted)

Security Agent

The largest and most critical agent. Responsible for 35% of the total score.

Rules (15 patterns)

Rule ID Description CWE
secret/aws-key AWS access key ID pattern CWE-798
secret/aws-secret AWS secret access key CWE-798
secret/github-token GitHub personal access token CWE-798
secret/openai-key OpenAI API key CWE-798
secret/anthropic-key Anthropic API key CWE-798
secret/stripe-key Stripe secret key CWE-798
secret/jwt-secret Hardcoded JWT signing secret CWE-798
secret/database-url Database connection string with credentials CWE-798
secret/private-key RSA/EC private key block CWE-321
secret/generic-api-key Generic API key patterns CWE-798
secret/slack-webhook Slack webhook URL CWE-798
secret/sendgrid-key SendGrid API key CWE-798
secret/twilio-key Twilio auth token CWE-798
secret/google-api-key Google API key CWE-798
secret/heroku-api-key Heroku API key CWE-798

Additional Checks

  • Dependency audit: Lock file analysis for known CVEs (SEC-DEP-001 through SEC-DEP-003)
  • SAST rules: 20+ static analysis patterns (see Semgrep Rules)
    • CORS wildcard detection (CWE-942)
    • XSS via innerHTML (CWE-79)
    • Insecure HTTP URLs (CWE-319)
    • Console.log in production (CWE-532)
    • Hardcoded IPs (CWE-1188)
    • eval() usage (CWE-95)
    • SQL injection patterns (CWE-89)

Database Agent

9 rules focused on data integrity and access control.

Rule ID Description CWE
db/no-migration No migration system detected CWE-1188
db/no-rollback Migrations lack rollback/down methods CWE-1188
db/raw-sql Raw SQL without parameterized queries CWE-89
db/no-rls Supabase tables without Row Level Security CWE-284
db/no-schema-validation No input validation before database writes CWE-20
db/hardcoded-credentials Database credentials in source code CWE-798
db/no-connection-pool Missing connection pooling configuration CWE-400
db/no-indexes Large tables without index definitions CWE-405
db/cascade-delete CASCADE DELETE without confirmation logic CWE-1188

Infrastructure Agent

11 rules covering deployment, CI/CD, and operational readiness.

Rule ID Description CWE
infra/no-dockerfile No Dockerfile or container configuration
infra/docker-root Container runs as root user CWE-250
infra/no-ci No CI/CD pipeline configuration
infra/ci-no-lint CI pipeline missing lint step
infra/ci-no-test CI pipeline missing test step
infra/no-env-example Missing .env.example for environment documentation CWE-1188
infra/env-in-repo .env file committed to repository CWE-798
infra/no-health-endpoint No health check endpoint (/health, /healthz)
infra/no-gitignore Missing or incomplete .gitignore
infra/no-lockfile No package lock file (unpinned dependencies) CWE-829
infra/no-node-version No .nvmrc or engines field for Node.js version

Observability Agent

8 rules ensuring production visibility.

Rule ID Description CWE
obs/no-logging No structured logging library detected CWE-778
obs/console-only Using console.log instead of structured logger CWE-532
obs/no-error-tracking No error tracking service (Sentry, Bugsnag, etc.)
obs/no-metrics No metrics/APM instrumentation
obs/no-alerting No alerting configuration
obs/silent-catch Empty catch blocks swallowing errors CWE-390
obs/no-request-id No request ID/correlation ID in logging
obs/no-uptime-monitoring No uptime monitoring configuration

Quality Agent

10 rules for code maintainability.

Rule ID Description CWE
qual/no-tests No test files or test framework detected
qual/low-coverage Test coverage below threshold
qual/no-linter No linter configuration (ESLint, Prettier, etc.)
qual/no-typescript JavaScript without TypeScript (for TS-capable projects)
qual/high-complexity Cyclomatic complexity exceeds threshold CWE-1121
qual/large-files Files exceeding 500 lines
qual/no-readme Missing README.md
qual/no-license Missing LICENSE file
qual/dead-code Unreachable or unused exports
qual/no-formatting No code formatter configuration

Agent Isolation

Cloud Mode (Production)

Each agent is a separate Cloudflare Worker deployment:

  • Own V8 isolate — no shared memory
  • Own Queues binding — messages are isolated
  • Own secrets — least-privilege access
  • Independent scaling — hot agents don't starve cold ones
  • Independent deployment — update Security Agent without touching Quality Agent

Local Mode (CLI)

Each agent is a separate module in the CLI bundle:

  • Imported dynamically based on configuration
  • Run sequentially (or parallel via Promise.all)
  • Same isolation contract: no shared state between agent invocations
  • Findings are collected in separate arrays, merged only at scoring time

Clone this wiki locally