Ingestion de données WAP avec Bauplan

VérifiéPrudence

Ingérez des données depuis S3 vers bauplan en utilisant le modèle Write-Audit-Publish pour un chargement sécurisé avec contrôles de qualité.

Spar Skills Guide Bot
Data & IAIntermédiaire
29/07/2026
Claude CodeCodex
#data-ingestion#s3#write-audit-publish#data-quality#bauplan

Recommandé pour

Synthèse automatique

Génère un script Python utilisant le SDK bauplan pour ingérer en toute sécurité des données depuis S3 selon le schéma Write-Audit-Publish, via une branche temporaire.

Points forts

  • Applique une séparation claire Write/Audit/Publish sur une branche éphémère, jamais sur main
  • Utilise les fusions atomiques multi-tables de merge_branch pour un chargement tout-ou-rien
  • Expose des paramètres explicites pour le comportement en cas de succès (inspect/merge) et d'échec (keep/delete)
  • Fournit un template de script complet avec assertions de sécurité (branche/table inexistante)

Limites

  • Le SKILL.md fourni est tronqué : le template s'arrête au milieu de la phase Audit
  • Spécifique à bauplan et au SDK Python ; ne couvre pas d'autres moteurs ou l'usage en CLI
  • Suppose une source S3 et une inférence de schéma automatique, sans gestion détaillée des transformations ou schémas explicites
Quand l'utiliser

À utiliser lorsqu'il faut charger des fichiers parquet/csv/jsonl depuis S3 dans bauplan de manière sûre avec des contrôles qualité avant publication.

Quand l'éviter

À éviter pour des écritures directes sur main, des sources non-S3, ou des workflows hors de l'écosystème bauplan.

Analyse de sécurité

Prudence
Score qualité85/100

The skill uses the bauplan SDK to interact with a remote data platform, including creating branches, importing data from S3, and optionally merging to main. These are legitimate operations but involve network access and potential modification of production data. The main concern is the unsanitized f-string SQL query, which is a minor injection risk. No destructive or exfiltrating instructions are present.

Points d'attention
  • •Template builds SQL query using f-string with user-provided table name and namespace, which could allow SQL injection if untrusted input is used.
  • •The script can merge changes to the main branch and delete branches if the user selects those options, potentially modifying production data.
  • •The skill declares Bash as an allowed tool but instructs to avoid CLI commands; no dangerous shell commands are present.
Comment cette analyse est faite

Exemples

Load parquet files from S3
Ingest s3://my-bucket/events/*.parquet into a table called events_raw in bauplan using the WAP pattern, keeping the branch for inspection on success.
Safe ingestion with auto-merge
Use wap-ingestion to load s3://data-lake/orders/*.jsonl into namespace analytics as orders, and automatically merge to main on success.
Multi-table safe load with failure cleanup
Write a WAP script that ingests sales and returns parquet files from S3 into bauplan, deleting the branch on failure but keeping it open on success.

name: wap-ingestion description: "Ingest data from S3 into bauplan using the Write-Audit-Publish pattern for safe data loading. Use when loading new data from S3, performing safe data ingestion, or when the user mentions WAP, data ingestion, importing parquet/csv/jsonl files, or needs to safely load data with quality checks." allowed-tools:

  • Read
  • Write
  • Glob
  • Grep
  • Bash
  • WebFetch(domain:docs.bauplanlabs.com)

Write-Audit-Publish (WAP) Pattern

Implement WAP by writing a Python script using the bauplan SDK. Do NOT use CLI commands.

The three steps: Write (ingest to temp branch) → Audit (quality checks) → Publish (merge to main)

Branch safety: All operations happen on a temporary branch, NEVER on main. By default, branches are kept open for inspection after success or failure.

Atomic multi-table operations: merge_branch is atomic. You can create or modify multiple tables on a branch, and when you merge, either all changes apply to main or none do. This enables safe multi-table ingestion workflows.

Required User Input

Before writing the WAP script, you MUST ask the user for the following parameters:

  1. S3 path (required): The S3 URI pattern for the source data (e.g., s3://bucket/path/*.parquet)
  2. Table name (required): The name for the target table
  3. On success behavior (optional):
    • inspect (default): Keep the branch open for user inspection before merging
    • merge: Automatically merge to main and delete the branch
  4. On failure behavior (optional):
    • keep (default): Leave the branch open for inspection/debugging
    • delete: Delete the failed branch

WAP Script Template

This is the complete template for WAP:

"""
WAP (Write-Audit-Publish) Template for bauplan data ingestion.

Usage:
    python wap_template.py

Or import and call wap_ingest() with your parameters.
"""
import bauplan
from datetime import datetime


def wap_ingest(
    table_name: str,
    s3_path: str,
    namespace: str = "bauplan",
    on_success: str = "inspect",  # "inspect" (default) or "merge"
    on_failure: str = "keep",  # "keep" (default) or "delete"
):
    """
    Write-Audit-Publish flow for safe data ingestion.

    Args:
        table_name: Target table name
        s3_path: S3 URI pattern (e.g., 's3://bucket/path/*.parquet')
        namespace: Target namespace (default: 'bauplan')
        on_success: "inspect" to keep branch for review, "merge" to auto-merge
        on_failure: "keep" to preserve branch for debugging, "delete" to cleanup

    Returns:
        tuple: (branch_name, success)
    """
    client = bauplan.Client()

    # Generate unique branch name using username
    info = client.info()
    username = info.user.username
    branch_name = f"{username}.wap_{table_name}_{int(datetime.now().timestamp())}"

    success = False
    try:
        # === WRITE PHASE ===
        # 1. Create temporary branch from main (must not exist)
        assert not client.has_branch(branch_name), (
            f"Branch '{branch_name}' already exists - this should be an ephemeral branch"
        )
        client.create_branch(branch_name, from_ref="main")

        # 2. Verify table doesn't exist on branch before creating
        assert not client.has_table(
            table=table_name, ref=branch_name, namespace=namespace
        ), (
            f"Table '{namespace}.{table_name}' already exists on branch - refusing to overwrite"
        )

        # 3. Create table (schema inferred from S3 files)
        client.create_table(
            table=table_name,
            search_uri=s3_path,
            namespace=namespace,
            branch=branch_name,
        )

        # 4. Import data into table
        client.import_data(
            table=table_name,
            search_uri=s3_path,
            namespace=namespace,
            branch=branch_name,
        )

        # === AUDIT PHASE ===
        # 5. Run quality check: verify data was imported
        fq_table = f"{namespace}.{table_name}"
        result = client.query(
            query=f"SELECT COUNT(*) as row_count FROM {fq_table}", ref=branch_name
        )
        row_count = result.column("row_count")[0].as_py()
        assert row_count > 0, "No data was imported"
        print(f"Imported {row_count} rows")

        success = True

        # === PUBLISH PHASE ===
        if on_success == "merge":
            # 6. Merge to main and cleanup
            client.merge_branch(source_ref=branch_name, into_branch="main")
            print(f"Successfully published {table_name} to main")
            client.delete_branch(branch_name)
            print(f"Cleaned up branch: {branch_name}")
        else:
            # Keep branch for inspection
            print(
                f"WAP completed successfully. Branch '{branch_name}' ready for inspection."
            )
            print(
                f"To merge manually: client.merge_branch(source_ref='{branch_name}', into_branch='main')"
            )

    except Exception as e:
        print(f"WAP failed: {e}")
        if on_failure == "delete":
            if client.has_branch(branch_name):
                client.delete_branch(branch_name)
                print(f"Cleaned up failed branch: {branch_name}")
        else:
            print(f"Branch '{branch_name}' preserved for inspection/debugging.")
        raise

    return branch_name, success


if __name__ == "__main__":
    # Example: customize these parameters
    branch, success = wap_ingest(
        table_name="my_table",
        s3_path="s3://my-bucket/data/*.parquet",
        namespace="bauplan",
        on_success="inspect",
        on_failure="keep",
    )

Minimal usage:

from wap_template import wap_ingest

branch, success = wap_ingest(
    table_name="orders",
    s3_path="s3://my-bucket/data/*.parquet",
    namespace="bauplan",
    on_success="inspect",  # or "merge"
    on_failure="keep"      # or "delete"
)

Key SDK Methods

| Method | Description | | ---------------------------------------------- | ----------------------------------------------------- | | bauplan.Client() | Initialize the bauplan client | | client.info() | Get client info; access username via .user.username | | client.create_branch(name, from_ref="main") | Create a new branch from specified ref | | client.has_branch(name) | Check if branch exists | | client.delete_branch(name) | Delete a branch | | client.create_table(table, search_uri, ...) | Create table with schema inferred from S3 | | client.import_data(table, search_uri, ...) | Import data from S3 into table | | client.query(query, ref) | Run SQL query, returns PyArrow Table | | client.merge_branch(source_ref, into_branch) | Merge branch into target | | client.has_table(table, ref, namespace) | Check if table exists on branch |

SDK Reference: For detailed method signatures, check https://docs.bauplanlabs.com/reference/bauplan

Workflow Checklist

Copy and track progress:

WAP Progress:

  • [ ] Ask user for: S3 path, table name, on_success, on_failure
  • [ ] Write script using wap_template.py
  • [ ] Run script: python wap_script.py
  • [ ] Verify output shows row count > 0
  • [ ] If on_success="inspect": confirm branch ready for review
  • [ ] If on_success="merge": confirm merge to main succeeded

Example Output

Successful run (on_success="inspect"):

$ python wap_script.py
Imported 15234 rows
WAP completed successfully. Branch 'alice.wap_orders_1704067200' ready for inspection.
To merge manually: client.merge_branch(source_ref='alice.wap_orders_1704067200', into_branch='main')

Successful run (on_success="merge"):

$ python wap_script.py
Imported 15234 rows
Successfully published orders to main
Cleaned up branch: alice.wap_orders_1704067200

Failed run (on_failure="keep"):

$ python wap_script.py
WAP failed: No data was imported
Branch 'alice.wap_orders_1704067200' preserved for inspection/debugging.

WAP on Existing Tables

To append data to an existing table, skip create_table and only call import_data:

# Table already exists on main - just import new data
client.import_data(
    table=table_name,
    search_uri=s3_path,
    namespace=namespace,
    branch=branch_name
)

This appends rows to the existing table schema. The audit and publish phases remain the same: the new rows are automatically sandboxed on the branch until merged.

CLI Merge After Inspection

When on_success="inspect" (default), the branch is left open for user review. If the user asks to merge after inspecting the data, use the CLI:

# 1. Checkout to main first (required before merging)
bauplan checkout main

# 2. Merge the WAP branch into main
bauplan branch merge <username>.wap_<table_name>_<timestamp>

# 3. Optionally delete the branch after successful merge
bauplan branch rm <username>.wap_<table_name>_<timestamp>

Note: You must be on main to run bauplan branch merge. The branch name is printed by the WAP script upon completion.

Du fichier au premier essai

Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.

Consulter la source et ses fichiers annexes

Ce téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.

1. Télécharger le fichier

Télécharger SKILL.md

Depuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.

Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.

mkdir -p '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/wap-data-ingestion-with-bauplan-ms5lrgik/download' --output '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md.part' && mv '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md.part' '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md'

2. Vérifier les prérequis

Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.

Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.

Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.

3. Charger la skill

Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.

Claude Code
test -f '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md' && test -s '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/wap-ingestion' && cp -R '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik' '.claude/skills/wap-ingestion'

Codex
test -f '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md' && test -s '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/wap-ingestion' && cp -R '.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik' '.agents/skills/wap-ingestion'

OpenSkills

OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.

Installation officielle d’OpenSkills
openskills install './.skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik'

openskills read 'wap-data-ingestion-with-bauplan-ms5lrgik'

La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.

Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.

openskills sync

Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.

4. Faire un premier essai

Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :

Lis .skill-downloads/wap-data-ingestion-with-bauplan-ms5lrgik/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.

Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.

Skills similaires