Why Nanitics is shaped this way

This page describes the design decisions behind Nanitics and the reasoning for them. It is written for engineers and tech leads evaluating the SDK before adopting it.

Composable primitives, not a framework

Agentic systems vary widely in shape. A research workflow, a customer-support handoff chain, and a code-execution sandbox have little in common at the runtime layer. A framework that imposes one shape on all of them either constrains the systems that fit it badly, or grows in surface area until the framework becomes the application.

Nanitics is a library of independent primitives. Agent strategies, coordination patterns, memory stores, and planners are classes that share only the protocols they need to interoperate. An author composes them by passing instances into constructors, with no required shape for the surrounding program.

The cost is a longer ramp before an application is useful. The benefit is no binding to a runtime, database, web framework, or workflow shape chosen by someone else. Orchestration shape, persistence layer, and runtime form (CLI, job runner, HTTP server, long-running daemon) are application-level decisions the author makes when composing the primitives.

Composable primitives also localise change. A primitive that needs to evolve does so on its own public surface, without disturbing a top-down framework lifecycle. The deprecation policy and the changelog record the contract for change so an adopter can plan around it.

Trace-first observability as a design discipline

Observability added after the code is written drifts from the code that produced it. The events name what the instrumentation author remembered to record rather than what the primitive actually did, and the trace becomes a partial reconstruction of the run instead of a faithful record.

Every primitive in Nanitics emits structured events by default. Agent loop iterations, tool invocations and returns, coordination handoffs, and evaluator verdicts produce events without configuration. The Observatory trace viewer reads these events directly and renders them as a hierarchical timeline. No separate tracing service is required, and no additional instrumentation is needed for a useful trace.

This shapes how an engineer writes code with the SDK. A new behaviour begins with the events it should emit, before the data structure that holds its state. Observability is part of the primitive’s design from the start, not a feature added at the end.

The same trace supports debugging and after-the-fact auditing. A failed run renders as a tree of decisions, tool calls, evaluator verdicts, and the point at which the loop broke.

Real-services validation

A test suite that runs only against mocks confirms that the code behaves the way the test expected. It does not confirm that the public surface behaves the way the documentation claims when bound to a real LLM, a real embedding service, and a real search provider. Both questions matter for an SDK that ships a public API.

The Nanitics test suite covers both. Unit tests run against MockLLMClient and MockEmbeddingClient at one hundred per cent line coverage. A separate validation suite runs every public component against real providers before each release.

The mocks are written so an example built against them runs unchanged against the real providers when the client is swapped. The shape of the mock is the shape of the contract, and the validation suite enforces that the contract holds.

Documentation philosophy

Documentation that drifts from the code it describes leads adopters to build on false assumptions, then discover the divergence at runtime. A smaller documentation set that stays accurate is more useful to an adopter than a comprehensive one that has fallen behind.

Each concept has one source of truth. Docstrings cover API details and live in the file they describe, so the documentation a reader sees in the editor matches the implementation in front of them. Guides under docs/guides/ cover decision guidance: when to use a primitive and what trade-offs it involves. Examples under examples/ are complete runnable programs with no missing imports or stubbed helpers.

When something in the SDK changes, the docstring changes in the same commit, and any guide that describes the affected concept is updated alongside it. Drift between code and docs is the failure mode the project treats as a bug.

Next steps