OpenWriterControle/plugins/claude-code/scripts/context/openagents-repo/examples/zod-schema-migration.md
Darren Hinde a8fc9c7715
feat(plugin): enhance context management and skill invocation (#239)
* fix(shellcheck): declare and assign separately in router.sh (SC2155)

* feat(plugin): enhance context management and skill invocation

- Update .context-manifest.json to include profile and detailed source information.
- Revise context-scout.md to clarify context root discovery and navigation.
- Modify commands to replace deprecated skills with updated ones (brainstorming → approach, systematic-debugging → debugger).
- Streamline install-context.md for clarity and remove interactive profile selection.
- Improve oac-status.md to provide a more comprehensive status report.
- Add OAC system paths to session-start.sh for better context management.
- Remove obsolete skills and improve documentation for existing commands.
2026-02-23 12:12:29 +00:00

4.1 KiB

Example: Zod Schema Migration Pattern

Purpose: Migrate TypeScript definitions to runtime-validated Zod schemas

Last Updated: 2026-02-04


Why Zod?

Benefits: Runtime validation + single source of truth + better error messages


Basic Pattern

// BEFORE: .d.ts interface
interface AgentFrontmatter {
  name: string
  mode: 'primary' | 'subagent' | 'all'
  temperature?: number
}

// AFTER: Zod schema
import { z } from 'zod'

export const AgentFrontmatterSchema = z.object({
  name: z.string(),
  mode: z.enum(['primary', 'subagent', 'all']),
  temperature: z.number().min(0).max(2).optional()
})

export type AgentFrontmatter = z.infer<typeof AgentFrontmatterSchema>

Complex Schema

// Granular permissions
export const GranularPermissionSchema = z.object({
  allow: z.array(z.string()).optional(),
  deny: z.array(z.string()).optional(),
  ask: z.array(z.string()).optional()
})

export const PermissionRuleSchema = z.union([
  z.literal('allow'),
  z.literal('deny'),
  z.boolean(),
  GranularPermissionSchema
])

export const ToolAccessSchema = z.object({
  read: PermissionRuleSchema.optional(),
  write: PermissionRuleSchema.optional(),
  bash: PermissionRuleSchema.optional()
})

export type ToolAccess = z.infer<typeof ToolAccessSchema>

Validation Usage

// Strict parsing (throws on invalid)
const frontmatter = AgentFrontmatterSchema.parse(data)

// Safe parsing (returns result object)
const result = AgentFrontmatterSchema.safeParse(data)

if (result.success) {
  console.log(result.data)  // Typed correctly
} else {
  console.error(result.error.errors)  // Detailed errors
}

Common Patterns

Enums

export const ModeSchema = z.enum(['primary', 'subagent']).default('primary')

Arrays

export const SkillSchema = z.union([
  z.string(),                    // "skill-name"
  z.object({ name: z.string() }) // { name, config }
])
export const SkillsSchema = z.array(SkillSchema).optional()

Records

export const MetadataSchema = z.record(z.unknown())  // { [key: string]: any }

Optionals

z.string().optional()        // string | undefined
z.number().default(0.7)      // number with default

Full Example: OpenAgent

export const OpenAgentSchema = z.object({
  frontmatter: AgentFrontmatterSchema,
  metadata: AgentMetadataSchema.optional(),
  systemPrompt: z.string(),
  contexts: z.array(ContextReferenceSchema).optional()
})

export type OpenAgent = z.infer<typeof OpenAgentSchema>

Migration Checklist

  • interface → z.object()
  • type X = Y | Z → z.union([...])
  • ? optional → .optional()
  • Add constraints (.min(), .max())
  • Export schema AND type
  • Test with valid/invalid data

Testing

describe('AgentFrontmatterSchema', () => {
  it('validates correct data', () => {
    expect(() => AgentFrontmatterSchema.parse({
      name: 'TestAgent',
      mode: 'primary'
    })).not.toThrow()
  })
  
  it('rejects invalid mode', () => {
    expect(() => AgentFrontmatterSchema.parse({
      name: 'Test',
      mode: 'invalid'
    })).toThrow()
  })
  
  it('rejects out-of-range temperature', () => {
    expect(() => AgentFrontmatterSchema.parse({
      name: 'Test',
      temperature: 5.0  // Max 2.0
    })).toThrow()
  })
})

Key Schemas (Compatibility Layer)

20+ schemas migrated:

  • OpenAgentSchema - Complete agent
  • AgentFrontmatterSchema - YAML frontmatter
  • ToolAccessSchema - Tool permissions
  • PermissionRuleSchema - Permission types
  • SkillReferenceSchema - Skill definitions
  • HookDefinitionSchema - Hook configs

Reference

  • Implementation: packages/compatibility-layer/src/types.ts (315 lines)
  • Original: packages/compatibility-layer/dist/src/types.d.ts (679 lines)
  • Zod Docs: https://zod.dev
  • Related:
    • examples/baseadapter-pattern.md
    • concepts/compatibility-layer.md