Configuration: Give Plugins Validated Options and Defaults
Define Cordis plugin configuration with Schemastery and see how defaults, path-aware errors, and FAILED Fibers prevent a sick start.
The conclusion: configuration is not an unchecked object. A schema runs before apply, fills defaults, rejects invalid input, and lets the plugin handle only valid options.
Behavior choices can stay in cordis.yml or a profile patch while runtime preconditions remain explicit.
01 / Keep the type and schema together
A configurable plugin can declare its options like this:
import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
export interface Config {
greeting: string
targets: string[]
}
export const Config: Schema<Config> = Schema.object({
greeting: Schema.string().default('Hello'),
targets: Schema.array(String).default(['world']),
})
export function apply(ctx: Context, config: Config) {
for (const target of config.targets) {
console.log(config.greeting + ', ' + target + '!')
}
}The Config interface supplies static TypeScript types. The runtime schema with the same name validates and defaults values. A plain object is not enough because Cordis needs a runtime validator that follows Standard Schema.
02 / Configuration comes from cordis.yml
- name: './config-demo.ts'
config:
targets: ['alpha', 'beta']Because greeting is omitted, the schema fills in Hello. apply receives a complete configuration:
Hello, alpha!
Hello, beta!03 / Errors appear before apply
Pass a string where the schema requires an array:
- name: './config-demo.ts'
config:
targets: 'not-an-array'Loader reports a path-aware ValidationError, for example:
ValidationError: invalid config:
- $.targets expected array but got not-an-array (at targets)The Fiber enters FAILED and the launcher exits with failure. The plugin does not run several steps with bad input and leave an ambiguous error deeper in the runtime.
04 / The schema is part of the configuration API
A schema records input types, defaults, and constraints together. If a field changes deployment behavior, make it a schema field instead of scattering a DEFAULT_* constant through the plugin.
This repository uses Schemastery, while Cordis accepts validators that follow Standard Schema. Schemas can also express required values, unions, arrays, and objects.
05 / Keep computed values in explicit locations
The repository’s loader extension supports !!js:
- name: './config-demo.ts'
config:
greeting: !!js process.env.DEMO_GREETING ?? 'Hello'It is evaluated only inside config and an entry’s disabled field. Metadata such as name, id, and inject stays static. A config expression is evaluated against the plugin Context after required services are active; disabled is evaluated against the Loader Context at each mount decision. For environment-specific composition, a profile overlay is usually clearer than making every metadata field dynamic.
Where to go next
Sources: configuration tutorial, Schemastery, and Fiber implementation.
More Posts
Composition and HMR: Import New Code, Dispose the Old Fiber, Then Activate
Understand stable ids, configuration groups, and Cordis HMR’s unload-reload cycle, including how to diagnose plugins stuck in PENDING.
Services and Context: Share Capabilities Without Binding Implementations
Use Service, Context, and declaration merging to understand how providers, consumers, and scopes connect DeepSeek Harness capabilities.
waterfall: Intercept, Wrap, and Short-Circuit with next()
Follow a Cordis waterfall chain to see listeners delegate downstream, wrap results, or short-circuit when they own the decision.
Newsletter
Join the community
Subscribe to our newsletter for the latest news and updates