Référence manifest V1
Le manifest relie les tools à des handlers hôtes et peut activer explicitement des triggers. Il est fourni explicitement au runtime.
Dans un projet Touba, touba prepare peut générer ou vérifier le manifest à partir de l'AIR. Cela ne change pas le runtime : l'exécution avec tool demande toujours --manifest.
Le handler est lancé sans shell implicite et avec un environnement minimal. Pour
un handler JavaScript, touba prepare écrit donc le chemin absolu du Node
courant dans handler.command.
Forme minimale
{
"manifest_version": "touba-manifest-v1",
"bindings": {
"tool:examples.search/SearchDatasets": {
"handler": {
"kind": "process",
"command": "/absolute/path/to/node",
"args": ["handlers/search_datasets.handler.mjs"],
"cwd": "."
},
"grants": ["network"],
"effect_contract": { "kind": "none" },
"sandbox": {
"required": true
},
"timeout_ms": 5000,
"max_payload_bytes": 1048576
}
}
}
Champs
| Champ | Rôle |
|---|---|
manifest_version | Version du manifest |
effect_contract | Contrat d’effet explicite pour chaque binding |
bindings | Table explicite tool → binding |
triggers | Table explicite trigger → activation |
run_limits | Budgets d’autonomie applicables au run |
handler.kind | process |
handler.command | Exécutable lancé sans shell implicite |
handler.args | Arguments du process |
handler.cwd | Dossier de travail optionnel |
grants | Capabilities accordées explicitement |
sandbox | Isolation de plateforme exigée pour le process handler |
secrets | Handles de secrets accordés |
memories | Accès mémoire accordés |
timeout_ms | Timeout process |
max_payload_bytes | Limite de payload |
Contrat des effets
touba-manifest-v1 est le seul format admis. Chaque binding possède
exactement un contrat d'effet explicite :
"effect_contract": { "kind": "none" }
"effect_contract": {
"kind": "external_write",
"retry_mode": "idempotency_key"
}
Pour external_write, retry_mode vaut idempotency_key, reconcile ou
none. Il est interdit avec kind: none. Les champs et valeurs inconnus sont
refusés. Le runtime exige une portée d'effet et un journal durables avant de
lancer une écriture externe.
Seule une écriture externe peut déclarer la relation inverse suivante :
"effect_contract": {
"kind": "external_write",
"retry_mode": "idempotency_key",
"compensation": {
"entry_ref": "strategy:orders/CancelOrder"
}
}
compensation contient seulement entry_ref. La stratégie doit exister dans
l'AIR exact et se fermer sur un unique appel de tool externe suivi directement
d'un terminal. L'inverse ne peut pas déclarer sa propre compensation.
Secrets
Les secrets sont des handles. Le manifest ne contient pas les valeurs.
"secrets": ["OPENAI_API_KEY"]
Scopes secrets par agent
{
"agent_secret_scopes": {
"agent:examples/Researcher": ["OPENAI_API_KEY"]
}
}
Si le handle est absent du scope de l'agent actif, le runtime refuse avant handler.
Mémoires
"memories": [
{ "ref": "memory:examples/ProjectKnowledge", "access": "read" }
]
Le runtime croise AIR, manifest et owner actif avant dispatch.
Isolation des handlers
Un binding peut exiger une isolation de plateforme :
"sandbox": {
"required": true,
"profile": "default"
}
Lorsque sandbox.required: true, macOS utilise sandbox-exec ; Linux x64
combine bubblewrap, seccomp et le lanceur natif touba-sandbox avec Landlock
ABI 3 minimum. Les données hors périmètre, écritures, descendants et connexions
réseau sont refusés par défaut. Les essais natifs Linux couvrent Ubuntu 24.04,
Node et Python, y compris l'arrêt des descendants au timeout.
Sous Linux, bubblewrap doit être installé et les user namespaces utilisables.
Un hôte Ubuntu protégé par AppArmor peut nécessiter un profil administrateur
limité à ce binaire, sans désactiver les protections globales. Un chemin
write_paths doit déjà exister : utilisez un répertoire de sortie dédié pour
créer des fichiers. Écrire n'accorde pas la lecture. Les sockets Unix exacts
exigent Landlock ABI 9 ; une politique non applicable est refusée avant lancement.
La sonde exécute une commande sous confinement pour vérifier les prérequis.
Le backend Windows est encore en qualification pour la V1, notamment pour les
handlers Python asynchrones sans autorisation réseau. Il n'est pas annoncé
comme disponible dans une distribution finalisée. Un confinement indisponible
ou une politique non applicable bloque le lancement, sans exécution directe
de secours. Sans sandbox obligatoire, les handlers restent du code hôte de confiance.
Le code HandlerSandboxUnsupportedPolicy désigne une politique non prise en
charge par le backend sélectionné.
Les chemins sont relatifs au cwd du handler ou absolus. L'interpréteur
doit avoir un chemin absolu ; l'alias node désigne le Node de Touba.
| Champ | Grant requis | Portée |
|---|---|---|
code_paths | code choisi par l'hôte | fichiers individuels existants de code/bibliothèque |
read_paths | filesystem_read | fichiers ou sous-répertoires |
write_paths | filesystem_write | fichiers ou sous-répertoires |
local_sockets | network_local | chemins exacts de sockets Unix clients |
process autorise des enfants qui héritent de la politique. network
ouvre le réseau ; network_local seul n'ouvre pas le réseau IP.
Un service autorisé peut lui-même être très privilégié : un socket Docker
n'est pas équivalent à une connexion limitée à une base.
La base technique comprend le code exécutable, les bibliothèques chargées par Node, les bibliothèques système, les métadonnées de chemins et les configurations OpenSSL usuelles. Elle n'ouvre pas globalement le projet, le dossier personnel ni les fichiers temporaires. Les chemins explicitement accordés restent à auditer ; la sandbox ne prouve pas la sûreté du handler.
Contraintes de payload
Un binding peut déclarer des contraintes de payload appliquées après le schéma AIR et avant le handler pour l’input, puis avant publication de résultat pour l’output.
"payload_constraints": {
"input": {
"request.query": {
"non_empty": true,
"max_length": 120
},
"request.rows": {
"min": 1,
"max": 50
},
"request.mode": {
"allowed_values": ["dry_run", "review", "execute"]
},
"request.recipients": {
"min_items": 1,
"max_items": 5
}
},
"output": {
"$": {
"max_items": 20
}
}
}
Les opérateurs disponibles sont bornés :
non_emptyetmax_lengthpourText;minetmaxpourIntouFloat;allowed_valuespour scalaires JSON portables ;min_itemsetmax_itemspourList<T>.
Un refus produit ToolPayloadConstraintViolation sans afficher la valeur brute
du payload.
Budgets de run
Le manifest peut restreindre les budgets d’autonomie :
{
"manifest_version": "touba-manifest-v1",
"run_limits": {
"max_steps": 100,
"max_tool_calls": 20,
"max_agent_invocations": 5,
"max_provider_calls": 4
},
"bindings": {}
}
run_limits concerne le run Touba. Les champs timeout_ms et max_payload_bytes dans un binding concernent le process handler.
Le manifest peut restreindre une limite AIR. Il ne peut pas l’élargir silencieusement.
Triggers
Un trigger reste inactif tant que le manifest ne l’active pas.
{
"manifest_version": "touba-manifest-v1",
"triggers": {
"trigger:examples.daily_research/DailyResearchSchedule": {
"enabled": true,
"source": {
"kind": "schedule"
},
"limits": {
"max_runs_per_day": 1,
"timeout_ms": 30000
}
}
}
}
Le runtime refuse si la source événementielle ne correspond pas ou si le manifest tente d’élargir une limite déclarée dans l’AIR.
Relation avec le lock supply chain
Le manifest reste l’autorité runtime : il accorde le handler, les grants, les secrets, les mémoires, les limites et les triggers.
Un lock supply chain ne donne aucun droit supplémentaire. Il vérifie seulement que
l’AIR, le manifest, les handlers, la metadata SDK et l’identité déclarée
handler_package correspondent aux artefacts attendus. Avec l’extension
artefacts de dépendances (SC-2), le même lock peut aussi vérifier des fichiers de paquet handler et des
artefacts de dépendances déclarés explicitement. Avec l’extension provenance et revue (SC-3),
il peut aussi porter une provenance et une revue déclarées.
touba supply-chain validate \
--lock touba.lock.json \
--air program.air.json \
--manifest touba.manifest.json
Si le manifest change après la création du lock, la validation doit signaler une dérive. Le runtime continue toutefois à appliquer le manifest fourni à l’exécution.
Une revue de lock approuvée n’accorde aucun grant, secret, scope ou trigger. Elle documente une discipline de revue.
Frontières du manifest
grantsetsandboxsont deux contrôles distincts- une sandbox requise dépend du mécanisme disponible sur la plateforme
- Le manifest n'est pas un système de permissions complet
- Aucun handler n'est découvert automatiquement
- Aucun secret n'est lu implicitement
- Un manifest généré reste un artefact à relire, pas une autorisation invisible
- Aucun trigger n'est activé automatiquement sans entrée manifest explicite