<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es">
    <title></title>
    <link rel="self" type="application/atom+xml" href="https://blog.hashbang.cl/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blog.hashbang.cl"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-11-06T00:00:00+00:00</updated>
    <id>https://blog.hashbang.cl/atom.xml</id>
    <entry xml:lang="es">
        <title>Scaffold</title>
        <published>2026-11-06T00:00:00+00:00</published>
        <updated>2026-11-06T00:00:00+00:00</updated>
        
        <author>
          <name>hashbangcore</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.hashbang.cl/work/scaffold/"/>
        <id>https://blog.hashbang.cl/work/scaffold/</id>
        
        <content type="html" xml:base="https://blog.hashbang.cl/work/scaffold/">&lt;h1 id=&quot;scaffold&quot;&gt;Scaffold&lt;/h1&gt;
&lt;p&gt;Esta herramienta permite gestionar plantillas desde la línea de comandos. Es simple, versátil y veloz.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.hashbang.cl/work/scaffold/./README.md&quot;&gt;README en inglés&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;instalacion&quot;&gt;Instalación&lt;/h2&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; scaffold-cli&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;variable-de-entorno&quot;&gt;Variable de entorno&lt;/h2&gt;
&lt;p&gt;El programa utiliza únicamente &lt;code&gt;SCAFFOLDS&lt;/code&gt; como variable de entorno, la cual define la ruta donde se almacenan las plantillas.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;export&lt;/span&gt;&lt;span&gt; SCAFFOLDS&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;HOME&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;/scaffolds&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;comandos&quot;&gt;Comandos&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;init&lt;/code&gt;: despliega una plantilla. Si no se especifica el destino, se utiliza el directorio en donde se ejecuta el comando.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; template&lt;/span&gt;&lt;span&gt; [destino&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;list&lt;/code&gt;: lista las plantillas disponibles.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; list&lt;/span&gt;&lt;span&gt; [grupo/plantilla&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;schema&lt;/code&gt;: imprime el contenido de &lt;code&gt;schema.json&lt;/code&gt;, si está disponible.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; schema&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; grupo/plantilla&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;completion&lt;/code&gt;: genera el script de autocompletado para la shell seleccionada.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; completion&lt;/span&gt;&lt;span&gt; [shell&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;help&lt;/code&gt;: muestra el mensaje de ayuda.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;version&lt;/code&gt;: muestra la versión del programa.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;sistema-de-organizacion&quot;&gt;Sistema de organización&lt;/h2&gt;
&lt;p&gt;Para que el programa funcione correctamente, las plantillas deben organizarse en directorios.&lt;/p&gt;
&lt;p&gt;El directorio padre (grupo) puede contener uno o varios subdirectorios (plantillas), cada uno con los elementos que deseas utilizar.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$SCAFFOLDS/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── grupo/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── plantilla/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── fichero&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   └── directorio&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── plantilla/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── grupo/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── plantilla/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── plantilla/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Por ejemplo, puedes organizar tus &lt;code&gt;justfiles&lt;/code&gt; para diferentes escenarios.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;just/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── just/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── justfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── publish/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── dist/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └── justfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── justfile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;plantilla-predeterminada&quot;&gt;Plantilla predeterminada&lt;/h2&gt;
&lt;p&gt;El programa determina la plantilla predeterminada mediante dos reglas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cuando es la única plantilla disponible dentro de un grupo.&lt;/li&gt;
&lt;li&gt;Cuando el nombre de la plantilla coincide con el nombre del grupo.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── ansible/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── ansible   -&amp;gt; (plantilla predeterminada)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── database/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── firewall/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── css/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── blades/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── css       -&amp;gt; (plantilla predeterminada)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── just/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── just      -&amp;gt; (plantilla predeterminada)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── publish/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── tofu/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── forgejo   -&amp;gt; (plantilla predeterminada)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En este contexto, los siguientes comandos generan el mismo resultado:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; tofu&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; tofu/forgejo&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; ansible&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; ansible/ansible&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;schema&quot;&gt;Schema&lt;/h2&gt;
&lt;p&gt;De manera opcional, puedes utilizar &lt;code&gt;schema.json&lt;/code&gt; para configurar el despliegue de tus plantillas.&lt;/p&gt;
&lt;p&gt;Las opciones disponibles son &lt;code&gt;include&lt;/code&gt;, &lt;code&gt;exclude&lt;/code&gt;, &lt;code&gt;variables&lt;/code&gt;, &lt;code&gt;commands&lt;/code&gt; y &lt;code&gt;delimiters&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;just/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── just/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── justfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── schema.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── publish/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── dist/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └── justfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── justfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── schema.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Las opciones &lt;code&gt;include&lt;/code&gt; y &lt;code&gt;exclude&lt;/code&gt; permiten utilizar patrones glob (glob patterns) para seleccionar ficheros y directorios.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;inclusion-de-ficheros-y-directorios&quot;&gt;Inclusión de ficheros y directorios&lt;/h3&gt;
&lt;p&gt;Con &lt;code&gt;include&lt;/code&gt; puedes seleccionar manualmente los elementos que debe desplegar la plantilla.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;schema.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;pyproject.toml&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;src/**/*.py&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── .git           -&amp;gt; (no se incluye)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── pyproject.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── README.md      -&amp;gt; (no se incluye)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── schema.json    -&amp;gt; (no se incluye por defecto)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── src/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── tool/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        └── __init__.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;exclusion-de-ficheros-y-directorios&quot;&gt;Exclusión de ficheros y directorios&lt;/h3&gt;
&lt;p&gt;Con &lt;code&gt;exclude&lt;/code&gt; puedes seleccionar manualmente los elementos que deseas excluir.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;schema.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;.git&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;README.md&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Esta opción es útil si deseas versionar tus plantillas e incluir su propia documentación.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;variables&quot;&gt;Variables&lt;/h3&gt;
&lt;p&gt;En &lt;code&gt;schema.json&lt;/code&gt; puedes definir tus propias variables y sus valores se inyectarán en todos los ficheros donde se detecten las variables correspondientes.&lt;/p&gt;
&lt;p&gt;Las variables se exponen mediante flags de la línea de comandos al ejecutar &lt;code&gt;scaffold init&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Por ejemplo, puedes definir la variable &lt;code&gt;port&lt;/code&gt;. El programa buscará &lt;code&gt;{{port}}&lt;/code&gt; en todos los ficheros y realizará la sustitución correspondiente.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span&gt; [template&lt;/span&gt;&lt;span&gt;] --port 9000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Un caso de uso más complejo puede ser el siguiente:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;Nombre de proyecto&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;Hello world&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; 8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; web/laravel&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; ./new-dashboard&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-name&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; dashboard&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-description&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;Hotel reservation dashboard&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-port&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; 9000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;comandos-1&quot;&gt;Comandos&lt;/h3&gt;
&lt;p&gt;Hay casos en los cuales será necesario ejecutar tareas de inicialización al desplegar una plantilla; para ello está disponible la opción &lt;code&gt;commands&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;schema.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;commands&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;--initial-branch=dev&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;npm&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;direnv&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Las variables que definas previamente pueden ser usadas en los comandos que utilices de la siguiente forma:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;schema.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;commands&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;--initial-branch={{branch}}&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La plantilla crea la rama &lt;code&gt;dev&lt;/code&gt; por defecto, pero puedes modificar la variable &lt;code&gt;branch&lt;/code&gt; desde la línea de comandos.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;scaffold&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span&gt; [plantilla&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;directorio&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; --branch main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;delimitadores-personalizados&quot;&gt;Delimitadores personalizados&lt;/h3&gt;
&lt;p&gt;Por defecto los delimitadores son llaves dobles &lt;code&gt;{{ variable }}&lt;/code&gt;, pero los puedes modificar si agregas &lt;code&gt;settings.delimiters&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;schema.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;delimiters&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En este escenario tendrías que usar &lt;code&gt;#{variable}&lt;/code&gt; en tus ficheros.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Cargo.toml&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;package&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;#{name}&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;#{name}&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[[&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;bin&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;#{bin}&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;path&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;src/main.rs&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/main.rs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Personalmente no me agrada que el software limite al usuario, pero usar delimitadores fijos simplifica el &lt;code&gt;schema.json&lt;/code&gt; respecto a la versión anterior. Para lidiar con esa contradicción, decidí incluir la opción de definir delimitadores personalizados. &lt;code&gt;settings&lt;/code&gt; se reserva para posibles personalizaciones en el futuro.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;license&quot;&gt;License&lt;/h2&gt;
&lt;p&gt;BSD 2-Clause. See &lt;a href=&quot;https://blog.hashbang.cl/work/scaffold/./LICENSE&quot;&gt;LICENSE&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="es">
        <title>Sheath</title>
        <published>2026-11-06T00:00:00+00:00</published>
        <updated>2026-11-06T00:00:00+00:00</updated>
        
        <author>
          <name>hashbangcore</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.hashbang.cl/work/sheath/"/>
        <id>https://blog.hashbang.cl/work/sheath/</id>
        
        <content type="html" xml:base="https://blog.hashbang.cl/work/sheath/">&lt;h1 id=&quot;sheath&quot;&gt;sheath&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;sheath&lt;/code&gt; es una herramienta de línea de comandos escrita en Rust para ejecutar
programas con variables de entorno que viven en perfiles cifrados con
&lt;a rel=&quot;external&quot; href=&quot;https://age-encryption.org/&quot;&gt;age&lt;/a&gt;. La idea es parecida a &lt;code&gt;env VAR=VALOR programa&lt;/code&gt;, pero sin escribir secretos en el historial del shell, sin crear un
&lt;code&gt;.env&lt;/code&gt; en disco y sin modificar el entorno del shell padre.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Estado: MVP funcional. Los comandos &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;,
&lt;code&gt;profile&lt;/code&gt;, &lt;code&gt;lock&lt;/code&gt;, &lt;code&gt;unlock&lt;/code&gt; y &lt;code&gt;completions&lt;/code&gt; están implementados y cubiertos
por tests. Las funcionalidades marcadas como «planificadas» al final todavía
no existen.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;requisitos&quot;&gt;Requisitos&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Rust estable reciente (el proyecto usa edición 2024).&lt;/li&gt;
&lt;li&gt;No hace falta instalar el ejecutable &lt;code&gt;age&lt;/code&gt;: Sheath usa la biblioteca Rust
&lt;code&gt;age&lt;/code&gt; y realiza el cifrado y descifrado internamente.&lt;/li&gt;
&lt;li&gt;Unix (Linux, BSD, macOS). En Unix &lt;code&gt;profile&lt;/code&gt; usa &lt;code&gt;exec&lt;/code&gt; para sustituir el
proceso. En otras plataformas se usa &lt;code&gt;spawn&lt;/code&gt; + &lt;code&gt;wait&lt;/code&gt;, pero no es el objetivo
principal de la versión actual.&lt;/li&gt;
&lt;li&gt;Un editor de texto para &lt;code&gt;sheath edit&lt;/code&gt; (&lt;code&gt;$SHEATH_EDITOR&lt;/code&gt;, &lt;code&gt;$VISUAL&lt;/code&gt;, &lt;code&gt;$EDITOR&lt;/code&gt;
o &lt;code&gt;vi&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;compilar-y-probar&quot;&gt;Compilar y probar&lt;/h2&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; build&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-release&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; test&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-all-targets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; fmt&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-all&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; clippy&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-all-targets&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-all-features&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; warnings&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;El binario queda en &lt;code&gt;target/release/sheath&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;primeros-pasos&quot;&gt;Primeros pasos&lt;/h2&gt;
&lt;p&gt;Para probar sin tocar la configuración real, usa un &lt;code&gt;SHEATH_HOME&lt;/code&gt; aislado:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;export&lt;/span&gt;&lt;span&gt; SHEATH_HOME&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;PWD&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;/playground/sheath-home&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; 700&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;SHEATH_HOME&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; init&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-no-passphrase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; edit&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; profile&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; dev&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--no-passphrase&lt;/code&gt; deja la identidad en claro en &lt;code&gt;identity.txt&lt;/code&gt; y está pensado
para CI y pruebas. En uso normal, ejecuta &lt;code&gt;sheath init&lt;/code&gt; sin ese flag: la
identidad se guarda cifrada con una passphrase en &lt;code&gt;identity.age&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;crear-un-perfil&quot;&gt;Crear un perfil&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; edit&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/cliente01&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se abre el editor con una plantilla. El formato es dotenv estricto:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;dotenv&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;# Perfil: prod/cliente01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-12 z-d-9&quot;&gt;FOO&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;=&lt;/span&gt;&lt;span&gt;bar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-9&quot;&gt;API_URL&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;=&lt;/span&gt;&lt;span&gt;https://example.test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-12 z-d-9&quot;&gt;QUOTED&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;valor con espacios&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-12 z-d-9&quot;&gt;LITERAL&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;#39;sin $expansión&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-12 z-d-9&quot;&gt;EMPTY&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Al guardar, el contenido se valida, se cifra con la clave pública del store y
se escribe de forma atómica en &lt;code&gt;store/prod/cliente01.age&lt;/code&gt;. El texto plano solo
existe en el fichero temporal del editor mientras este está abierto.&lt;/p&gt;
&lt;h3 id=&quot;ejecutar-un-comando&quot;&gt;Ejecutar un comando&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; profile&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/cliente01&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; ls&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;la&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; profile&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/cliente01&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; ./deploy.sh&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-flag&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;El programa hijo recibe las variables del perfil. Por defecto hereda el entorno
del shell padre &lt;strong&gt;menos&lt;/strong&gt; todas las variables que empiezan por &lt;code&gt;SHEATH_&lt;/code&gt;, y
después aplica el perfil (el perfil gana si redefine una variable).&lt;/p&gt;
&lt;p&gt;Con &lt;code&gt;--clean&lt;/code&gt; no se hereda nada: solo existen las variables del perfil.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; profile&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-clean&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/cliente01&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; /usr/bin/env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Si el perfil define &lt;code&gt;PATH&lt;/code&gt;, &lt;code&gt;sheath&lt;/code&gt; lo usa para resolver el programa. Con
&lt;code&gt;--clean&lt;/code&gt;, si el perfil no define &lt;code&gt;PATH&lt;/code&gt;, Sheath usa el &lt;code&gt;PATH&lt;/code&gt; del proceso
padre únicamente para localizar el primer ejecutable. Ese &lt;code&gt;PATH&lt;/code&gt; no se pasa al
hijo; los comandos que el programa lance por nombre necesitarán un &lt;code&gt;PATH&lt;/code&gt;
definido en el perfil.&lt;/p&gt;
&lt;h3 id=&quot;mostrar-un-perfil&quot;&gt;Mostrar un perfil&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; show&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/cliente01&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Descifra y escribe el contenido dotenv del perfil en stdout. Esto imprime los
valores secretos en claro; evita redirigir la salida a archivos o compartirla.
El nombre del perfil se completa dinámicamente desde el store.&lt;/p&gt;
&lt;h3 id=&quot;listar-perfiles&quot;&gt;Listar perfiles&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; list&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recorre &lt;code&gt;store/&lt;/code&gt; sin descifrar nada y muestra una ruta por línea, sin el sufijo
&lt;code&gt;.age&lt;/code&gt;. Un prefijo opcional limita los resultados:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;prod/cliente01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;prod/cliente02&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se ignoran ficheros ocultos, temporales y todo lo que no termine en &lt;code&gt;.age&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;eliminar-un-perfil&quot;&gt;Eliminar un perfil&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; remove&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/cliente01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; remove&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; prod/cliente01&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-force&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sin &lt;code&gt;--force&lt;/code&gt;, &lt;code&gt;sheath&lt;/code&gt; pide confirmación y la respuesta predeterminada es no.
Con &lt;code&gt;--force&lt;/code&gt;, elimina el perfil sin preguntar. La eliminación es permanente;
solo se borra el fichero &lt;code&gt;.age&lt;/code&gt; del perfil.&lt;/p&gt;
&lt;h3 id=&quot;completar-comandos&quot;&gt;Completar comandos&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sheath completions&lt;/code&gt; genera la línea de inicialización para el shell indicado.
La integración dinámica consulta perfiles y directorios del store al completar
&lt;code&gt;list&lt;/code&gt;, &lt;code&gt;profile&lt;/code&gt;, &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt; y &lt;code&gt;remove&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; completions&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; bash&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; completions&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; zsh&lt;/span&gt;&lt;span class=&quot;z-l-10 z-d-8&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; ~/.zshrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Para Fish, ejecuta &lt;code&gt;sheath completions fish&lt;/code&gt; y guarda la salida en
&lt;code&gt;~/.config/fish/completions/sheath.fish&lt;/code&gt;. Completar nombres solo lee el store;
no descifra perfiles.&lt;/p&gt;
&lt;h3 id=&quot;bloquear-y-desbloquear-la-identidad&quot;&gt;Bloquear y desbloquear la identidad&lt;/h3&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; lock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;sheath&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; unlock&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lock&lt;/code&gt; cifra &lt;code&gt;identity.txt&lt;/code&gt; con una passphrase y crea &lt;code&gt;identity.age&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unlock&lt;/code&gt; descifra &lt;code&gt;identity.age&lt;/code&gt; y escribe &lt;code&gt;identity.txt&lt;/code&gt; con permisos &lt;code&gt;0600&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;unlock&lt;/code&gt; es un compromiso explícito: deja la identidad en claro para no pedir la
passphrase en cada ejecución. Si la identidad está bloqueada, &lt;code&gt;sheath profile&lt;/code&gt;
la descifra &lt;strong&gt;solo en memoria&lt;/strong&gt; y no escribe &lt;code&gt;identity.txt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Si no hay terminal y no se ha configurado un fichero de passphrase,
&lt;code&gt;profile&lt;/code&gt;/&lt;code&gt;unlock&lt;/code&gt; fallan sin ejecutar nada. &lt;code&gt;SHEATH_NO_PROMPT=1&lt;/code&gt; fuerza ese
comportamiento incluso con terminal.&lt;/p&gt;
&lt;h2 id=&quot;resolucion-de-rutas-y-configuracion&quot;&gt;Resolución de rutas y configuración&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Elemento&lt;/th&gt;&lt;th&gt;Precedencia&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SHEATH_HOME&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;$SHEATH_HOME&lt;/code&gt; → &lt;code&gt;~/.config/sheath&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;config&lt;/td&gt;&lt;td&gt;&lt;code&gt;-c/--config&lt;/code&gt; → &lt;code&gt;$SHEATH_CONFIG&lt;/code&gt; → &lt;code&gt;$SHEATH_HOME/config.toml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;store&lt;/td&gt;&lt;td&gt;&lt;code&gt;$SHEATH_STORE&lt;/code&gt; → &lt;code&gt;config.store&lt;/code&gt; → &lt;code&gt;$SHEATH_HOME/store&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;identidad&lt;/td&gt;&lt;td&gt;&lt;code&gt;$SHEATH_IDENTITY&lt;/code&gt; → &lt;code&gt;config.identity&lt;/code&gt; → &lt;code&gt;$SHEATH_HOME/identity.txt&lt;/code&gt; → &lt;code&gt;$SHEATH_HOME/identity.age&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;recipient&lt;/td&gt;&lt;td&gt;&lt;code&gt;$SHEATH_RECIPIENT&lt;/code&gt; → &lt;code&gt;config.recipient&lt;/code&gt; → derivado de la identidad&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;passphrase&lt;/td&gt;&lt;td&gt;&lt;code&gt;$SHEATH_IDENTITY_PASSPHRASE_FILE&lt;/code&gt; → &lt;code&gt;config.identity_passphrase_file&lt;/code&gt; → prompt si hay TTY&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;editor&lt;/td&gt;&lt;td&gt;&lt;code&gt;$SHEATH_EDITOR&lt;/code&gt; → &lt;code&gt;config.editor&lt;/code&gt; → &lt;code&gt;$VISUAL&lt;/code&gt; → &lt;code&gt;$EDITOR&lt;/code&gt; → &lt;code&gt;vi&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Reglas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SHEATH_HOME&lt;/code&gt; puede ser absoluto o empezar por &lt;code&gt;~&lt;/code&gt;; si es relativo se resuelve
contra el directorio actual.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt; y &lt;code&gt;SHEATH_CONFIG&lt;/code&gt; relativos se resuelven contra el directorio actual.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SHEATH_STORE&lt;/code&gt;, &lt;code&gt;SHEATH_IDENTITY&lt;/code&gt; y las rutas del config se resuelven contra
&lt;code&gt;SHEATH_HOME&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SHEATH_HOME&lt;/code&gt; y el store deben ser &lt;code&gt;0700&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config.toml&lt;/code&gt;, la identidad, el fichero de passphrase y los perfiles deben ser
&lt;code&gt;0600&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;SHEATH_HOME&lt;/code&gt; no existe, solo &lt;code&gt;sheath init&lt;/code&gt; lo crea; el resto de comandos
fallan con un error claro.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ejemplo de configuración:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt; $SHEATH_HOME/config.toml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;                 #&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt; relativo a SHEATH_HOME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;           #&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt; base o fichero .txt/.age&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt; identity_passphrase_file = &amp;quot;passphrase&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;recipient&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;age1...&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-5&quot;&gt; editor = &amp;quot;vi&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;config.toml&lt;/code&gt; se actualiza con &lt;code&gt;toml_edit&lt;/code&gt; para conservar comentarios y formato
cuando &lt;code&gt;init&lt;/code&gt; escribe el recipient.&lt;/p&gt;
&lt;h2 id=&quot;formato-de-perfil&quot;&gt;Formato de perfil&lt;/h2&gt;
&lt;p&gt;El parser es deliberadamente estricto y no es un intérprete de shell:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;KEY=VALUE&lt;/code&gt; o &lt;code&gt;export KEY=VALUE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Clave válida: &lt;code&gt;[A-Za-z_][A-Za-z0-9_]*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Comentario: &lt;code&gt;#&lt;/code&gt; como primer carácter no blanco de la línea.&lt;/li&gt;
&lt;li&gt;Sin comentarios inline. Un &lt;code&gt;#&lt;/code&gt; dentro de un valor forma parte del valor.&lt;/li&gt;
&lt;li&gt;Sin expansión de variables, sustitución de comandos ni multilinea.&lt;/li&gt;
&lt;li&gt;Comillas simples: contenido literal, sin escapes.&lt;/li&gt;
&lt;li&gt;Comillas dobles: se admiten &lt;code&gt;\\&lt;/code&gt;, &lt;code&gt;\&quot;&lt;/code&gt;, &lt;code&gt;\n&lt;/code&gt;, &lt;code&gt;\t&lt;/code&gt; y &lt;code&gt;\r&lt;/code&gt;; cualquier otro
escape es error.&lt;/li&gt;
&lt;li&gt;Valor sin comillas: se recorta el whitespace al inicio y al final.&lt;/li&gt;
&lt;li&gt;Clave duplicada: gana la última.&lt;/li&gt;
&lt;li&gt;Línea vacía y valor vacío permitidos.&lt;/li&gt;
&lt;li&gt;UTF-8 obligatorio; se tolera &lt;code&gt;\r\n&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Los errores indican línea y clave, nunca el valor.&lt;/li&gt;
&lt;li&gt;Límite de tamaño: 1 MiB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;estructura-del-proyecto&quot;&gt;Estructura del proyecto&lt;/h2&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;src/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── main.rs              # entrada y mapeo de errores a exit codes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── lib.rs               # módulos y dispatch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli.rs               # definición clap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── completion.rs        # integración con clap_complete&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── error.rs             # SheathError + Result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── config.rs            # config.toml + merge con entorno&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── paths.rs             # SHEATH_HOME, store, identidad, precedencia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── fs.rs                # permisos, escritura atómica, canonicalización&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── store.rs             # listado y resolución de perfiles&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── dotenv.rs            # parser estricto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── crypto.rs            # age: identidad, recipient, cifrar/descifrar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── identity.rs          # init, lock, unlock y passphrase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── env.rs               # entorno seguro, filtrado SHEATH_*, zeroize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── exec.rs              # resolución de PATH + exec/spawn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── commands/            # comandos finos que orquestan servicios&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── init.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── list.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── show.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── profile.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── edit.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── remove.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── lock.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── unlock.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tests/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── common/mod.rs        # TestHome, editores falsos, helpers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli_completions.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli_config.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli_edit.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli_identity.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli_list.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli_profile.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── cli_remove.rs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── cli_show.rs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;patrones-y-decisiones-de-diseno&quot;&gt;Patrones y decisiones de diseño&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Arquitectura por capas&lt;/strong&gt;: CLI (&lt;code&gt;cli.rs&lt;/code&gt;), configuración (&lt;code&gt;config.rs&lt;/code&gt;,
&lt;code&gt;paths.rs&lt;/code&gt;), dominio (&lt;code&gt;store.rs&lt;/code&gt;, &lt;code&gt;identity.rs&lt;/code&gt;, &lt;code&gt;dotenv.rs&lt;/code&gt;), infraestructura
(&lt;code&gt;fs.rs&lt;/code&gt;, &lt;code&gt;crypto.rs&lt;/code&gt;, &lt;code&gt;exec.rs&lt;/code&gt;) y comandos finos (&lt;code&gt;commands/&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapter&lt;/strong&gt;: &lt;code&gt;crypto.rs&lt;/code&gt; aísla la API de &lt;code&gt;age&lt;/code&gt;; &lt;code&gt;fs.rs&lt;/code&gt; aísla permisos y
escritura atómica; &lt;code&gt;edit.rs&lt;/code&gt; aísla el editor externo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;code&gt;Store&lt;/code&gt; es la única puerta de entrada al filesystem de
perfiles. &lt;code&gt;ProfileName&lt;/code&gt; es un &lt;em&gt;value object&lt;/em&gt; que valida rutas y evita
traversal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strategy&lt;/strong&gt;: la identidad puede estar en claro o cifrada; &lt;code&gt;identity.rs&lt;/code&gt;
resuelve el estado y elige el camino. La ejecución usa &lt;code&gt;exec&lt;/code&gt; en Unix y
&lt;code&gt;spawn&lt;/code&gt;/&lt;code&gt;wait&lt;/code&gt; fuera de Unix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inyección manual de dependencias&lt;/strong&gt;: &lt;code&gt;Config&lt;/code&gt;, &lt;code&gt;Store&lt;/code&gt; y &lt;code&gt;EnvPlan&lt;/code&gt; se pasan
explícitamente a los comandos, sin estado global ni singletons.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zeroize&lt;/strong&gt;: los valores de perfil, la passphrase y los buffers descifrados
viven en contenedores que se limpian al dropear.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No se usan &lt;code&gt;unwrap()&lt;/code&gt; ni &lt;code&gt;expect()&lt;/code&gt; en rutas de producción.&lt;/p&gt;
&lt;h2 id=&quot;seguridad&quot;&gt;Seguridad&lt;/h2&gt;
&lt;h3 id=&quot;en-reposo&quot;&gt;En reposo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Perfiles cifrados con &lt;code&gt;age&lt;/code&gt; X25519 (ChaCha20-Poly1305 + X25519).&lt;/li&gt;
&lt;li&gt;Identidad bloqueada cifrada con passphrase mediante scrypt.&lt;/li&gt;
&lt;li&gt;Store y &lt;code&gt;SHEATH_HOME&lt;/code&gt;: &lt;code&gt;0700&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Config, identidad, passphrase, perfiles y temporales de edición: &lt;code&gt;0600&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si se usa &lt;code&gt;$XDG_RUNTIME_DIR&lt;/code&gt; para el temporal de &lt;code&gt;edit&lt;/code&gt;, debe ser un
directorio &lt;code&gt;0700&lt;/code&gt;; si no, se usa el directorio temporal del sistema.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;age&lt;/code&gt; autentica el cifrado: un perfil manipulado falla al descifrar.&lt;/li&gt;
&lt;li&gt;Las escrituras usan un temporal en el directorio destino y &lt;code&gt;rename&lt;/code&gt; atómico,
sin seguir symlinks al escribir.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;en-memoria&quot;&gt;En memoria&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;El perfil descifrado vive en un &lt;code&gt;Zeroizing&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Las variables parseadas se guardan en &lt;code&gt;SecretEnv&lt;/code&gt;, que zeroiza sus valores.&lt;/li&gt;
&lt;li&gt;La passphrase y la identidad descifrada se zeroizan.&lt;/li&gt;
&lt;li&gt;Los valores nunca se incluyen en &lt;code&gt;Debug&lt;/code&gt;, errores ni logs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;std::process::Command&lt;/code&gt; copia el entorno para el hijo; esa copia no se puede
zeroizar desde Rust. En un &lt;code&gt;exec&lt;/code&gt; exitoso la imagen del proceso se reemplaza.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;en-ejecucion&quot;&gt;En ejecución&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exec&lt;/code&gt; en Unix evita dejar un proceso padre con secretos en memoria.&lt;/li&gt;
&lt;li&gt;El hijo recibe las variables por entorno, que es el mecanismo pedido.&lt;/li&gt;
&lt;li&gt;Se eliminan del entorno heredado todas las variables &lt;code&gt;SHEATH_*&lt;/code&gt; antes de
aplicar el perfil. El perfil puede volver a definirlas si lo necesita.&lt;/li&gt;
&lt;li&gt;No se usan &lt;code&gt;std::env::set_var&lt;/code&gt; ni mutaciones globales del entorno.&lt;/li&gt;
&lt;li&gt;El programa se resuelve contra el &lt;code&gt;PATH&lt;/code&gt; efectivo. En modo &lt;code&gt;--clean&lt;/code&gt;, el
&lt;code&gt;PATH&lt;/code&gt; padre solo se usa para localizar el ejecutable inicial cuando el
perfil no define uno; nunca se hereda al hijo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;limites-del-modelo&quot;&gt;Límites del modelo&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sheath&lt;/code&gt; &lt;strong&gt;no&lt;/strong&gt; puede evitar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;que el programa hijo lea sus propias variables;&lt;/li&gt;
&lt;li&gt;que otro proceso del mismo usuario lea &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/environ&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;que el hijo haga logging de secretos;&lt;/li&gt;
&lt;li&gt;que el editor cree swap/backup con el texto plano temporal;&lt;/li&gt;
&lt;li&gt;que un &lt;code&gt;SIGKILL&lt;/code&gt; deje un temporal en tmpfs hasta el reinicio;&lt;/li&gt;
&lt;li&gt;que root o malware con la sesión del usuario acceda a los secretos;&lt;/li&gt;
&lt;li&gt;que &lt;code&gt;unlink&lt;/code&gt; borre físicamente datos en SSD/COW.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;El cifrado de disco completo y un editor sin swap son responsabilidad del
usuario. La seguridad real viene del cifrado y de los permisos; &lt;code&gt;SHEATH_HOME&lt;/code&gt;
solo aísla config/store y evita contaminar el entorno del shell.&lt;/p&gt;
&lt;h2 id=&quot;dependencias&quot;&gt;Dependencias&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Dependencia&lt;/th&gt;&lt;th&gt;Uso&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;age&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cifrado X25519 de perfiles y scrypt para &lt;code&gt;identity.age&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;clap&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CLI declarativa con &lt;code&gt;derive&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;clap_complete&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Generar scripts de completions para shells compatibles.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;home&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Resolver &lt;code&gt;~&lt;/code&gt; y el home del usuario.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;rpassword&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Leer passphrases sin eco.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;secrecy&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Contenedores de secretos (&lt;code&gt;SecretString&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;serde&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Deserializar &lt;code&gt;config.toml&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;shell-words&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Parsear &lt;code&gt;$SHEATH_EDITOR&lt;/code&gt;/&lt;code&gt;$VISUAL&lt;/code&gt;/&lt;code&gt;$EDITOR&lt;/code&gt; con argumentos.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tempfile&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Temporales de &lt;code&gt;edit&lt;/code&gt; y escritura atómica.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;thiserror&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Errores tipados.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;toml&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Lectura de configuración.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;toml_edit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Escritura de configuración preservando formato.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;zeroize&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Limpieza de buffers con secretos.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Dev: &lt;code&gt;assert_cmd&lt;/code&gt;, &lt;code&gt;predicates&lt;/code&gt; y &lt;code&gt;tempfile&lt;/code&gt; para tests de integración.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;age&lt;/code&gt; es una dependencia de biblioteca compilada junto con Sheath; no se
requiere instalar el comando &lt;code&gt;age&lt;/code&gt; en el sistema.&lt;/p&gt;
&lt;p&gt;No se añaden &lt;code&gt;tokio&lt;/code&gt;, &lt;code&gt;anyhow&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;tracing&lt;/code&gt;, &lt;code&gt;keyring&lt;/code&gt; ni agentes.&lt;/p&gt;
&lt;h2 id=&quot;modelo-de-almacenamiento&quot;&gt;Modelo de almacenamiento&lt;/h2&gt;
&lt;p&gt;No hay índice ni base de datos: el store es el filesystem.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$SHEATH_HOME/                  # default: ~/.config/sheath&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── config.toml                # opcional&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── store/                     # default: $SHEATH_HOME/store&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── dev.age                # perfil &amp;quot;dev&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── prod/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       ├── cliente01.age      # perfil &amp;quot;prod/cliente01&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│       └── cliente02.age&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── identity.txt               # identidad en claro, 0600, si está desbloqueada&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── identity.age               # identidad cifrada con passphrase, si está bloqueada&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cada &lt;code&gt;*.age&lt;/code&gt; dentro de &lt;code&gt;store/&lt;/code&gt; es un perfil. El nombre es la ruta relativa al
store sin el sufijo &lt;code&gt;.age&lt;/code&gt;. Los subdirectorios son namespaces. Si el store se
versiona, los nombres de perfil siguen siendo metadatos visibles.&lt;/p&gt;
&lt;h2 id=&quot;tests&quot;&gt;Tests&lt;/h2&gt;
&lt;p&gt;Los tests unitarios cubren el parser dotenv, la validación de nombres de perfil,
la resolución de rutas, los permisos y la escritura atómica, el filtrado de
&lt;code&gt;SHEATH_*&lt;/code&gt; y el cifrado/descifrado básico.&lt;/p&gt;
&lt;p&gt;Los tests de integración usan un &lt;code&gt;SHEATH_HOME&lt;/code&gt; temporal y editores falsos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;list&lt;/code&gt; ordena perfiles anidados y omite ocultos/temporales.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;profile&lt;/code&gt; inyecta variables, no crea &lt;code&gt;.env&lt;/code&gt; y no filtra &lt;code&gt;SHEATH_*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;show&lt;/code&gt; imprime el contenido descifrado en stdout y completa perfiles anidados.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--clean&lt;/code&gt; deja solo las variables del perfil.&lt;/li&gt;
&lt;li&gt;En &lt;code&gt;--clean&lt;/code&gt;, el &lt;code&gt;PATH&lt;/code&gt; del padre puede localizar el primer ejecutable sin
filtrarse al entorno del hijo.&lt;/li&gt;
&lt;li&gt;Un perfil puede definir &lt;code&gt;SHEATH_HOME&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PATH&lt;/code&gt; del perfil se usa para resolver el programa.&lt;/li&gt;
&lt;li&gt;Perfil inexistente o cifrado corrupto: falla y no ejecuta.&lt;/li&gt;
&lt;li&gt;Se propaga el código de salida del hijo (&lt;code&gt;42&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;init&lt;/code&gt; con y sin passphrase; &lt;code&gt;lock&lt;/code&gt;/&lt;code&gt;unlock&lt;/code&gt;; prompt ausente.&lt;/li&gt;
&lt;li&gt;Permisos incorrectos en identidad, store, config, perfil y passphrase.&lt;/li&gt;
&lt;li&gt;Path traversal, componentes ocultos y symlinks fuera del store.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edit&lt;/code&gt; con editor correcto, editor que falla y contenido inválido.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remove&lt;/code&gt; con confirmación, cancelación, &lt;code&gt;--force&lt;/code&gt; y perfil inexistente.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;completions&lt;/code&gt; genera scripts de shell sin requerir un store.&lt;/li&gt;
&lt;li&gt;Precedencia &lt;code&gt;-c&lt;/code&gt; vs &lt;code&gt;SHEATH_CONFIG&lt;/code&gt; vs &lt;code&gt;SHEATH_HOME&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SHEATH_HOME&lt;/code&gt; relativo y &lt;code&gt;config&lt;/code&gt; relativo al home.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-7 z-d-6&quot;&gt;cargo&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-2&quot;&gt; test&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-4 z-d-1&quot;&gt;-all-targets&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;limitaciones-y-trampas-conocidas&quot;&gt;Limitaciones y trampas conocidas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;unlock&lt;/code&gt; deja &lt;code&gt;identity.txt&lt;/code&gt; en claro: es cómodo, pero elimina la protección
de la passphrase en reposo.&lt;/li&gt;
&lt;li&gt;Si se pierde la passphrase, se pierde la identidad. La recuperación es un
backup externo de &lt;code&gt;identity.age&lt;/code&gt; o del recipient y los perfiles.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edit&lt;/code&gt; depende del editor: si el editor crea swap/backup, esos ficheros pueden
contener secretos.&lt;/li&gt;
&lt;li&gt;Un &lt;code&gt;SIGKILL&lt;/code&gt; puede dejar un temporal en &lt;code&gt;$XDG_RUNTIME_DIR&lt;/code&gt; o en el directorio
temporal del sistema.&lt;/li&gt;
&lt;li&gt;La identidad descifrada en &lt;code&gt;profile&lt;/code&gt; no se escribe en disco, pero el hijo
puede leer sus propias variables.&lt;/li&gt;
&lt;li&gt;El store no se sincroniza ni se comparte; no hay locking entre procesos.&lt;/li&gt;
&lt;li&gt;No hay soporte completo de Windows/macOS; el camino principal es Unix.&lt;/li&gt;
&lt;li&gt;Los nombres de perfil son metadatos visibles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;planificado&quot;&gt;Planificado&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sheath export&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Salida &lt;code&gt;--json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Múltiples recipients por perfil.&lt;/li&gt;
&lt;li&gt;Plugins de &lt;code&gt;age&lt;/code&gt; (YubiKey, TPM, Secure Enclave).&lt;/li&gt;
&lt;li&gt;Keyring o agente de caché de identidad.&lt;/li&gt;
&lt;li&gt;Rotación automática de claves.&lt;/li&gt;
&lt;li&gt;Cifrado de nombres de perfil.&lt;/li&gt;
&lt;li&gt;Soporte completo de Windows/macOS y GUI/TUI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bitacora&quot;&gt;Bitácora&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: implementación inicial del MVP: resolución de &lt;code&gt;SHEATH_HOME&lt;/code&gt;,
config, parser dotenv, store cifrado con age, identidad X25519 con
lock/unlock, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;profile&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, filtrado de &lt;code&gt;SHEATH_*&lt;/code&gt;, &lt;code&gt;--clean&lt;/code&gt;,
resolución de &lt;code&gt;PATH&lt;/code&gt;, tests unitarios y de integración. Documentación de
seguridad y límites en este README.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: commits &lt;code&gt;b57f6b8&lt;/code&gt; (dependencias), &lt;code&gt;5f05704&lt;/code&gt; (implementación)
y &lt;code&gt;d28d632&lt;/code&gt; (tests). &lt;code&gt;README.md&lt;/code&gt; y &lt;code&gt;.gitignore&lt;/code&gt; quedan fuera de esos commits
porque los gestiona el usuario.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: commit &lt;code&gt;d758e92&lt;/code&gt;: modelo de seguridad y límites documentados en
el rustdoc de la crate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: commit &lt;code&gt;d19ed64&lt;/code&gt;: nombres de temporales genéricos y listado
que ignora entradas con nombres no válidos como perfil.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: commit &lt;code&gt;8481f51&lt;/code&gt;: tests de perfiles con dotenv inválido,
limpieza del temporal tras fallo del editor e &lt;code&gt;init&lt;/code&gt; sin passphrase/TTY.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: se integra &lt;code&gt;clap_complete&lt;/code&gt; con &lt;code&gt;sheath completions &amp;lt;shell&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: se añade &lt;code&gt;sheath remove&lt;/code&gt; con confirmación predeterminada
negativa y opción &lt;code&gt;--force&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: se añaden &lt;code&gt;sheath show&lt;/code&gt; y completions dinámicas para perfiles
anidados; &lt;code&gt;--clean&lt;/code&gt; usa el &lt;code&gt;PATH&lt;/code&gt; padre solo para resolver el ejecutable
inicial si el perfil no define uno.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-10-27&lt;/strong&gt;: se ordenan los comandos en &lt;code&gt;--help&lt;/code&gt; por grupos de uso.&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
</feed>
