Lavori da terminale. Apri una sessione, cominci a installare, configurare, modificare. A un certo punto chiedi aiuto a un’IA — copi l’output, incolli la risposta, esegui il comando suggerito. Funziona. Vai avanti.

Tre settimane dopo non ricordi cosa hai fatto, perché lo hai fatto, e soprattutto non riesci a riprodurre l’ambiente da zero.

Il terminale è il libro di ciò che avviene. Il problema è che non è di carta.

Questo script nasce da quella frustrazione. L’obiettivo è semplice: registrare tutto quello che succede in una sessione di lavoro, pulire il log da qualsiasi cosa sensibile, e produrre un file che puoi incollare direttamente a un’IA senza rischiare di portarti dietro token, password o chiavi private.


L’idea ha senso?#

Il problema che risolve è reale: le sessioni di lavoro con un’IA sono per natura iterative e caotiche, e la storia di come si arriva a un risultato si perde quasi sempre. Nessuno strumento mainstream affronta esattamente questo caso d’uso — la maggior parte dei tool di logging è pensata per ambienti di produzione, non per sessioni di sviluppo/configurazione personale.

Le alternative esistono, ma non fanno la stessa cosa:

  • script — il comando Unix usato internamente da questo script. Funziona, ma produce log grezzi illeggibili e non filtra niente.
  • asciinema — registra sessioni in formato riproducibile. Bellissimo per demo, inutile qui — l’output è pensato per essere riprodotto, non letto.
  • bash-preexec + hook personalizzati — pipeline simili esistono, ma richiedono molto più setup e non sono pensate per l’integrazione con IA.
  • atuin — history shell avanzata con sync e ricerca. Risolve il problema della history, non quello del log completo con output.

Nessuna di queste fa esattamente questo: registrare + pulire + oscurare + produrre un file pronto per IA. La combinazione è originale.


Come funziona#

Lo script aggiunge tre funzioni al tuo ambiente bash: logbook_start, logbook_stop e logbook_status.

logbook_start nome_sessione genera una cartella unica con timestamp, fa uno snapshot dei pacchetti installati, e avvia la registrazione. Il nome della sessione attiva viene salvato in ~/.logbook_session — questo è il meccanismo di recovery: se il terminale si chiude prima dello stop, al prossimo avvio lo script trova il file, ti avvisa, e ti chiede cosa fare.

logbook_stop esegue la pulizia in ordine preciso. Il primo passaggio oscura i dati sensibili direttamente sul log grezzo, prima di qualsiasi altra operazione — così anche un comando con password digitata per errore viene neutralizzato prima che il file venga letto. Poi rimuove le sequenze ANSI, fa un secondo passaggio di oscuramento sul log pulito come doppia sicurezza, genera l’hash di integrità ed elimina tutti i file intermedi.

logbook_status mostra la sessione attiva e la dimensione del log corrente — utile per sessioni lunghe.


Lo script completo#

Da aggiungere al tuo ~/.bashrc o ~/.bash_profile:

# ===== LOGBOOK – SESSIONE TERMINALE =====

# History sicura
shopt -s histappend
export PROMPT_COMMAND='history -a; history -n; history -w'
export HISTCONTROL=ignoreboth
export HISTFILESIZE=100000
export HISTSIZE=100000
export HISTIGNORE="*sudo*:*password*:*secret*"

# File di stato sessione attiva
LOGBOOK_STATE="$HOME/.logbook_session"

# Oscura dati sensibili da un file — usata sia sul raw che sul log finale
_logbook_redact() {
    local input="$1"
    local output="$2"
    sed -E \
        -e 's/(password|passwd|pwd)[= :]+[^ ]+/\1=REDACTED/gi' \
        -e 's/(token|access_token)[= :]+[^ ]+/\1=REDACTED/gi' \
        -e 's/(apikey|api_key|api-key)[= :]+[^ ]+/\1=REDACTED/gi' \
        -e 's/(Authorization: Bearer )[A-Za-z0-9\._-]+/\1REDACTED/gi' \
        -e 's/ghp_[A-Za-z0-9]+/REDACTED_GITHUB_TOKEN/gi' \
        -e 's/-----BEGIN PRIVATE KEY-----/REDACTED_PRIVATE_KEY/gi' \
        "$input" > "$output"
}

# Avvio sessione
logbook_start() {
    if [ -z "$1" ]; then
        echo "Uso: logbook_start nome_sessione"
        return 1
    fi

    # Controlla se esiste una sessione precedente non chiusa
    if [ -f "$LOGBOOK_STATE" ]; then
        local prev_dir
        prev_dir=$(cat "$LOGBOOK_STATE")
        echo ""
        echo "⚠️  ATTENZIONE: trovata una sessione precedente non chiusa."
        echo "   Cartella: $prev_dir"
        echo ""
        echo "   Cosa vuoi fare?"
        echo "   [1] Chiudi quella sessione e avvia questa"
        echo "   [2] Abbandona quella sessione ed elimina i log grezzi"
        echo "   [3] Annulla"
        echo ""
        read -rp "Scelta [1/2/3]: " choice
        case "$choice" in
            1)
                echo "Chiusura sessione precedente..."
                AUDIT_DIR="$prev_dir" logbook_stop
                ;;
            2)
                echo "Eliminazione log grezzi della sessione precedente..."
                rm -f "$prev_dir/full_raw.log" "$prev_dir/clean.log" "$prev_dir/clean_no_ansi.log"
                rm -f "$LOGBOOK_STATE"
                echo "Fatto."
                ;;
            3)
                echo "Operazione annullata."
                return 0
                ;;
            *)
                echo "Scelta non valida. Operazione annullata."
                return 1
                ;;
        esac
    fi

    # ID unico per terminale + timestamp
    export AUDIT_NAME="$(date +%F_%H%M%S)_$1"
    export AUDIT_DIR="$HOME/terminal_audit/$AUDIT_NAME"
    mkdir -p "$AUDIT_DIR"

    # Salva il path della sessione attiva per recovery
    echo "$AUDIT_DIR" > "$LOGBOOK_STATE"

    # Snapshot pacchetti prima della sessione
    dpkg --get-selections > "$AUDIT_DIR/packages_before.txt"

    echo ""
    echo "📋 Logbook avviato: $AUDIT_NAME"
    echo "   Per chiudere la sessione: logbook_stop"
    echo ""

    script -q -f "$AUDIT_DIR/full_raw.log"
}

# Stop sessione
logbook_stop() {
    if [ -z "$AUDIT_DIR" ]; then
        if [ -f "$LOGBOOK_STATE" ]; then
            export AUDIT_DIR=$(cat "$LOGBOOK_STATE")
            echo "Recovery: ripreso da $AUDIT_DIR"
        else
            echo "Nessuna sessione logbook attiva trovata."
            return 1
        fi
    fi

    if [ ! -d "$AUDIT_DIR" ]; then
        echo "Cartella sessione non trovata: $AUDIT_DIR"
        return 1
    fi

    echo "Elaborazione sessione in corso..."

    # STEP 1: oscura i dati sensibili dal raw log prima di tutto
    if [ -f "$AUDIT_DIR/full_raw.log" ]; then
        _logbook_redact "$AUDIT_DIR/full_raw.log" "$AUDIT_DIR/full_raw_redacted.log"
        mv "$AUDIT_DIR/full_raw_redacted.log" "$AUDIT_DIR/full_raw.log"
    fi

    # STEP 2: pulizia ANSI/sequenze terminale
    col -b < "$AUDIT_DIR/full_raw.log" > "$AUDIT_DIR/clean.log"
    sed -r "s/\x1B(\[[0-9;]*[mK]|\]0;.*\x07)//g" "$AUDIT_DIR/clean.log" > "$AUDIT_DIR/clean_no_ansi.log"

    # STEP 3: comandi della sessione
    history | sed 's/^ *[0-9]\+ *//' > "$AUDIT_DIR/commands.log"

    # STEP 4: snapshot pacchetti dopo sessione
    dpkg --get-selections > "$AUDIT_DIR/packages_after.txt"
    diff "$AUDIT_DIR/packages_before.txt" "$AUDIT_DIR/packages_after.txt" > "$AUDIT_DIR/package_changes.diff"

    # STEP 5: secondo passaggio redact sul log pulito
    _logbook_redact "$AUDIT_DIR/clean_no_ansi.log" "$AUDIT_DIR/safe_for_ai_clean.log"

    # STEP 6: hash di integrità
    sha256sum "$AUDIT_DIR/safe_for_ai_clean.log" > "$AUDIT_DIR/integrity.sha256"

    # STEP 7: elimina tutti i log intermedi
    rm -f "$AUDIT_DIR/full_raw.log" "$AUDIT_DIR/clean.log" "$AUDIT_DIR/clean_no_ansi.log"

    # STEP 8: rimuove il file di stato sessione
    rm -f "$LOGBOOK_STATE"

    echo ""
    echo "✅ Logbook chiuso."
    echo "   Cartella: $AUDIT_DIR"
    echo "   Pronto per IA: $AUDIT_DIR/safe_for_ai_clean.log"
    echo ""

    unset AUDIT_DIR
    unset AUDIT_NAME
}

# Stato sessione corrente
logbook_status() {
    if [ -f "$LOGBOOK_STATE" ]; then
        local session_dir
        session_dir=$(cat "$LOGBOOK_STATE")
        echo "Sessione attiva: $session_dir"
        if [ -f "$session_dir/full_raw.log" ]; then
            local size
            size=$(du -h "$session_dir/full_raw.log" | cut -f1)
            echo "Dimensione log corrente: $size"
        fi
    else
        echo "Nessuna sessione logbook attiva."
    fi
}

Come si usa#

# Inizio sessione
logbook_start configurazione-hugo

# ... lavori, installi, configuri, sbagli, correggi ...

# Verifica stato (opzionale)
logbook_status

# Fine sessione
logbook_stop

Al termine trovi tutto in ~/terminal_audit/2026-02-27_143022_configurazione-hugo/:

commands.log              # Comandi eseguiti nella sessione
packages_before.txt       # Pacchetti installati prima
packages_after.txt        # Pacchetti installati dopo
package_changes.diff      # Cosa è cambiato
safe_for_ai_clean.log     # Log pulito, pronto da incollare
integrity.sha256          # Hash del log finale

Cosa viene oscurato#

PatternSostituito con
password=, passwd:, pwd =REDACTED
token=, access_token:REDACTED
apikey=, api_key=, api-key=REDACTED
Authorization: Bearer ...Authorization: Bearer REDACTED
Token GitHub (ghp_...)REDACTED_GITHUB_TOKEN
Intestazione chiave privataREDACTED_PRIVATE_KEY

Il filtro viene applicato due volte: una sul log grezzo appena chiusa la sessione, una sul log pulito prima di generare il file finale. Se un comando sensibile è finito nel log per errore, viene neutralizzato prima che qualsiasi altro processo lo legga.


Lavorare bene durante una sessione logbook#

Il log che il logbook produce è tanto più leggibile quanto meno usi editor interattivi. Nano, Vim e simili generano sequenze di controllo che il filtro ANSI non riesce a pulire completamente — il risultato nel log è rumore illeggibile.

La regola pratica è semplice: tutto quello che puoi fare da riga di comando, fallo da riga di comando. Tre strumenti coprono il 90% dei casi.

cat — scrivere un file da zero#

cat > ~/nomefile.txt
riga uno
riga due
riga tre

Premi Ctrl+D per chiudere. Nel log appare esattamente quello che hai scritto, pulito e leggibile.

heredoc — scrivere file con struttura in un colpo solo#

cat > ~/nomefile.txt << 'EOF'
riga uno
riga due
riga tre
EOF

Le virgolette singole attorno a EOF impediscono a bash di espandere variabili dentro il testo. Se vuoi che le variabili vengano espanse, togli le virgolette:

cat > ~/nomefile.txt << EOF
data di oggi: $(date)
utente: $USER
EOF

sed — modificare una riga specifica in un file esistente#

# Sostituisce la prima occorrenza
sed -i 's/vecchio/nuovo/' ~/nomefile.txt

# Sostituisce tutte le occorrenze
sed -i 's/vecchio/nuovo/g' ~/nomefile.txt

# Sostituisce solo alla riga 5
sed -i '5s/vecchio/nuovo/' ~/nomefile.txt

# Aggiunge una riga dopo la riga 3
sed -i '3a\nuova riga aggiunta' ~/nomefile.txt

# Elimina la riga 7
sed -i '7d' ~/nomefile.txt

Il flag -i modifica il file direttamente. Per vedere l’anteprima senza modificare, togli -i.

Il flusso pratico#

# Creo il file
cat > ~/test.conf << 'EOF'
host = localhost
port = 9000
debug = false
EOF

# Verifico
cat ~/test.conf

# Modifico una riga
sed -i 's/debug = false/debug = true/' ~/test.conf

# Verifico di nuovo
cat ~/test.conf

Nel log risultante tutto è perfettamente leggibile — nessuna sequenza spuria, nessun rumore. Esattamente quello che serve per ridare contesto a una sessione futura.


L’obiettivo non è automatizzare tutto. È capire tutto quello che viene fatto, poterlo spiegare e replicare

Il logbook è il primo mattone.