Reference

Config schema

All config files parse into a ProjectConfig instance. The classes below correspond directly to the fields you write in .jsonnet / .json.

class ProjectConfig(**data)[source]

Top-level kiln configuration.

A project is a collection of apps plus shared infrastructure (auth, databases, framework target). Resources always live under apps[*].config.resources; a shorthand config with top-level module / resources / operations fields is wrapped into a single implicit app with prefix="" by _wrap_shorthand(), so the scope tree (project app resource) is uniform across configs.

Inherits package_prefix from foundry and overrides its default to "_generated" so generated code lives at _generated/{module}/ and is imported as _generated.{module}.routes.article. Set it to "" to disable the prefix.

apps: Annotated[list[App], Scoped(name=app)]
auth: AuthConfig | None
databases: list[DatabaseConfig]
framework: str

Target framework profile. Selects which renderer set runs; each renderer is tagged with the framework it implements, and only those matching this value are used.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

package_prefix: str
resolve_database(db_key)[source]

Return the DatabaseConfig selected by db_key.

When db_key is None, returns the database marked default=True.

Raises:

ValueError – If db_key does not match any configured database, or if no database has default=True and db_key is None.

Return type:

DatabaseConfig

version: str
class AppConfig(**data)[source]

One app within a project: a module of related resources.

An app owns its own Python package (module) and a list of resources.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

module: str
resources: Annotated[list[ResourceConfig], Scoped(name=resource)]
class App(**data)[source]

An app mounted at a URL prefix in the project router.

config: AppConfig
model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

prefix: str
class ResourceConfig(**data)[source]

A resource: a consumer-defined Python model plus its operations.

model is a dotted import path to any SQLAlchemy selectable class (table, mapped view, etc.) defined by the consumer, e.g. "myapp.models.Article".

operations is a scoped list of OperationConfig entries — each entry becomes an "operation" scope instance that the engine visits independently.

require_auth sets the default authentication requirement for all operations. Individual operations can override this via their own require_auth field.

db_key: str | None
generate_tests: bool

When True, emit a pytest test file for this resource’s generated routes and serializers.

model: str

Dotted import path to the consumer’s SQLAlchemy model class, e.g. "myapp.models.Article".

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

operations: Annotated[list[OperationConfig], Scoped(name=operation)]

Ordered list of operations to run — each becomes a scope instance of "operation" that the engine visits in turn.

pk: str

Primary-key attribute name on the model.

pk_type: Literal['uuid', 'str', 'email', 'int', 'float', 'bool', 'datetime', 'date', 'json']

Type of the primary key, used to generate the correct path parameter.

require_auth: bool

Default authentication requirement for all operations on this resource. Individual operations can override via their own require_auth field.

route_prefix: str | None

URL prefix for this resource’s router, e.g. "/articles". Defaults to "/{model_lower}s" (simple lowercase + ‘s’).

class OperationConfig(**data)[source]

Configuration for a single operation.

Known fields (name, require_auth) are parsed normally. All other keys are collected into options via Pydantic’s extra="allow" setting and passed to the operation’s Options model (see foundry.operation.operation()).

Each OperationConfig is a scope instance of the "operation" scope: the engine descends into ResourceConfig.operations and visits each entry independently. Every @operation class with dispatch_on="name" matches at most one entry per resource — the one whose name equals the op’s own.

Examples:

# Built-in operation
{"name": "get"}

# With extra options (go into ``options`` via model_extra)
{"name": "create", "fields": [...]}

# Action operation
{"name": "publish", "fn": "blog.actions.publish", "params": [...]}

# Custom third-party operation
{"name": "bulk_create", "class": "my_pkg.ops.BulkOp", "max": 100}
model_config: ClassVar[ConfigDict] = {'extra': 'allow'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
property options: dict[str, Any]

Operation-specific options (all extra fields).

require_auth: bool | None

Per-operation auth override. When None, inherits the resource-level require_auth default.

class FieldSpec(**data)[source]

A named, typed field — used in operation schemas and action params.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
type: Literal['uuid', 'str', 'email', 'int', 'float', 'bool', 'datetime', 'date', 'json']
class AuthConfig(**data)[source]

JWT authentication configuration.

algorithm: str
exclude_paths: list[str]
get_current_user_fn: str | None

Dotted import path to a custom get_current_user dependency, e.g. "myapp.auth.custom.get_current_user". When set, the generated auth/dependencies.py re-exports this function instead of containing the default JWT implementation.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

secret_env: str
token_url: str
type: Literal['jwt']
verify_credentials_fn: str | None

Dotted import path to a credential-verification function, e.g. "myapp.auth.verify_credentials". The function must accept (username: str, password: str) and return a dict (the JWT payload) on success or None on failure.

Required when using the default JWT auth flow (get_current_user_fn is not set).

class DatabaseConfig(**data)[source]

Configuration for a single database connection.

default: bool
echo: bool
property get_db_fn: str

Name of the FastAPI dependency exposed by the session module.

key: str
max_overflow: int
model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

pool_pre_ping: bool
pool_recycle: int
pool_size: int
pool_timeout: int
property session_module: str

Dotted module path of the scaffolded session file.

Matches what DbScaffold emits at db/{key}_session.py.

url_env: str

Field types

The type field on FieldSpec accepts:

Type

Python annotation

Used in

Notes

uuid

uuid.UUID

request/response schemas, pk

Default for primary keys.

str

str

schemas, action params

email

str

schemas

Added pydantic.EmailStr validation.

int

int

schemas, pk

float

float

schemas

bool

bool

schemas

datetime

datetime.datetime

schemas

date

datetime.date

schemas

json

dict[str, Any]

schemas

Built-in operations

Every built-in operation is registered under the foundry.operations entry-point group in kiln’s own pyproject.toml. See Usage for what each one generates and Extending kiln for the operation protocol.

Name

Module

Scope

Description

scaffold

kiln.operations.scaffold

project

Emits db/*_session.py and (if auth is configured) auth/dependencies.py + auth/router.py.

get / list / create / update / delete

kiln.operations.get, list, create, update, delete

resource

The five CRUD endpoints. Each op lives in its own module alongside the FastAPI renderer for its output.

action

kiln.operations.action

resource

Custom action endpoints: POST /{pk}/{slug} for per-instance actions, POST /{slug} for collection-level actions.

auth

kiln.operations.auth

resource

Cross-cutting augmenter. Appends current_user dependency to every CRUD / action handler when config.auth is set.

router

kiln.operations.routing

app

Emits routes/__init__.py for one app, aggregating every resource router via include_router.

project_router

kiln.operations.routing

project

Multi-app projects only. Emits the top-level routes/__init__.py that mounts each app at its prefix.

Generated file layout

The table below summarises every file kiln can produce. Paths are relative to the --out directory (or to the config’s package_prefix when --out is omitted). {module} is the app’s module config field. {name} is the lowercase, snake-cased model name.

Path

Produced by

Overwrite

db/__init__.py

scaffold

Yes

db/{db_key}_session.py (or db/session.py)

scaffold

Yes

auth/__init__.py

scaffold

Yes

auth/dependencies.py

scaffold

Yes

auth/router.py

scaffold

Yes

{module}/schemas/{name}.py

get / list / create / update

Yes

{module}/serializers/{name}.py

get / list

Yes

{module}/routes/{name}.py

CRUD + action

Yes

{module}/routes/__init__.py

router

Yes

{module}/tests/test_{name}.py

CRUD + action (when generate_tests: true)

Yes

routes/__init__.py

project_router

Yes

Every file is overwritten on every generation run.

foundry API

Targets

class Target(name, language, schema, template_dir, jsonnet_stdlib_dir=None)[source]

A concrete code-generation target.

name

Short identifier, used for --target dispatch when multiple targets are installed and as the jsonnet stdlib import prefix.

language

Language-identifier the target generates for (e.g. "python"). Passed to foundry.imports.format_imports() so the assembler renders import blocks in the right syntax. Targets declare their formatter under the foundry.import_formatters entry-point group.

schema

FoundryConfig subclass the target’s config files validate against. Foundry’s loader instantiates this.

template_dir

Directory of Jinja templates the target’s renderers reference. Foundry builds the Jinja environment rooted here.

jsonnet_stdlib_dir

Optional directory of jsonnet .libsonnet files exposed to configs as <name>/... imports. None when the target ships no stdlib.

discover_targets()[source]

Load every Target registered under foundry.targets.

Return type:

list[Target]

Returns:

All installed targets, in entry-point discovery order.

class CLIError[source]

Base class for errors the CLI should render cleanly.

Subclasses set prefix to control how the error is labelled when rendered at the CLI boundary.

Engine

class Engine(registry=<factory>, package_prefix='')[source]

Orchestrates the build phase of code generation.

registry

OperationRegistry holding the ops to run. Defaults to the populated DEFAULT_REGISTRY; tests pass an isolated registry to keep their ops out of the global one.

package_prefix

Dotted prefix for generated imports, forwarded to every BuildContext.

build(config)[source]

Run the build phase over all scopes and operations.

Walks the scope tree depth-first. At each scope instance, pre-phase operations (after_children=False) run before descending into children; post-phase operations (after_children=True) run after every child scope instance completes, so they can aggregate earlier output from the store.

Parameters:

config (BaseModel) – The project config model instance.

Return type:

BuildStore

Returns:

An BuildStore containing all objects produced by operations.

class BuildContext(config, scope, instance, instance_id, store, package_prefix='')[source]

Context passed to every operation’s build method.

Parameterized on the scope instance type so operations can annotate e.g. ctx: BuildContext[ResourceConfig] and get typed access to ctx.instance.*. The engine itself builds BuildContext[Any] since it’s scope-agnostic.

config

The full project config (top-level model).

scope

The scope this operation is running in.

instance

The config object for the current scope instance (e.g. one resource’s config dict).

instance_id

Human-readable identifier for the instance within its scope.

store

The build store for querying earlier operations’ output.

package_prefix

Dotted prefix for generated imports (e.g. "_generated"). Extensions use this to resolve their own import paths.

Operations

operation(name, *, scope, requires=None, after_children=False, dispatch_on=None, registry=OperationRegistry(entries=[OperationEntry(meta=OperationMeta(name='get', scope='operation', requires=(), after_children=False, dispatch_on='name'), cls=<class 'kiln.operations.get.Get'>), OperationEntry(meta=OperationMeta(name='list', scope='operation', requires=('get', ), after_children=False, dispatch_on='name'), cls=<class 'kiln.operations.list.List'>), OperationEntry(meta=OperationMeta(name='create', scope='operation', requires=('list', ), after_children=False, dispatch_on='name'), cls=<class 'kiln.operations.create.Create'>), OperationEntry(meta=OperationMeta(name='update', scope='operation', requires=('create', ), after_children=False, dispatch_on='name'), cls=<class 'kiln.operations.update.Update'>), OperationEntry(meta=OperationMeta(name='delete', scope='operation', requires=('update', ), after_children=False, dispatch_on='name'), cls=<class 'kiln.operations.delete.Delete'>), OperationEntry(meta=OperationMeta(name='action', scope='operation', requires=(), after_children=False, dispatch_on=None), cls=<class 'kiln.operations.action.Action'>), OperationEntry(meta=OperationMeta(name='auth', scope='resource', requires=(), after_children=True, dispatch_on=None), cls=<class 'kiln.operations.auth.Auth'>), OperationEntry(meta=OperationMeta(name='scaffold', scope='project', requires=(), after_children=False, dispatch_on=None), cls=<class 'kiln.operations.scaffold.Scaffold'>), OperationEntry(meta=OperationMeta(name='auth_scaffold', scope='project', requires=(), after_children=False, dispatch_on=None), cls=<class 'kiln.operations.scaffold.AuthScaffold'>), OperationEntry(meta=OperationMeta(name='router', scope='app', requires=(), after_children=True, dispatch_on=None), cls=<class 'kiln.operations.routing.Router'>), OperationEntry(meta=OperationMeta(name='project_router', scope='project', requires=(), after_children=False, dispatch_on=None), cls=<class 'kiln.operations.routing.ProjectRouter'>)]))[source]

Decorate a class as a kiln operation.

The decorated class must define:

  • Options: a pydantic.BaseModel subclass (defaults to EmptyOptions if absent).

  • build(self, ctx, options) -> list: produces output objects for the engine to collect.

Optionally it may define:

  • when(self, ctx) -> bool: when present and returning False, the engine skips this operation for the current build context. Use this for conditional operations (e.g. auth, which only runs when the project has auth configured).

Operations can also modify earlier operations’ outputs by inspecting BuildContext.store and mutating the objects returned by BuildStore.outputs_under() in place. Combined with requires for ordering and when for activation, a single operation mechanism covers both “produce” and “augment” roles.

Parameters:
  • name (str) – Unique operation name.

  • scope (str) – Scope name (e.g. "resource", "app", "project").

  • requires (list[str] | None) – Operation names that must run first.

  • after_children (bool) – When True (project scope only), defer this operation until every child scope has executed so build can walk child output in the store. The engine rejects this flag at any other scope.

  • dispatch_on (str | None) – Attribute name on the scope instance to compare against name. When set, the engine skips the op unless getattr(ctx.instance, dispatch_on) == name. Designed for scopes whose instance is a discriminated-union config (e.g. OperationConfig entries under a resource), where multiple ops share one scope and each matches a single entry.

  • registry (OperationRegistry) – Registry to register into. Defaults to the process-wide DEFAULT_REGISTRY; tests may pass an isolated registry to keep their ops out of the global namespace.

Return type:

Any

Returns:

Class decorator.

Example:

@operation("get", scope="resource")
class Get:
    class Options(BaseModel):
        fields: list[FieldSpec] | None = None

    def build(self, ctx, options):
        return [RouteHandler(...)]
class OperationMeta(name, scope, requires=(), after_children=False, dispatch_on=None)[source]

Metadata attached to a decorated operation class.

name

Unique operation name (e.g. "get").

scope

Scope name this operation runs in (e.g. "resource").

requires

Names of operations that must run before this one within the same scope.

after_children

When True, this project-scope operation runs after all child scopes have executed, so its build method can inspect objects produced at the resource/app scopes via the build store. Ignored outside the project scope (the engine raises if set).

dispatch_on

Attribute name on ctx.instance whose value must equal name for this op to run. Engine skips the op silently when the attribute is absent or mismatched. Use it at scopes where the instance is a discriminated union — every registered op at the scope shares the scope walk and each dispatches to its own entry by name.

class EmptyOptions(**data)[source]

Default options model for operations with no config.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

Scopes

class Scope(name, config_key, parent=None, resolve_path=())[source]

A named level in the config tree.

name

Human-readable scope name, e.g. "resource".

config_key

The config field name that produced this scope, e.g. "resources". Empty string for the root (project) scope.

parent

The parent scope, or None for the root.

resolve_path

Dotted attribute path from parent’s scope instance to this scope’s list of items. Empty for the root scope. Defaults to (config_key,) for a direct child.

discover_scopes(config_cls)[source]

Derive scopes from a Pydantic model’s Scoped markers.

The top-level config is always the "project" scope. Each field declared Annotated[list[T], Scoped()] becomes a child scope of the current level; the item type T is then itself descended into to discover grandchild scopes.

Non-list BaseModel fields (e.g. App.config) are traversed transparently: their nested Scoped fields become scopes rooted at the enclosing level, with resolve_path reflecting the full attribute walk.

Each scoped item type is descended into at most once, so discovery always terminates. If the same type appears in multiple scoped lists only the first occurrence is descended — subsequent ones still produce their own scope but no grandchildren.

Parameters:

config_cls (type[BaseModel]) – The Pydantic model class to inspect.

Return type:

ScopeTree

Returns:

ScopeTree containing every discovered scope, project first.

foundry.scope.PROJECT

The root scope – always present in every generation run.

Typed outputs

Every operation’s build method returns instances of the types below. All are mutable dataclasses.

class StaticFile(path, template, context=<factory>)[source]

A file rendered directly from a template.

Used for scaffold files (auth, db sessions), utils, and other files that don’t need the assembler’s multi-contributor merging.

Render registry

class RenderRegistry(_entries=<factory>)[source]

Maps output types to renderer functions.

Example:

registry = RenderRegistry()

@registry.renders(RouteHandler)
def render_route(handler, ctx):
    return Fragment(...)
render(obj, ctx)[source]

Produce fragments for a build output.

Every registered renderer returns an iterable of fragments (typically as a generator via yield). Renderers usually yield a FileFragment declaring the output file plus one or more SnippetFragment contributions into its slots.

Parameters:
  • obj (object) – The build output to render.

  • ctx (RenderCtx) – Render context.

Return type:

list[FileFragment | SnippetFragment]

Returns:

A list of fragments. May be empty if the renderer decides not to contribute.

Raises:

LookupError – No renderer registered for the type.

renders(output_type)[source]

Register a renderer for output_type.

Parameters:

output_type (type) – The output class this renderer handles.

Return type:

Callable[[Callable[[Any, RenderCtx], Iterable[FileFragment | SnippetFragment]]], Callable[[Any, RenderCtx], Iterable[FileFragment | SnippetFragment]]]

Returns:

The original function, unmodified.

class RenderCtx(env, config, package_prefix='', language='', store=<factory>, instance_id='')[source]

Context passed to every renderer function.

env

Jinja2 environment for template lookups.

config

The full project config dict (or model).

package_prefix

Dotted prefix for generated imports, e.g. "_generated".

language

Target language identifier used to render import blocks (e.g. "python"). Must match a formatter declared in the foundry.import_formatters entry-point group.

store

The build store. Renderers reach ancestor scope instances through it (e.g. a handler rendered at operation scope looks up its resource via store.ancestor_of(instance_id, "resource")).

instance_id

Id of the scope instance whose output is being rendered. Paired with store for ancestor and self lookups.

class BuildStore(scope_tree=<factory>, _items=<factory>, _instances=<factory>, _children=<factory>, _parent_of=<factory>)[source]

Accumulator for objects produced during the build phase.

Objects are keyed by (instance_id, op_name). Instance ids are dot-path strings produced by the engine (e.g. "project.apps.0.resources.2") — the leaf scope, the ancestor chain, and every index are all recoverable from the id via foundry.scope.scope_for(), so the store never needs a separate scope field.

Ancestry is tracked in _children — the engine records each instance’s parent id on registration so children() can walk the tree without callers reconstructing store keys.

scope_tree

ScopeTree for the build’s config. Required for the scope_of() derivation (and therefore for child_scope= filtering on children()). Defaults to empty so ad-hoc store-level tests can skip it when they don’t care.

_items

Internal storage mapping (instance_id, op_name) keys to object lists.

_instances

Map from instance_id to the scope-instance config object.

_children

Map from a parent instance id to its registered child instance ids, in insertion order.

add(instance_id, op_name, *objects)[source]

Store build outputs for a build step.

Parameters:
  • instance_id (str) – Dot-path id produced by the engine.

  • op_name (str) – Operation name that produced these objects.

  • *objects (object) – The build outputs to store.

Return type:

None

ancestor_of(instance_id, scope_name)[source]

Return the enclosing instance at scope_name, if any.

Walks _parent_of edges from instance_id toward the root and returns the first instance whose scope name matches. Used by descendant ops that need data from a higher scope (e.g. an operation-scope op reading its enclosing resource’s model).

Parameters:
  • instance_id (str) – Id whose ancestor to find.

  • scope_name (str) – Scope name of the wanted ancestor.

Return type:

object | None

Returns:

The ancestor instance, or None if no ancestor at that scope is registered.

children(parent_id, *, child_scope=None)[source]

Return child instances of parent_id.

Children come back in registration (config) order. When child_scope is given, only children in that scope are returned (requires scopes to be populated).

Parameters:
  • parent_id (str) – Parent instance id.

  • child_scope (str | None) – Optional scope-name filter.

Return type:

list[tuple[str, object]]

Returns:

List of (child_id, child_instance) pairs.

entries()[source]

Iterate stored entries as (instance_id, op_name, items).

Used by the assembler to walk the store and dispatch each item to the correct renderer.

Return type:

Iterator[tuple[str, str, list[object]]]

outputs_under(ancestor_id, output_type)[source]

Return every output_type output at or below ancestor_id.

Walks the store by path prefix, so output produced at any depth under ancestor_id surfaces — useful for ops that aggregate or mutate outputs from deeper scopes (e.g. auth adding dependencies to every handler under a resource).

Return type:

list[TypeVar(T)]

register_instance(instance_id, instance, *, parent=None)[source]

Remember the scope-instance object for instance_id.

Called by the engine before operations run at each scope instance. Renderers access these via ancestor_of() when they need a higher scope’s config.

Parameters:
  • instance_id (str) – Dot-path id.

  • instance (object) – The scope-instance config object.

  • parent (str | None) – Id of the enclosing scope instance. When given, children() will surface this instance under parent. Omit for the project root.

Return type:

None

scope_of(instance_id)[source]

Resolve the Scope an instance_id belongs to.

Return type:

Scope

Output

class GeneratedFile(path, content)[source]

Immutable final output – a path and its content.

path

Output path relative to the output directory.

content

File contents as a string.

write_files(files, out_dir)[source]

Write generated files to disk.

Each file’s path is joined with out_dir to determine the target path. Parent directories are created as needed. Existing files are always overwritten.

Parameters:
Return type:

int

Returns:

Number of files written.

Naming and imports

class Name(raw)[source]

Derives conventional identifiers from a base string.

Accepts either a PascalCase class name (e.g. "Article") or a snake_case identifier (e.g. "publish_article") and exposes the common derived forms used by code generators.

Examples:

model = Name("Article")
model.pascal              # "Article"
model.lower               # "article"
model.suffixed("Resource")  # "ArticleResource"

action = Name("publish_article")
action.pascal             # "PublishArticle"
action.slug               # "publish-article"
action.suffixed("Request")  # "PublishArticleRequest"
classmethod from_dotted(dotted_path)[source]

Create a Name from a dotted import path.

Parameters:

dotted_path (str) – A fully-qualified class path such as "myapp.models.Article".

Return type:

tuple[str, Name]

Returns:

A (module, Name) tuple, e.g. ("myapp.models", Name("Article")).

property lower: str

Fully lowercased form (for file/module names).

property pascal: str

PascalCase form of the name.

If the raw string contains no underscores and already starts with an uppercase letter it is returned as-is (assumed to already be PascalCase, e.g. "StockMovement" from a dotted import path).

property slug: str

Hyphenated slug form (for URL segments).

suffixed(suffix)[source]

PascalCase name with suffix appended.

Parameters:

suffix (str) – Class-name suffix, e.g. "CreateRequest".

Return type:

str

Returns:

Combined string, e.g. "ArticleCreateRequest".

prefix_import(prefix, *parts)[source]

Build a Python import path under prefix (which may be empty).

Parameters:
  • prefix (str) – Optional package prefix, e.g. "_generated".

  • *parts (str) – Module name segments to join with ..

Return type:

str

Returns:

A .-joined import path, with prefix prepended when non-empty.

split_dotted_class(dotted_path)[source]

Split a dotted import path into (module, class_name).

Parameters:

dotted_path (str) – A fully-qualified class path such as "myapp.models.Article".

Return type:

tuple[str, str]

Returns:

A (module, class_name) tuple, e.g. ("myapp.models", "Article").

Raises:

ValueError – If dotted_path contains fewer than two parts.

class ImportCollector(*others)[source]

Accumulates imports as (module, name) pairs.

A bare import is (module, None) (e.g. Python import uuid). A from-import is (module, name) (e.g. Python from datetime import datetime). Multiple calls for the same module are merged; duplicates are deduplicated.

Examples:

collector = ImportCollector()
collector.add("uuid")
collector.add_from("datetime", "datetime", "date")
collector.format("python")
# "import uuid\nfrom datetime import date, datetime\n"

Rendering is delegated to a language formatter looked up via the foundry.import_formatters entry-point group.

add(module)[source]

Register a bare <module> import.

Return type:

None

add_from(module, *names)[source]

Register an import of names from module.

Multiple calls with the same module are merged.

Return type:

None

property bare_modules: list[str]

Bare-imported modules (e.g. ["uuid"]).

format(language)[source]

Render the imports as a string in language’s syntax.

Raises:

KeyError – No formatter registered for language.

Return type:

str

property from_imports: dict[str, list[str]]

{module: [name, ...]} of from-imports, preserving order.

update(other)[source]

Merge imports from other into this collector.

Return type:

None

Jinja environment

create_jinja_env(*template_dirs)[source]

Create a Jinja2 environment for code generation.

The returned environment has trim_blocks and lstrip_blocks enabled so that block tags ({% if %}, {% for %}, etc.) do not add extra blank lines to the rendered output.

Parameters:

*template_dirs (Path) – One or more directories to search for templates. Earlier directories take priority.

Return type:

Environment

Returns:

A configured jinja2.Environment.

render_template(env, template_name, **context)[source]

Render template_name against context and return the raw result.

Every jinja call in foundry/kiln flows through this helper so whitespace policy lives at the call site, not hidden inside a render wrapper. Callers handle trimming themselves:

  • Inline code snippets typically want .strip().

  • Whole-file output wants .rstrip() + "\n".

  • Slot contributions that the outer template controls typically want the raw output, unmodified.

Parameters:
  • env (Environment) – The Jinja2 environment to use.

  • template_name (str) – Template path relative to the environment’s template directories.

  • **context (object) – Template context variables.

Return type:

str

Returns:

The rendered template, exactly as jinja produced it.

Stdlib reference

The following .libsonnet files ship inside the kiln package and are importable from any config file using the kiln/ prefix.

kiln/auth/jwt.libsonnet

Configures JWT authentication.

local auth = import 'kiln/auth/jwt.libsonnet';

auth.jwt({
  secret_env:            "JWT_SECRET",
  algorithm:             "HS256",
  token_url:             "/auth/token",
  exclude_paths:         ["/docs", "/openapi.json", "/health"],
  verify_credentials_fn: "myapp.auth.verify_credentials",
})

To supply a custom get_current_user dependency instead of the generated JWT flow, set get_current_user_fn to a dotted import path. In that case verify_credentials_fn is not required.

kiln/db/databases.libsonnet

Configures async PostgreSQL connections.

local db = import 'kiln/db/databases.libsonnet';

db.postgres("primary", {
  url_env:       "DATABASE_URL",
  default:       true,
  echo:          false,
  pool_size:     5,
  max_overflow:  10,
  pool_timeout:  30,
  pool_recycle:  -1,
  pool_pre_ping: true,
})

Resources that omit db_key use the database with default: true.