@tisyn/config
v0.10.1
Published
`@tisyn/config` provides pure constructors, types, validation, and walking for Tisyn workflow configuration descriptors.
Readme
@tisyn/config
@tisyn/config provides pure constructors, types, validation, and walking for Tisyn workflow configuration descriptors.
This package owns the descriptor data model — tagged data structures that declare a workflow's runtime topology (agents, transports, environment references, journals, entrypoints, servers). All constructors are pure functions that return serializable data within the tisyn_config tagged domain.
Where It Fits
@tisyn/config sits between authored configuration and runtime resolution.
- Authors use the constructor vocabulary to declare workflow topology.
@tisyn/runtimeresolves descriptors into workflow-visible config projections.@tisyn/cliloads and validates descriptors duringtsn runandtsn check.
This package defines the shape of configuration. It does not resolve environment variables, apply entrypoint overlays, or project runtime-visible config — those responsibilities belong to @tisyn/runtime.
Constructor Vocabulary
import {
workflow, agent, transport, env, journal, entrypoint, server,
configToken, Config,
} from "@tisyn/config";
export default workflow({
run: "chat",
agents: [
agent("llm", transport.worker("./llm-worker.js")),
agent("app", transport.local("./browser-agent.ts")),
],
journal: journal.file(env("JOURNAL_PATH", "./data/chat.journal")),
entrypoints: {
dev: entrypoint({
server: server.websocket({ port: env("PORT", 3000) }),
}),
},
});Constructors
| Constructor | Output |
|---|---|
| workflow({ run, agents, journal?, entrypoints? }) | WorkflowDescriptor |
| agent(id, transport, config?) | AgentBinding |
| transport.worker(url) | WorkerTransportDescriptor |
| transport.local(module) | LocalTransportDescriptor |
| transport.stdio(command, args?) | StdioTransportDescriptor |
| transport.websocket(url) | WebSocketTransportDescriptor |
| transport.inprocess(module) | InprocessTransportDescriptor |
| env(name, default) | EnvOptionalDescriptor |
| env.required(name) | EnvRequiredDescriptor |
| env.secret(name) | EnvSecretDescriptor |
| journal.file(path) | FileJournalDescriptor |
| journal.memory() | MemoryJournalDescriptor |
| entrypoint(config?) | EntrypointDescriptor |
| server.websocket({ port, static? }) | ServerDescriptor |
| configToken<T>() | ConfigToken<T> |
The optional config bag on agent() supports env() nodes for deferred environment resolution, letting transport modules receive resolved configuration at startup.
Transport, journal path, server port, and stdio command/args positions also accept EnvDescriptor nodes for deferred environment resolution.
Config Token and Config.useConfig()
ConfigToken<T> is a typed anchor for accessing resolved config inside workflows. The token carries the projected config type T at compile time:
import { configToken, Config } from "@tisyn/config";
type AppConfig = {
agents: Array<{ id: string }>;
journal: { kind: string; path?: string };
};
export const AppConfigToken = configToken<AppConfig>();Workflow code accesses the resolved config projection via yield* Config.useConfig(Token):
function* main(): Workflow<void> {
const config = yield* Config.useConfig(AppConfigToken);
// config is statically typed as AppConfig
}The compiler erases the token and emits ExternalEval("__config", Q(null)). At runtime, the __config effect returns the resolved config from the execution-scoped config context. Config.useConfig() throws if called outside the Tisyn compiler.
Validation
import { validateConfig } from "@tisyn/config";
const result = validateConfig(descriptor);
if (!result.ok) {
console.error(result.errors);
}Validates rules V1-V10 from the Configuration Specification:
- V1: recognized
tisyn_configdiscriminant - V2: workflow has
runand non-emptyagents - V3: agents have non-empty
idand valid transport - V4: unique agent ids
- V5: transports have
kindand required fields - V6: env mode/default consistency
- V7: entrypoint keys match
[a-z][a-z0-9-]* - V8: all values in portable serializable data domain
- V9: no node with both
tisyn_configandtisyn - V10: base workflow must not have
server
Walking
import { walkConfig, collectEnvNodes } from "@tisyn/config";
// Depth-first traversal of all tisyn_config nodes
walkConfig(descriptor, (node, path) => {
console.log(path, node.tisyn_config);
});
// Collect all environment variable references
const envNodes = collectEnvNodes(descriptor);Relationship to the Rest of Tisyn
@tisyn/runtimeresolves descriptors into workflow-visible config projections usingapplyOverlay(),resolveEnv(), andresolveConfig().@tisyn/cliloads descriptor modules and usescollectEnvNodes()fortsn check --env-example.@tisyn/compileris independent of config — it compiles workflows, not descriptors.
Boundaries
@tisyn/config owns:
- descriptor data model and tagged constructors
- config validation (V1-V10)
- config tree walking and env node collection
@tisyn/config does not own:
- environment resolution or entrypoint overlay application (owned by
@tisyn/runtime) - descriptor module loading or CLI integration (owned by
@tisyn/cli) - workflow compilation or IR (owned by
@tisyn/compiler)
Specification
See Configuration Specification and Configuration Test Plan.
