Multi-Module Imports
Imports explicitly connect several Touba modules inside a local project.
Touba covers these imports within one project:
type;- non-sensitive
define; - pure
function; - local
tool; skill;strategy;agentwith explicitcallable_by;- logical
memorywith explicit scopes.
Imports grant no execution authority. They add no grant, secret, memory scope, handler, or manifest.
Imported fields and function signatures are resolved before expression typing.
You can read request.query, reuse a result in an expression and supply named
arguments without workaround annotations. Types remain nominal: declarations
with the same name in different modules are not interchangeable.
With touba prepare, keep sources under src/<module/name>.tb and declare
the packages used by the project. Missing, incompatible or unexported imports
are errors; they never create implicit contracts.
Syntax
Shape:
import type Name from module.name
import define Name from module.name
import function Name from module.name
import tool Name from module.name
import skill Name from module.name
import strategy Name from module.name
import agent Name from module.name
import memory Name from module.name
Imports are placed after module and before the other declarations in the file.
Example:
module examples.search
import type SearchRequest from examples.common
import define DefaultRows from examples.common
import function NormalizeQuery from examples.common
Project Example
Pure Imports
Shared module:
module examples.common
type SearchRequest
query is Text
rows is Int
define DefaultRows as Int = 5
function NormalizeQuery
takes query as Text
gives Text
do
give query
Importing module:
module examples.search
import type SearchRequest from examples.common
import define DefaultRows from examples.common
import function NormalizeQuery from examples.common
strategy RunSearch
gives Text
do
show
with message as "search project ready"
give "done"
Command:
touba prepare --mode write
Expected result:
- the prepared project AIR contains the declared imports;
- imports are resolved by project assembly;
- no manifest or handler is created when the project declares no
tool; touba inspectcan display imports and their status;- the VS Code extension can display hover, symbols, navigation, and diagnostics related to imports.
Local Tool Import
Declaring module:
module examples.data_tools
type DatasetSearchRequest
query is Text
rows is Int
type DatasetSearchResult
title is Text
url is Text
tool SearchDatasets
takes request as DatasetSearchRequest
gives DatasetSearchResult
requires network
Importing module:
module examples.research_app
import type DatasetSearchRequest from examples.data_tools
import type DatasetSearchResult from examples.data_tools
import tool SearchDatasets from examples.data_tools
skill BuildDatasetBrief
takes request as DatasetSearchRequest
gives DatasetSearchResult
uses SearchDatasets
do
SearchDatasets
with request as request
into result
give result
After touba prepare --mode write:
- the prepared AIR for the importing module contains the resolved
toolimport; - the tool reference remains
tool:examples.data_tools/SearchDatasets; - the manifest binding targets this canonical reference;
- the handler stub is attached to the declaring module, for example
handlers/examples/data_tools/search_datasets.handler.mjs; - the import creates no implicit grant:
requires networkmust still be granted by the manifest.
Skill and Strategy Import
Shared module:
module examples.shared_flow
skill NormalizeTopic
takes topic as Text
gives Text
do
bind normalized as Text = "topic:" ++ topic
give normalized
strategy SharedTopicRun
takes topic as Text
gives Text
uses NormalizeTopic
do
NormalizeTopic
with topic as topic
into normalized
give normalized
Importing module:
module examples.flow_app
import skill NormalizeTopic from examples.shared_flow
import strategy SharedTopicRun from examples.shared_flow
strategy RunImportedSkill
takes topic as Text
gives Text
uses NormalizeTopic
do
NormalizeTopic
with topic as topic
into normalized
give normalized
Expected result:
- the imported skill keeps reference
skill:examples.shared_flow/NormalizeTopic; - the imported strategy keeps reference
strategy:examples.shared_flow/SharedTopicRun; - the prepared AIR includes the required graphs;
- no handler or manifest is created if the flow calls no
tool.
Agent Import
The compiler resolves the agent's explicit signature from its source module.
The importer uses the same named with inputs and into output as a local call.
The agent remains closed by default: its module names authorized callers.
module examples.agent_pool
function PrepareReview
description "Return the supplied review text."
takes brief as Text
gives Text
do
give brief
agent Reviewer
takes brief as Text
gives Text
responsibility "Return the review through the declared capability."
uses PrepareReview
callable_by strategy examples.agent_app.RunReview
module examples.agent_app
import agent Reviewer from examples.agent_pool
strategy RunReview
takes brief as Text
gives Text
uses Reviewer
do
Reviewer
with brief as brief
into reviewed
give reviewed
examples.agent_app.RunReview is a qualified caller, not module-wide authority.
Compile from the project root with both modules present. A compatible signature
does not bypass callable_by; imported types retain their module identities.
A typed imported agent can also be a parallel target in an authorized strategy.
Logical Memory Import
An imported memory remains a logical resource. It does not create a backend and grants no access by itself.
module examples.shared_memory
memory ProjectKnowledge
module examples.memory_tools
import memory ProjectKnowledge from examples.shared_memory
type KnowledgeQuery
query is Text
type KnowledgeResult
summary is Text
tool ReadKnowledge
takes query as KnowledgeQuery
gives KnowledgeResult
requires memory_read
uses memory ProjectKnowledge read
module examples.memory_app
import type KnowledgeQuery from examples.memory_tools
import type KnowledgeResult from examples.memory_tools
import memory ProjectKnowledge from examples.shared_memory
import tool ReadKnowledge from examples.memory_tools
skill BuildKnowledgeAnswer
takes query as KnowledgeQuery
gives KnowledgeResult
uses ReadKnowledge
memory ProjectKnowledge read
do
ReadKnowledge
with query as query
into result
give result
Expected result:
- the memory keeps reference
memory:examples.shared_memory/ProjectKnowledge; - the access tool keeps
uses memory ... read; - the skill must declare
memory ProjectKnowledge read; - the manifest must grant the binding, grants, and any handler secrets;
- without an owner-side scope, the project is refused.
Inspection
After prepare, inspect the produced AIR:
touba inspect .touba/air/examples/search.air.json
Expected output, in substance:
imports=3 resolved=3 unresolved=0
import type SearchRequest from examples.common -> type:examples.common/SearchRequest
import define DefaultRows from examples.common -> define:examples.common/DefaultRows
import function NormalizeQuery from examples.common -> function:examples.common/NormalizeQuery
The exact detail depends on the output mode, but the important information is:
- import kind;
- imported name;
- source module;
- canonical AIR reference;
- resolved or refused status.
Important Refusals
Touba refuses imports that would open implicit authority or name ambiguity.
Refusal examples:
import function NormalizeQuery from examples.common
function NormalizeQuery
takes query as Text
gives Text
do
give query
Expected refusal: name collision between import and local declaration.
import * from examples.common
Expected refusal: wildcard imports are not accepted.
An imported agent without a compatible callable_by rule is also refused. An imported tool without an expected grant, secret, or binding is refused by the runtime before the handler.
Import Contract
Pure imports (IM-1) cover the pure part of multi-module sharing: type, non-sensitive define, and pure function. Effectful imports (IM-2) add local effectful components: tool, skill, strategy, agent, and memory, without moving runtime authority.
The import contract is explicit by design:
- no external packages or registry resolution in this local-project mechanism;
- no aliases, wildcards, or re-exports;
- no implicit grant, secret, memory scope, agent caller, manifest, or handler;
- no runtime-side import resolution;
- no memory backend inferred from
memory; - no module-wide authorization.
These boundaries keep imports from silently adding grants, secrets, memory scopes, agent callers, packages, or runtime entry points. Packages and the registry preserve the same rule: make a component available without granting execution authority.
Imported agent and strategy signatures are resolved before typed calls, including
parallel targets. Import enums with import type; lists, records and optionals
retain the nominal identity of their module-defined types. Source modules must
be available to the compiler: imports never discover handlers or grant authority.