Core Development

Plugin Configuration

Build strictly-typed configuration schemas with default values, environment variable parsing, and hot updates.

In building resilient enterprise-grade agent systems, “No Hardcoded Tunable Parameters” is a fundamental architectural invariant of DeepSeek Harness. Network timeouts, concurrency thresholds, gateway endpoints, and authentication tokens should all be declaratively managed in configuration files.

DeepSeek Harness integrates @deepseek-ai/schemastery to provide a strongly-typed configuration algebra, supporting compile-time inference, runtime validation, and automated default value injection for cordis.yml.

This tutorial uses an “Inference Gateway & Rate Limiter Plugin” as a real-world case study to unpack configuration schemas and sensitive credential masking.


Core Paradigm: Dual Export & Standard Schema

In Cordis, configuration contracts are declared through a same-named dual export pattern: exporting both a TypeScript interface Config and a matching export const Config: Schema<Config> runtime validator:

typescript
import type { Context } from '@deepseek-ai/cordis';
import Schema from '@deepseek-ai/schemastery';

export const name = 'inference-gateway-plugin';

// 1. Compile-time static type interface (enables IDE auto-completion)
export interface Config {
    endpoint: string;
    maxConcurrency: number;
    timeoutMs: number;
    enableFallback?: boolean;
}

// 2. Runtime Schema validator (parses YAML, injects defaults, blocks invalid keys)
export const Config: Schema<Config> = Schema.object({
    endpoint: Schema.string().required().description('Base endpoint URL for the model proxy gateway'),
    maxConcurrency: Schema.number().default(5).min(1).max(50).description('Maximum allowable concurrent requests'),
    timeoutMs: Schema.number().default(15000).description('Request timeout threshold in milliseconds'),
    enableFallback: Schema.boolean().default(true).description('Automatically switch to fallback routes upon gateway failure')
});

// 3. apply function receives the sanitized config object with injected defaults
export function apply(ctx: Context, config: Config) {
    console.log(`[Gateway] Connected to endpoint: ${config.endpoint} (Concurrency: ${config.maxConcurrency})`);
}

Crucial Architecture Rule: Never export a plain JavaScript literal object as Config. The Cordis microkernel requires configuration definitions to implement the Standard Schema specification for static inference and runtime sandboxing.


Step 1: Supplying Configuration via cordis.yml

Inject parameters into your local plugin within cordis.yml:

yaml
- insert:
    - id: gateway-instance
      name: './custom-plugins/gateway'
      config:
        endpoint: 'https://api.deepseek.com/v1'
        maxConcurrency: 10
        timeoutMs: 20000
        enableFallback: false

During startup, Harness reconciles YAML values against the schema, populating defaults for any omitted properties.


Step 2: Strict Validation and the "Fail Loudly" Principle

For mission-critical production plugins, combine Schemastery operators to embrace the Fail Loudly principle:

typescript
import type { Context } from '@deepseek-ai/cordis';
import Schema from '@deepseek-ai/schemastery';

export const name = 'secure-vault-plugin';

export interface Config {
    masterApiKey: string;
    environment: 'production' | 'staging' | 'development';
    ipWhitelist: string[];
    rateLimitPerMinute: number;
}

export const Config: Schema<Config> = Schema.object({
    // required() enforces presence; .role('secret') masks values across logs & UI
    masterApiKey: Schema.string().required().role('secret').description('Master authentication token'),

    // union specifies strict enum constraints
    environment: Schema.union(['production', 'staging', 'development']).default('development').description('Target execution tier'),

    // array declares typed list validation
    ipWhitelist: Schema.array(Schema.string()).default([]).description('Trusted client IP whitelist'),

    // Numeric boundary constraints
    rateLimitPerMinute: Schema.number().default(60).min(1).max(600).description('Maximum requests permitted per minute')
});

export function apply(ctx: Context, config: Config) {
    console.log(`[Vault] Tier: ${config.environment}, Limit: ${config.rateLimitPerMinute} req/min`);
}

If a user forgets the mandatory masterApiKey or provides an unrecognized environment: 'test', Harness aborts startup immediately with detailed error paths, preventing silent production bugs.


Four Best Practices for Configuration Engineering

  1. Eliminate Hardcoded Constants: Move network timeouts, retry limits, and endpoints into configuration schemas;
  2. Mask Confidential Secrets: Chain .role('secret') on all API keys and credentials;
  3. Enforce Boundary Constraints: Use .min(), .max(), and .union() to catch malformed values early;
  4. Seamless Live Updates: Design plugins to handle dynamic configuration changes gracefully during hot reload.

Frequently Asked Questions (FAQ)

Q1: Why use Schemastery instead of standard TypeScript type assertions?

Answer: TypeScript interfaces are erased during compilation and cannot validate data at runtime. Schemastery provides both static TypeScript types and runtime validation with automatic default assignment.

Q2: What happens if undeclared fields are passed in cordis.yml?

Answer: Schemastery strips undeclared keys and logs diagnostic warnings, helping developers catch typographical errors (e.g. time_out instead of timeoutMs).

Q3: What is the exact behavior of .role('secret')?

Answer: When marked as a secret, values are masked as *** across Web UI dashboards, CLI dumps, and persisted Trajectory audit logs, preventing accidental credential exposure.

Q4: How does a plugin adapt to dynamic configuration edits in production?

Answer: In hot-reload environments (e.g. pnpm dsh web --patch), file changes trigger validation. Once verified, the microkernel updates the plugin Fiber branch with the fresh configuration.