Skip to content

Options and HostConfig ​

Options describes the agent; HostConfig describes the deployment it runs in. Source: packages/noeta-sdk/noeta/client/options.py and client/host_config.py.

python
from noeta.sdk import Client, HostConfig, Options
from noeta.sdk.providers import AnthropicProvider

options = Options(
    system_prompt="You are a careful coding agent.",
    permission_mode="acceptEdits",
    max_turns=40,
)
host = HostConfig(storage_path="noeta.sqlite", write_mode="apply")

with Client(options, provider=AnthropicProvider(), model="claude-sonnet-5", host_config=host) as client:
    client.start(goal="Fix the failing test in tests/test_utils.py")

Options ​

A frozen dataclass. Fields are either identity (compiled into the recorded AgentSpec; change one and it is a different agent) or wiring (ignored by compile_options and excluded from ==, so swapping a provider or directory never changes identity).

Identity fields ​

FieldTypeDefaultMeaning
system_promptstr | SystemPromptPresetrequiredthe instructions, verbatim or a named preset
namestr"main"agent name; must not collide with an agents key
skillstuple[str, ...]()skills activated for this agent
budgetBudgetSpec | NoneNonecaps; None means BudgetSpec(max_subtask_depth=3)
pluginstuple[str, ...]DEFAULT_PLUGINS = ("fs", "web")plugins this agent activates (below)
agentsMapping[str, AgentDefinition]{}subagents, a flat dict
allowed_toolstuple[str | tool, ...] | NoneNonereplaces the tool list; None = the 10 built-ins, () = none
disallowed_toolstuple[str, ...]()removed from whichever list applies; unknown names ignored
permission_modestr"default"default / acceptEdits / bypassPermissions
max_turnsint | NoneNoneshorthand for budget.max_iterations; setting both raises ValueError
policy(llm) -> Policy with .refNonereplaces the built-in ReAct loop
mcp_serverstuple[SdkMcpServer, ...]()in-process MCP servers; their tools join the tool list

The 10 built-in tools are Read, Write, Edit, Glob, Grep, Bash, BashOutput, KillShell, WebFetch, WebSearch (WebSearch only appears when NOETA_WEB_SEARCH_API_KEY is set). See Tools.

Wiring fields ​

FieldTypeDefaultMeaning
providerLLMProvider | NoneNonethe model adapter; Client(provider=...) wins
modelstr | NoneNonemodel id or alias for decide turns
compaction_modelstr | NoneNonecheaper model for context-compaction summaries only; None = model
recall_modelstr | NoneNoneturns on the memory-recall judge when keyword recall finds nothing; None = keyword recall only
webfetch_modelstr | NoneNonemodel that digests a fetched page for WebFetch; None = the main model
metadataMapping[str, str]{}labels for observers
cwdstr | Path | NoneNoneworkspace fallback when Client gets no workspace_dir
can_use_tool(tool_name, arguments) -> boolNoneapprove/deny gated calls in code; recorded with resolver="can_use_tool"
output_schemaMapping | NoneNoneJSON Schema for the final answer; the answer comes back as a dict / list (raw text if it doesn't parse)
thinking"adaptive" | "disabled" | NoneNonereasoning mode; None = provider default
effort"low" | "medium" | "high" | "xhigh" | "max" | NoneNonereasoning effort
guardstuple[Guard, ...]()checks that run before an action and can deny it
observerstuple[Observer, ...]()callbacks on each committed event
content_channelstuple[ContentKindSpec, ...]()extra resident context blocks

Invalid thinking / effort raise ValueError at construction, and so does thinking="disabled" with effort="xhigh" or "max" (Anthropic rejects that pair).

AgentDefinition ​

A subagent. It cannot nest: declare every agent at the top level of Options.agents.

FieldTypeDefaultMeaning
descriptionstrrequiredshown to the parent model in the Task tool; blank raises ValueError
promptstrrequiredthe subagent's instructions
toolstuple | NoneNoneNone = the built-in tools
modelstr | NoneNonemodel for this subagent; None = host default
pluginstuple[str, ...]()no fs/web default; ("delegation",) lets it spawn its own subagents
metadataMapping[str, str]{}labels, not identity

SystemPromptPreset ​

FieldTypeDefaultMeaning
presetstr"main"a name registered with register_preset_prompt(name, prompt) (last write wins)
appendstr | NoneNonetext appended after a blank line

main and main-web are registered for you — see Presets.

BudgetSpec ​

All fields default to None (no cap): max_iterations, max_tool_calls, max_cost_usd, max_spawned_subtasks, max_subtask_depth. Counters cover the task's whole life, not one turn.

compile_options ​

python
compile_options(options, *, plugins=None, preset_prompts=None)
    -> tuple[AgentSpec, tuple[AgentSpec, ...]]

Pure: equal Options give equal specs. plugins maps plugin name to PluginActivation (the Client builds it from its PluginSet); preset_prompts replaces the process-wide preset registry for a hermetic compile.

Permission modes ​

ModeAsks before running
defaultevery tool whose risk_level is not low
acceptEditsthe same, except Edit and Write
bypassPermissionsnothing

Bash and WebFetch are also gated per call: a command outside the shell allowlist, or a host outside HostConfig.webfetch_allowed_hosts, asks — except under bypassPermissions. A Guard can still deny in any mode.

Read the legal values at runtime, in display order:

python
from noeta.sdk import effort_modes, model_capabilities, permission_modes

permission_modes()   # ('default', 'acceptEdits', 'bypassPermissions')
effort_modes()       # ('low', 'medium', 'high', 'xhigh', 'max')
model_capabilities(["claude-sonnet-4-6", "gpt-4o-mini"])
# {'claude-sonnet-4-6': {'supports_vision': True}, 'gpt-4o-mini': {'supports_vision': False}}

An uncatalogued model reports supports_vision: True.

Plugin activation ​

Options.plugins names the plugins this agent uses, and the names are recorded in AgentSpec.plugins. A name must be one of:

KindNames
built-in feature (turns a capability on)memory, browser, mcp, todo_write, ask_user_question, skill_invocation, delegation
built-in, no effect on the agent (recognised so typos fail)app, fs, governance, presets, providers, react, reminders, sandbox, skills, storage, web, workspace
a loaded pluginany name in the PluginSet passed to Client
python
from noeta.sdk import DEFAULT_PLUGINS, Options

Options(system_prompt="...", plugins=DEFAULT_PLUGINS + ("memory", "todo_write"))
# plugins=("memry",) fails at compile:
#   ValueError: unknown plugin activation 'memry' on Options — not a built-in activation (...)

delegation is added automatically when agents is non-empty; naming it only ever turns it on. Dropping fs/web does not remove the default tools, but it does change the recorded identity.

HostConfig ​

A frozen dataclass passed as Client(..., host_config=...). Never part of agent identity. HostConfig() means in-memory storage, no sandbox, no MCP.

Storage ​

FieldTypeDefaultMeaning
storage_pathstr | NoneNonesqlite file path, postgresql:// DSN, or ":memory:"
event_log, content_store, dispatcheradaptersNoneexplicit storage; all three or none
queuestr"default"this client's worker queue on a shared store; its workers claim only this queue

Passing storage_path and the explicit trio together, or only part of the trio, raises ValueError. noeta.sdk.storage.open_storage_stack(path) builds the trio from one string; the module also exports build_storage_stack, is_memory_path, is_postgres_url and the Sqlite / Postgres adapters.

Model calls and MCP ​

FieldTypeDefaultMeaning
provider_headers(StepContext) -> Mapping[str, str]Noneextra headers per model request (e.g. a gateway stickiness key)
delta_sink(StepContext, call_id, StreamDelta) -> NoneNonelive token deltas from a streaming provider; never stored
extra_modelsMapping[str, ModelSpec]{}extra model rows for the catalog; a name clash fails; register the same rows every run
mcp_server_resolver(alias) -> McpAnyServerSpec | NoneNoneresolves MCP aliases each turn
mcp_http_postHttpPostFnNonecustom HTTP transport for remote MCP
mcp_idle_ttlfloat | None1800.0seconds an unused pooled MCP connection stays open; None = forever
mcp_scope_resolver(task_id) -> str | NoneNonepool partition (e.g. a tenant id); tasks share a connection only within a scope
otlp_tracesOtlpTraceConfigNoneOTLP/HTTP trace export: endpoint, headers=(), service_name="noeta"
otlp_http_postcallableNonecustom transport for the exporter

Sandbox ​

FieldTypeDefaultMeaning
exec_envSandboxExecEnvConfigNoneattach one shared container: base_url, api_key_env="SANDBOX_API_KEY", workdir="/workspace"
sandbox_providerSandboxProviderNonea fresh container per root task; wins over exec_env
sandbox_specSandboxSpecNonefixed part of each allocation: image, mounts, resources, env
sandbox_exec_preamble(exec_env_ref, argv) -> strNoneshell prefix computed per command (fresh credentials)
sandbox_backend_factory, sandbox_browser_factoryfactoriesNonereplace the sandbox or browser client
sandbox_policy(root_task_id, workspace_dir) -> boolNoneFalse runs that task locally
app_gatewayAppPreviewGatewayNoneenables the open_app preview tool
write_roots(task_id) -> Sequence[str]Noneextra directories a task may write outside its workspace
write_mode"dry_run" | "apply""dry_run""apply" performs real file writes; anything else raises

Memory ​

Store root precedence: memory_root_resolver > memory_dir > global_memory_dir > ~/.noeta/memories. See Per-tenant memory.

FieldTypeDefaultMeaning
memory_dir, global_memory_dirPath | NoneNonehost-level store roots
memory_root_resolver(task_id) -> Path | NoneNoneper-task store root; must be deterministic per task
recall_excludeCollection[str]()pages auto-recall never brings in (still listed and readable)
memory_max_bytesint | NoneNonerefuse a memory_write body over this many UTF-8 bytes; keep under 4096 so pages recall whole
memory_read_onlyboolFalseoffer only memory_read and memory_search
memory_index_budget_tokensint | NoneNonesize cap for the memory index; None = 1% of the context window

Skills and plugins ​

FieldTypeDefaultMeaning
skill_menu_rank_resolver(task_id) -> {skill: score} | NoneNonewhich skills keep full descriptions when the menu is over budget
skill_usage_rankingboolTruewith no resolver, rank by recent usage across the store; off automatically when a memory or MCP scope resolver is set
plugin_configMapping[str, Mapping[str, Any]]{}per-plugin operator config; for fs / skills / workspace / memory your keys override the derived ones key by key

The skill menu takes 1% of the context window. Over that, entries shrink to a one-sentence summary, then to the name alone, lowest rank first. A static rank can go in plugin_config["skills"]["menu_rank"] instead of a resolver (not both).

Limits and switches ​

FieldTypeDefaultMeaning
repetition_thresholdint | NoneNoneafter this many identical (tool, arguments) calls, ask for approval; must be positive
tool_output_inline_limitint | NoneNonetruncate any tool result over this many characters before the model sees it (full bytes stay recorded); must be positive; keep it stable across resumes
webfetch_allowed_hostsSequence[str]()hosts WebFetch reaches without approval: "example.com" exact, "*.example.com" subdomains only; bad entries raise
workflow_allowedboolFalseexpose run_workflow (also needs delegation)
max_background_jobs_per_root_taskint8background Bash jobs past this are rejected
max_background_subagents_per_root_taskint8same for Task(background=True)
environment_enabledboolTruerecord the working directory / git / platform block at task start
instructions_enabledboolFalseload NOETA.md, else AGENTS.md, else CLAUDE.md from the workspace root
instructions_filePath | NoneNoneload this file instead of searching
instructions_discoveryboolFalsealso pick up instruction files in subdirectories the agent reads

WARNING

webfetch_allowed_hosts only controls approval prompts. WebFetch blocks no address itself — enforce egress at the network or sandbox.

Wiring types ​

SymbolMeaning
SandboxProviderProtocol: allocate / release / attach
SandboxSpec, MountSpecallocation input; MountSpec(source, target, mode="rw", kind="local-path"), kind in local-path / nas / volume / pvc
SandboxHandlea live container: base_url, sandbox_id, auth, workdir="/workspace"
SandboxAuth, StaticApiKeyAuthconnect_headers() Protocol and its env-var implementation
encode_exec_env_ref, decode_exec_env_refcodec for the recorded container reference
ExecEnv, BrowserBackendexecution and browser Protocols
BackendFactory, BrowserBackendFactory, BoundPreambletypes for the sandbox factory fields
McpServerSpec, McpHttpServerSpec, McpAnyServerSpecwhat mcp_server_resolver returns (stdio, HTTP, either)
HttpPostFn, McpHttpResponse, McpError, McpConfigErrorMCP transport and errors
OtlpTraceConfigtrace export config
path_within(resolved, root) -> boolthe write fence's containment check, by path component (/srv/app-old is not inside /srv/app)

Next ​

Released under the Apache License 2.0.