js/task

js/task.ts

fino:task — shared executable tasks for CLIs, agents, MCP, and runtimes.

A Task describes one named operation with input metadata, optional output metadata, effect metadata, child tasks, and one executor. The same value can be invoked directly by application code, parsed as a CLI command, exposed as an AI tool, mounted in an MCP server, or reused later by RPC and queue surfaces.

Design

Task output is explicit at execution time. outputMode declares what a task can produce: text, JSON, or both. The writer passed to a task is a discriminated union, so task code must check writer.mode before writing text or structured JSON. Fino does not try to convert a generic structured result into human text; each task owns the output behavior that fits its domain.

CLI parsing is built on fino:process/argv for now. Task.parse() converts CLI options and positionals into a flat input object, walks child tasks, and honors a global --json token before running the selected task.

import { task } from 'fino:task';

const greet = task({
  name: 'greet',
  outputMode: 'both',
  cli: { positionals: [{ name: 'name', required: true }] },
  run: async (input: { name: string }, ctx) => {
    if (ctx.writer.mode === 'json') {
      await ctx.writer.writeJson({ greeting: `hello ${input.name}` });
    } else {
      await ctx.writer.writeText(`hello ${input.name}\n`);
    }
    return { greeting: `hello ${input.name}` };
  },
});

await greet.parse(['--json', 'Ada']);

Types

type TaskOutputMode = 'text' | 'json' | 'both'

Output formats a task can produce.

type TaskRequestedOutputMode = 'text' | 'json'

Concrete output format requested for a single task execution.

type TaskJsonValue = null | boolean | number | string | TaskJsonValue[] | { [key: string]: TaskJsonValue; }

JSON-compatible value accepted by JSON task writers.

type TaskOutputWriter = { readonly mode: 'text'; writeText(chunk: string): void | Promise<void>; writeJson?: never; } | { readonly mode: 'json'; writeJson(value: TaskJsonValue): void | Promise<void>; writeText?: never; }

Output writer passed into a task executor.

The union is intentionally discriminated by mode: TypeScript callers must narrow before calling writeText() or writeJson().

type TaskHandler< Input, Output = unknown > = (input: Input, ctx: TaskContext) => Output | Promise<Output>

Function that performs a task.

type TaskToolResult = string | { content: ContentPart | ContentPart[] | string; isError?: boolean; }

Result shape returned by AI-tool-compatible task invocation.

Interfaces

interface TaskEffect {

Side-effect metadata for policy, approval, and audit layers.

Properties

kind: string

Machine-readable effect category.

description?: string

Human-readable explanation of the effect.

interface TaskContext {

Context passed to a task executor.

Readonly Properties

readonly signal: AbortSignal

Signal cancelled when the current run should stop.

readonly runId?: string

Optional caller-supplied run identifier for tracing.

readonly writer: TaskOutputWriter

Output writer selected for this run.

readonly env?: Record<string, string | undefined>

Environment variables visible to the task.

readonly cwd?: string

Current working directory for filesystem-oriented tasks.

readonly prompt?: PromptSession

Prompt session available to interactive CLI tasks.

readonly providedOptions?: ReadonlySet<string>

CLI option keys explicitly provided by the caller.

readonly toolCallId?: string

AI tool call id when invoked through a model tool surface.

readonly step?: number

AI agent step index when invoked through a model tool surface.

readonly messages?: ModelMessage[]

Messages associated with an AI tool invocation.

readonly history?: MessageHistory

Mutable message history associated with an AI tool invocation.

Methods

optionProvided?(key: string): boolean

Return whether a CLI option key was explicitly provided.

suspend?(opts?: { reason?: string; payload?: unknown; }): never

Suspend the current task for an external resume flow.

interface TaskCliOption {

CLI option metadata for a task.

Properties

name?: string

Input object key to populate. Defaults to the long or short flag name.

flags: string

Comma-separated CLI flags, for example -v, --verbose.

description?: string

Help text shown next to the option.

type?: 'string' | 'number' | 'boolean'

Primitive parser used for the option value.

multiple?: boolean

Whether the option may appear more than once.

required?: boolean

Whether parsing should fail when the option is missing.

default?: boolean | string | number | Array<string | number> | ((ctx: CommandContext) => unknown)

Default value or resolver used by the argv parser.

choices?: Array<string | number>

Allowed option values.

interface TaskCliPositional {

CLI positional metadata for a task.

Properties

name: string

Input object key populated by this positional argument.

description?: string

Help text shown next to the positional.

type?: 'string' | 'number'

Primitive parser used for the positional value.

required?: boolean

Whether parsing should fail when the positional is missing.

multiple?: boolean

Whether the positional can collect multiple values.

variadic?: boolean

Alias for multiple when the positional consumes the remaining args.

choices?: Array<string | number>

Allowed positional values.

interface TaskCliSpec {

CLI-facing task metadata.

Properties

name?: string

CLI command name. Defaults to the task name.

usage?: string

Usage string shown in help output.

options?: TaskCliOption[]

Option definitions accepted by this task's CLI parser.

positionals?: TaskCliPositional[]

Positional argument definitions accepted by this task.

allowUnknown?: boolean

Whether unknown options should be preserved instead of rejected.

stopOptionsAfterPositionals?: boolean

Whether option parsing stops after the first positional argument.

allowHelp?: boolean

Whether --help should be handled by this task's CLI parser.

Defaults to true. Dispatcher tasks can set this to false when they need to forward --help to another task tree through a passthrough positional.

interface TaskRunContext {

Runtime context passed to AI-tool-compatible task invocation.

Properties

signal: AbortSignal

Signal cancelled when the tool invocation should stop.

toolCallId: string

Provider tool call id.

step: number

Agent step index for this invocation.

runId: string

Run identifier shared across related tool calls.

messages: ModelMessage[]

Messages visible to the tool invocation.

history?: MessageHistory

Optional persistent message history.

Methods

suspend(opts?: { reason?: string; payload?: unknown; }): never

Suspend this invocation for an external resume flow.

interface TaskOptions< Input = unknown, Output = unknown > {

Options used to create a task.

Properties

name: string

Stable task name used by CLI, tool, and child lookup surfaces.

description?: string

Human-readable description for help text and model tool definitions.

inputSchema?: SchemaLike<Input>

Input schema used to validate raw task input.

outputSchema?: unknown

Optional output schema metadata for callers that inspect task shape.

outputMode?: TaskOutputMode

Output formats this task supports. Defaults to text.

cli?: TaskCliSpec

CLI parser metadata for Task.parse() and Task.help().

children?: Task[]

Child tasks mounted under this task.

effects?: TaskEffect[]

Side-effect metadata for policy and approval layers.

requiresApproval?: boolean

Whether callers should request approval before running this task.

risk?: string

Human-readable risk description.

sideEffects?: boolean

Whether the task is expected to mutate external state.

timeoutMs?: number

Timeout in milliseconds for direct and CLI execution.

throwOnError?: boolean

Whether AI-tool invocation should throw instead of returning error content.

run: TaskHandler<Input, Output>

Executor called after input validation.

interface TaskRunOptions {

Options for direct task execution.

Properties

outputMode?: TaskRequestedOutputMode

Requested output mode for this execution.

writer?: TaskOutputWriter

Writer used to receive task output.

signal?: AbortSignal

Signal cancelled when this run should stop.

runId?: string

Optional run identifier for tracing.

env?: Record<string, string | undefined>

Environment variables visible to the task.

cwd?: string

Current working directory for filesystem-oriented tasks.

prompt?: PromptSession

Prompt session available to interactive tasks.

providedOptions?: ReadonlySet<string>

CLI option keys explicitly provided by the caller.

interface TaskParseOptions extends ParseOptions {

Options for CLI-style task parsing.

Properties

outputMode?: TaskRequestedOutputMode

Requested output mode for the selected task.

writer?: TaskOutputWriter

Writer used to receive parsed task output.

signal?: AbortSignal

Signal cancelled when parsing or execution should stop.

runId?: string

Optional run identifier for tracing.

env?: Record<string, string | undefined>

Environment variables visible to the task.

cwd?: string

Current working directory for filesystem-oriented tasks.

Classes

class Task< Input = unknown, Output = unknown > {

Shared executable task for CLI, AI, MCP, and runtime surfaces.

Readonly Properties

readonly name: string

Stable task name used by CLI, tool, and child lookup surfaces.

readonly description?: string

Human-readable description for help text and model tools.

readonly inputSchema?: Record<string, unknown>

Normalized input schema used for validation and tool parameters.

readonly outputSchema?: unknown

Optional output schema metadata.

readonly outputMode: TaskOutputMode

Output formats this task supports.

readonly cli?: TaskCliSpec

CLI parser metadata for this task.

readonly children: readonly Task[]

Direct child tasks.

readonly effects: readonly TaskEffect[]

Side-effect metadata for policy and approval layers.

readonly requiresApproval: boolean

Whether callers should request approval before running this task.

readonly risk?: string

Human-readable risk description.

readonly sideEffects: boolean

Whether this task is expected to mutate external state.

readonly timeoutMs?: number

Timeout in milliseconds for task execution.

readonly parameters: Record<string, unknown>

Tool parameters derived from the input schema.

Constructors

constructor(options: TaskOptions<Input, Output>)

Methods

async run(rawInput: Input, options: TaskRunOptions = {}): Promise<Output>

Run this task directly with already-structured input.

parse(argv: string[], options: TaskParseOptions = {}): Output | Promise<Output>

Parse CLI argv, select a child task when present, and run the matched task.

help(): string

Generate CLI help text for this task and its child tasks.

child(name: string): Task | undefined

Return a direct child task by name.

list(): readonly Task[]

Return direct child tasks.

async invoke(rawArgs: unknown, ctx: TaskRunContext): Promise<{ content: string | ContentPart[]; isError?: boolean; }>

Invoke this task through the AI-tool-compatible result contract.

toToolDefinition(): ToolDefinition

Convert this task to a provider-neutral model tool definition.

worker(): (call: unknown) => Promise<unknown>

Turn this task (and its children) into a job-worker dispatcher — the default-export-function contract used by scheduled job realms.

A module that default-exports a Task gets this applied automatically by the realm bootstrap, so new Realm({ entry: './my-task.ts' }) and fino:jobs pool processors work on plain task files.

import { task } from 'fino:task';

const compact = task({ name: 'compact', run: async () => 'ok' });
export default compact.worker();

Functions

function task< Input = unknown, Output = unknown >(options: TaskOptions<Input, Output>): Task<Input, Output>

Create a task from metadata and an executor.

function toTaskToolDefinition(t: Task): ToolDefinition

Convert a task into the provider-neutral model tool definition shape.