Capability: configuration
One TOML file validated into typed models that reject unknown keys; every secret from the environment only; one CLI that fails to start with the missing variable's name; Temporal either remote or embedded, from the same file.
What it is
How a deployment is described and how the processes come up. Lives in tiny_harness/config.py, tiny_harness/service/cli.py, commands.py and runtime.py.
Current behaviour
SettingsSHALL be the sectionstemporal,openai,anthropic(optional),server,heartbeat,plugins,agents,card,store,o11y,retries,contextandretention, every modelextra="forbid".[server] delegatorsSHALL list the participant ids trusted to setlifecycle,modelandreasoning_efforton a new task's first message; this agent's own id is always trusted.agents[].idSHALL NOT beself, the harness's own agent id (issue-34 R7).[card]SHALL take an optionalname,descriptionandversionand a list of[[card.skills]](id,name,description,tags,examples). A set string SHALL not be blank, and skill ids SHALL be unique; otherwise startup exits with status 2. An absent section or key keeps the built-in default (issue-34).- Each
agentsentry SHALL takeid,url,versionand, from issue-27,updates(auto,followoroff; defaultauto) andfollow_interval(default 5 s, at least 1 s); any otherupdatesvalue, or a shorter interval, exits with status 2 namingagents.<n>.<key>. [temporal] modeSHALL beremote(the default) orembedded; any other value exits with status 2 namingtemporal.mode. Remote mode requiresaddress,namespaceandTEMPORAL_API_KEYand refuses[temporal.embedded]; embedded mode refusesaddress,tlsandTEMPORAL_API_KEY, defaultsnamespacetodefault, and takes the optional[temporal.embedded]table (persist,database_path,binary_path,download_dir,port). Abinary_paththat is not an executable file exits with status 2.[openai]and[anthropic]SHALL also takemodels(the models/modelmay select; unset meansmodelalone) andreasoning_effort(low,mediumorhigh; the default effort, unset means none is sent). Amodelslist that is empty or lacksmodelSHALL exit with status 2 namingopenai.models, never "any model allowed".[openai]SHALL takebase_url(an absolutehttp/httpsURL; defaulthttps://api.openai.com/v1),api(responsesorchat_completions),model,timeout,max_output_tokensandcontext_window_tokens(a positive integer; a boolean or a float is refused).OPENAI_API_KEYSHALL be required only whenbase_urlis unset. Abase_urlwith user information, or withhttpto a non-loopback host while a key is set (loopback islocalhostor a literal loopback address, never resolved), SHALL exit with status 2 namingopenai.base_url.- Secrets SHALL come only from
TEMPORAL_API_KEY(remote mode only),OPENAI_API_KEY, andANTHROPIC_API_KEY,LANGFUSE_PUBLIC_KEY,LANGFUSE_SECRET_KEY(when their features are configured), held asSecretStrand never printed; the configured values are what the redactor masks. TINY_HARNESS_PUSH_KEYSHALL NOT be read; WHEN it is set THEN the runtime SHALL log oneWARNINGthat it is set and ignored, without its value (as forOPENAI_BASE_URL).- WHEN a required secret is missing or a key is unknown THEN the process SHALL exit with status 2 and the variable or key on stderr, with no anonymous or local fallback.
- The CLI SHALL be
tiny-harness [--config FILE] [serve [--with-worker] | worker | tui [--url] [--participant] | schedules delete | tasks purge <task-id>]; with no subcommand it SHALL runtuiwith no--url.--versionprints the package version and--helpnames the configuration file in effect and whether it came from--configor the default location (--helpnever creates it). - The configuration file SHALL be
--configwhen given, else~/.tiny-harness/config.toml(tiny_harness/home.py), for every subcommand. With--configthe home directory is never read or created, and a missing file exits 2. WHEN the default file is missing THEN the CLI SHALL create~/.tiny-harness/(mode0700) and the file (0600,O_EXCL | O_NOFOLLOW, through a no-follow directory descriptor), printcreated default configuration <path>on stderr and go on. The file selects embedded Temporal withpersist = true, puts the store (and so the Temporal database and the TUI log) under the home with absolute paths, holds no secret and comments every key. An existing file is never rewritten. A home or file that is a symlink, not a directory or regular file, or owned by another user SHALL exit 2 naming the path; there is no fallback to running without a file. - In embedded mode,
workerSHALL exit 2 (the worker runs insideserve),serveSHALL run the worker in-process,tuiwith no--urlSHALL host the harness in its own process (logs totiny-harness.logbeside the store), andschedules delete/tasks purgeSHALL act on the persisted state, exiting 2 whenpersist = false. A dev server that fails to start SHALL exit 1 with the cause. SIGTERM SHALL cancel the main task so everyfinallyruns:serve(and the programmaticserve) then exits 0, the other commands 143 (tiny_harness/service/signals.py). tiny_harness.serviceSHALL export the programmatic entry pointsrunning_harness,serve,RunningHarness,temporal_clientandcomplete_message, driven by the sameSettingsas the CLI.running_harnesstakesplugins=(paths orPluginobjects, loaded aftersettings.pluginswith override),commands=((CommandSpec, handler)pairs) andbuiltin_commands=False.Settings.loadand the entry points SHALL NOT read or create~/.tiny-harness/;tiny_harness.home.resolve_config_pathandensure_default_configare what the CLI calls, public for an SDK caller.[agent]SHALL name the agent:id(lowercase, digits and-, defaulttiny-harness). The card's name and description stay in[card].[temporal] task_queueSHALL default toagent.id. A file without either keeps the id and queuetiny-harness.tiny_harness.serviceSHALL also exportHarness,harnesses_lifespanandRouteOptions.pip install 'tiny_harness[fastapi]'addstiny_harness.fastapi, whose import without FastAPI names the extra.build_runtimeSHALL assemble one process fromSettings: the built-in plugin, the operator's plugins, the MCP tool sources, the skills, the system prompt, the model, the store and the in-process engine the activities run over, with the plugin data root atplugin-data/beside the store.selfSHALL carry the harness'spublic_url. A remote agent whose URL is a harness of this process SHALL get that harness's card built from its settings, not fetched.- The demo configuration SHALL document the keyring lookups
secret-tool lookup service temporal project tiny-harnessandsecret-tool lookup service openai project tiny-harness.
Design
design.md § Configuration, deploy guide, configuration.
History
| Work item | What changed | Links |
|---|---|---|
| issue-3 | Settings, secrets, errors (Layer 1); the CLI and runtime (Layer 5); trace_file, search_attributes, ui_dir, cors_origins (Layers 8–9) | spec, PR #7, PR #11 |
| issue-17 | temporal.mode and [temporal.embedded]; per-command embedded behaviour; the programmatic API in tiny_harness.service; SIGTERM cancels the main task | spec, PR #18, decision-005 |
| issue-19 | [openai] base_url, api, context_window_tokens; OPENAI_API_KEY optional with a base_url; examples/demo/config.ollama.toml | spec, PR #22, decision-006 |
| issue-23 | TINY_HARNESS_PUSH_KEY and Settings.push_key removed; a set variable is reported as ignored | spec, PR #24 |
| issue-25 | The default file ~/.tiny-harness/config.toml (created safely, --config wins); bare tiny-harness runs the TUI; --help names the file; models and reasoning_effort; running_harness(plugins=, commands=, builtin_commands=) and complete_message | spec, PR #26, decision-007 |
| issue-27 | agents[].updates and agents[].follow_interval | spec, PR #28 |
| issue-34 | [card]: this agent's own card name, description, version and skills | spec, PR #35 |
| issue-34 (R7) | [server] delegators; the agent id self reserved | spec, PR #35 |
| issue-36 | [agent]; the task queue defaults to the agent id; Harness, harnesses_lifespan, RouteOptions exported; the fastapi extra | spec, PR #37, decision-009 |