domingo, 25 de octubre de 2026

Memoria para los Agentes de IA

¡Hey! Esta vez quiero platicar sobre otro tema que me parece muy interesante: la memoria para los agentes de IA. Primero veremos por qué puede ser necesaria y después exploraremos algunas estrategias de implementación.

Para seguir el artículo, ayuda tener una idea general de qué es un agente: un sistema que usa un modelo de IA para decidir cómo avanzar en una tarea y que, según el caso, puede apoyarse en herramientas y conservar información útil. No necesitas conocer un framework en particular. Si quieres una introducción previa, puedes leer la explicación de Anthropic.


¿Por qué un agente necesita memoria?


Imagina un agente que analiza datos de ventas y le pide al usuario información para completar un dashboard. Durante la ejecución ocurre un error que obliga a reiniciar el agente. Al retomar la tarea…


Al reiniciarse, si el agente no guardó el estado de la tarea ni las respuestas del usuario, su contexto ya no incluye esa información. Por eso no sabe qué estaba haciendo ni qué datos había solicitado. Podría tener que empezar de nuevo o volver a pedirle al usuario información que ya había proporcionado. Un mecanismo de memoria puede conservar ese estado para que el agente retome la tarea.


Memoria de trabajo o corto plazo

Como ya mencioné los agentes cuentan con algo que se conoce como ventana de contexto que les permite tener presente la información de la conversación durante una sesión. Esta memoria de trabajo es muy útil, pero tiene dos limitaciones:

1. El costo de la autoatención puede crecer de forma cuadrática

Los LLM (large language model o modelo grande de lenguaje) que utilizan los agentes están basados en una arquitectura Transformer. Seguro puedes encontrar en la red más información de cómo funcionan exactamente. Aquí lo relevante es tener en mente que utilizan un mecanismo de autoatención, que calcula la relación de cada token (lo que puede ser una palabra, un fragmento de palabra o incluso un signo) con todos los demás tokens presentes en la ventana de contexto.

Matemáticamente, si el contexto tiene una longitud de n tokens, el cómputo de la autoatención densa estándar escala en un orden de O(n^2), considerando la notación Big-O. Esto significa que, al duplicar la longitud del contexto, el trabajo requerido por este mecanismo puede llegar aproximadamente a cuadruplicarse. Algunas implementaciones modernas optimizan el uso de memoria y el tiempo real de ejecución, pero procesar contextos cada vez más extensos continúa teniendo un costo.

Muchos agentes operan mediante ciclos continuos de razonamiento-acción-observación. El agente en cada paso añade más a la ventana de contexto el prompt del sistema, las descripciones de herramientas, el historial de conversación, los resultados intermedios de APIs y la información recuperada de fuentes externas. En implementaciones comunes, una parte importante de este contexto vuelve a ser procesada en cada iteración para que el agente pueda decidir su siguiente acción. Por esto, si el contexto crece de manera desproporcionada, también puede aumentar la latencia y el costo.

Este crecimiento puede degradar el rendimiento y contribuir a un fenómeno conocido como dilución de la atención. Como resultado, el agente puede pasar por alto información relevante y generar respuestas deficientes, inconsistentes o con mayor riesgo de alucinaciones.

2. Puede perderse al reiniciar
Para este punto pongamos en nuestra mente un sistema agéntico de atención al cliente. Al comenzar la conversación, se inicializa un agente que habla con el usuario y conserva temporalmente en su contexto información como su nombre, número de orden y el problema o asunto a tratar.
Si esta información se encuentra únicamente en la ventana de contexto y el sistema debe reiniciarse debido a una actualización o a un fallo inesperado, el nuevo proceso no tendrá acceso a la conversación anterior. Para el agente sería como comenzar desde cero y probablemente tendría que pedir al usuario toda la información de nuevo.

Esto se debe a que el LLM no recuerda por sí mismo las conversaciones entre ejecuciones. En cada llamada necesita recibir nuevamente el historial o la información relevante. Para poder retomar el trabajo después de un reinicio, el sistema debe guardar su estado utilizando algún mecanismo persistente. Esto puede ser una base de datos, un archivo, un almacén de memoria o un sistema de checkpoints.


Tipos de Memoria

Hasta ahora hemos hablado de la memoria de trabajo, y como seguro estarás imaginando, pasemos a lo que puede considerarse memoria a largo plazo. Esta complementa la memoria de trabajo o corto plazo y permite que el agente conserve información más allá de una tarea o sesión determinada.

Dependiendo del caso de uso, un agente necesitará recordar diferentes clases de información y recuperarla de diferentes maneras. Aunque no existe una única clasificación, normalmente se habla de los siguientes tipos de memoria:
  • Memoria Episódica – Experiencias
  • Memoria Semántica – Hechos
  • Memoria Procedimental – Instrucciones

Memoria Episódica

Si trasladamos este tipo de memoria a un ser humano, podríamos verla como el recuerdo de nuestras experiencias; es decir, las cosas que hicimos, el contexto en el que sucedieron y sus resultados. En un agente de IA podría representar interacciones o ejecuciones anteriores: qué acciones realizó, qué decisiones tomó, cuál fue el resultado y qué retroalimentación recibió. De esta manera, el agente podría recuperar una experiencia pasada cuando se encuentre ante una situación similar.

Memoria Semántica

En ocasiones necesitamos que el agente recuerde hechos concretos, por ejemplo el nombre de un usuario, sus preferencias, la descripción del problema o el estado actual de una situación que se está resolviendo con un cliente. Esto es, conservar estos datos sin tener que recuperar el momento exacto en el que el usuario dijo su nombre, relató el problema, explicó todo lo que había sucedido hasta llegar al estado actual. Esto último incluso podría regresarnos a los problemas relacionados con el crecimiento de contexto.

Memoria Procedimental

Este tipo de memoria es todo lo relacionado sobre cómo debe actuar el agente: instrucciones, pasos, políticas, reglas, y formas de ejecutar determinadas tareas. Los modelos son hoy en día tienen una gran capacidad para realizar diferentes actividades, pero no necesariamente saben cómo queremos que procedan dentro de un sistema u organización.

La intención no es proporcionarle simplemente toda la documentación de los procedimientos de una empresa de manera cruda o no estructurada. Esto nos podría poner de nuevo en los problemas con el crecimiento de contexto. Esta información se puede organizar mediante skills, de manera que el agente consulte las instrucciones y los recursos correspondientes según la tarea que necesite realizar. Las instrucciones procedimentales también pueden formar parte de los prompts, las configuraciones, el código, los guardrails o el harness encargado de controlar la operación del agente.


Almacenamiento y herramientas habituales

Las siguientes asociaciones no son reglas estrictas. Un mismo tipo de memoria puede utilizar diferentes formas de almacenamiento, y una misma herramienta puede servir para implementar más de un tipo.
  • Memoria de Trabajo
    • Qué conserva: la conversación y el estado de la tarea actual.
    • Almacenamiento habitual: estado en memoria o checkpoints persistentes.
    • Recuperación: por sesión, hilo o identificador.
    • Herramientas: Redis, SQLite, PostgreSQL o checkpointers de LangGraph.
  • Memoria Episódica
    • Qué conserva: Experiencias, acciones, y resultados anteriores.
    • Almacenamiento habitual: bases de datos relacionales o documentales y registros de eventos.
    • Recuperación: por fecha, sesión, filtros o similitud semántica
    • Herramientas: SQLite, PostgreSQL o MongoDB; pgvector o Qdrant cuando se necesite localizar experiencias similares.
  • Memoria Semántica
    • Qué conserva: hechos, preferencias, conceptos y relaciones.
    • Almacenamiento habitual: bases de datos relacionales, clave-valor, vectoriales o de grafos.
    • Recuperación: mediante consultas exactas, búsqueda por similitud semántica o relaciones entre entidades.
    • Herramientas: PostgreSQL, pgvector, Qdrant, Zep, Mem0, o Google Agent Platform Memory Bank.
  • Memoria Procedimental
    • Qué conserva: instrucciones, políticas, y formas de realizar tareas.
    • Almacenamiento habitual: archivos versionados, código, configuraciones o registros de prompts.
    • Recuperación: por tarea, versión o regla de activación.
    • Herramientas: skills, LangMem, Git, archivos markdown, o registros de prompts.


Similitud semántica

En varios puntos hemos hablado de la similitud semántica, esto hace referencia a una técnica que permite localizar información por su significado y no únicamente por la coincidencia exacta de palabras.

Para realizar este tipo de búsqueda, un modelo de embeddings convierte textos, imágenes u otros datos en representaciones numéricas llamadas vectores. Posteriormente, estos vectores pueden almacenarse e indexarse en un almacén vectorial para encontrar aquellos que se encuentran más próximos entre sí y que, de acuerdo con el modelo utilizado, representan contenidos similares.

Por ejemplo, un agente de soporte podría guardar la descripción de un problema, las acciones realizadas y su resultado. Si posteriormente recibe un caso similar, aunque esté expresado con palabras diferentes, el sistema puede generar su embedding, compararlo con los vectores almacenados y recuperar las experiencias más cercanas para que el agente las utilice como referencia.

Esto permite que una frase como “cambié de teléfono y no puedo entrar” pueda relacionarse con una experiencia anterior descrita como “el usuario perdió el acceso porque la autenticación de dos factores estaba vinculada a su dispositivo anterior”.

Consideraciones generales para la memoria

De manera general, una de las decisiones más importantes consiste en seleccionar estratégicamente qué información se va a almacenar. Como hemos revisado, la implementación no siempre tiene que ser algo muy complejo: incluso un archivo Markdown con un resumen podría funcionar como una forma sencilla de memoria externa o contexto persistente, siempre que el agente pueda consultarlo y actualizarlo cuando sea necesario.

Algunas consideraciones útiles para administrar la memoria son las siguientes:

  • Consolidación: la información relacionada puede combinarse, resumirse y actualizarse para evitar recuerdos duplicados o contradictorios. Por ejemplo, varios episodios podrían consolidarse en un hecho, una conclusión o una preferencia más general.

    Un caso práctico en herramientas de línea de comandos como Claude Code o Codex consiste en pedirle al agente que mantenga un archivo Markdown durante una investigación. En lugar de agregar indefinidamente todos los hallazgos, el agente puede actualizarlo periódicamente, agrupando información relacionada, resumiendo los puntos más importantes y reemplazando conclusiones que hayan quedado obsoletas.

    De esta manera, el archivo funciona como una memoria externa persistente que puede consultarse durante las siguientes etapas del trabajo. Al ser un formato legible para las personas, también podemos abrirlo, buscar información específica y corregir su contenido sin necesidad de invocar al modelo ni consumir tokens. Cuando el agente necesite utilizarlo, puede recuperar únicamente la información relevante e incorporarla nuevamente a su contexto.

  • Podado o eliminación (eviction): no todo debe recordarse indefinidamente. Pueden aplicarse políticas basadas en la antigüedad, frecuencia de uso, vigencia y utilidad de la información para eliminar recuerdos obsoletos o poco relevantes antes de incorporarlos nuevamente al contexto.

  • Múltiples estructuras de memoria: no toda la información tiene que almacenarse de la misma manera. Investigaciones recientes, como FluxMem, exploran la combinación de estructuras lineales —como secuencias temporales—, grafos —para representar relaciones— y estructuras jerárquicas —como temas y resúmenes—, seleccionando la más apropiada según el contexto de la consulta. Aunque es una línea de investigación prometedora, todavía no constituye una regla general para implementar memoria en todos los agentes.


¿El RAG es memoria?


Para dar un poco de contexto, el RAG (Retrieval-Augmented Generation ó generación aumentada por  recuperación) es una técnica que permite buscar información relevante en una fuente externa antes de generar una respuesta. Esta información puede ser especializada, privada o reciente, y no haber estado disponible durante el entrenamiento del modelo. Además, esta información puede proporcionarse al modelo sin necesidad de volver a entrenarlo.

Una forma práctica de verlo es como si le proporcionáramos al agente el acceso a una biblioteca. Entonces en vez de memorizar todos los libros, busca aquellos relacionados con la pregunta, recupera los fragmentos relevantes y los utiliza de referencia para elaborar su respuesta.


Esto no quiere decir que el contenido quede incorporado permanentemente en los parámetros del modelo: normalmente solo se encuentran disponible durante esa ejecución.

Pero bueno, entonces, ¿RAG es memoria o no? Depende de cómo se utilice el término. El trabajo original sobre RAG describe el almacén externo como una memoria no paramétrica. Sin embargo, dentro de un sistema agéntico, RAG se entiende como un mecanismo de recuperación y no necesariamente como memoria del agente.

Por ejemplo, si nuestro agente consulta manuales, documentos o políticas, estará accediendo a una fuente externa de conocimiento. Pero si el sistema conserva experiencias anteriores (memoria episódica), hechos y preferencias (memoria semántica), o incluso lineamientos sobre cómo realizar ciertos procedimientos (memoria procedimental), entonces esa información puede formar parte de la arquitectura de memoria del agente. RAG podría utilizarse como el mecanismo para recuperar, desde las fuentes externas, los detalles necesarios cuando resulten relevantes.

Una forma simplificada y práctica de verlo sería que el agente conservara en su memoria algo como: “El documento de procedimientos contables fue útil para revisar cómo registrar las pólizas”. La próxima vez que necesite resolver una situación relacionada con pólizas, ese recuerdo podría llevarlo a consultar nuevamente la fuente, mientras que RAG ayudaría a recuperar los fragmentos relevantes del documento.

La diferencia principal está en el contenido y en cómo se mantiene: RAG explica cómo recuperar información relevante, mientras que la memoria también implica decidir qué conservar, cómo actualizarlo, durante cuánto tiempo mantenerlo y cuándo olvidarlo.

¿Y si mi recuerdo no es seguro?


Para cerrar, esta parte me parece sumamente interesante. Recuerdo que alguna vez un profesor nos decía que el equipo más seguro era aquel que se encontraba cerrado, desconectado y apagado. Más que nada, trataba de advertirnos que, al abrir una puerta para compartir información, también comienzan a aparecer problemas de seguridad.

Al conectar un agente con fuentes externas en las que almacenamos y recuperamos información, ampliamos su superficie de ataque. Los principios de seguridad que normalmente aplicamos a los sistemas determinísticos también aplican aquí. Por ejemplo, el principio del mínimo privilegio o PoLP (Principle of Least Privilege) continúa siendo necesario: el agente solamente debería tener acceso a los datos y herramientas indispensables para realizar su tarea.  También es estratégico limitar el acceso en cada servicio o herramienta que el agente puede utilizar, de manera que el agente solamente cuente con los permisos necesarios para realizar su tarea.

Además, aparecen riesgos particulares de estos sistemas. Por ejemplo, podrían introducirse recuerdos falsos o manipulados en la memoria, algo conocido como memory poisoning (envenenamiento de memoria), o almacenarse instrucciones maliciosas donde el agente esperaba encontrar solamente datos. Si posteriormente el sistema recupera esa información y la considera confiable, podría alterar su comportamiento en futuras ejecuciones. Por ello, también es importante validar el origen y la integridad de los recuerdos, separar los datos de las instrucciones y mantener registros que permitan saber de dónde provino la información.

Por otro lado, también es importante que el agente pueda olvidar. Dentro del ámbito de la privacidad existe el concepto de RTBF (Right to Be Forgotten), conocido en español como derecho al olvido. Esto no significa que toda información deba eliminarse siempre y sin excepción, pero sí que debemos considerar cuándo corresponde borrar los datos personales. De manera similar a como lo hacemos en los sistemas determinísticos, también es necesario establecer políticas de retención que definan qué información se conserva, durante cuánto tiempo y bajo qué condiciones debe actualizarse o eliminarse.




Vaya! con esto dimos un pequeño recorrido a los conceptos generales de la memoria, te dejo algunas referencias en la parte de abajo y como siempre ...

Espero te sea de utilidad...

Salu2


___

Referencias:

sábado, 10 de octubre de 2026

Skills para agentes de IA

Wow, ha sido un rato que no pongo nada en mi blog :O... recientemente terminé unos estudios en IA y me gustaría ir compartiendo temas que me parecen interesantes, o que han sido relevantes para mí.

Ya tenía tiempo queriendo escribir en este blog con varios temas e ideas en la cabeza, este primer tema que seleccioné, es relacionado con los skills que se utilizan por agentes de IA que operan en la terminal, como Gemini CLI, Claude Code o Codex. Para este post asumiré que ya tienes una idea general de qué son estas herramientas y para qué sirven. En caso de que no, puedes buscarlas en la red y seguro encontrarás rápidamente una introducción y para qué se utilizan.

Para este post tomaré como referencia el formato abierto Agent Skills, aunque algunos detalles de su implementación pueden variar entre herramientas.

Pero, ¿para qué un skill?


La primera vez que yo escuché sobre ellos, me pregunté, pero si se supone que estas herramientas ya son inteligentes y tienen super conocimientos generales, ¿por qué necesitamos darles además instrucciones adicionales para realizar ciertas tareas? 

Ok, una forma de verlo es imaginando este escenario. Cuando trabajamos en algo contamos con los siguientes elementos a grandes rasgos:
  1. Una descripción de la tarea que tenemos que hacer.
  2. Nosotros como ejecutores de la tarea.
  3. Finalmente, una guía o conocimiento de cómo podemos ejecutar la tarea de la mejor manera posible y qué herramientas utilizar.
Podríamos decir que el punto 3 es opcional, pero si no tenemos esa guía podríamos estar improvisando cada vez que tenemos ese tipo de tarea particular. Además este punto 3 podría indicarnos atajos o recomendaciones de dónde encontrar herramientas que nos pueden servir para hacerlo mejor, más rápido y de una forma consistente. Pues bien cada uno de esos puntos se pueden ver de la siguiente forma cuando trabajamos con agentes de IA:
  1. La descripción de la tarea podría ser lo que entendemos como el prompt, junto con el contexto que proporcionamos.
  2. En este punto 2 (el ejecutor) sería el agente o sistema agéntico, por ejemplo, Gemini CLI, Claude Code o Codex. También puede ser un sistema agéntico orquestado mediante un framework como LangGraph, al que se le haya incorporado un mecanismo para descubrir y utilizar skills. Este utiliza un LLM (Large Language Model o Modelo Grande del Lenguaje), herramientas, contexto y un entorno de ejecución para realizar la tarea.
  3. Finalmente, este punto 3 sería el skill, que le indica al agente o sistema agéntico cómo abordar cierto tipo de trabajo de manera consistente.
Podemos concluir de manera general que un skill para un agente de IA es: un paquete reutilizable que contiene instrucciones y que también puede incluir documentos de referencia, scripts, plantillas y otros recursos para ejecutar una tarea de manera consistente. 


Super, entonces, le doy todo y ya está...


Si ya habías oído sobre los skills, podrías estarte preguntando, ok para que me ayude, le doy un bonche de documentos donde explique cómo hacer todo lo que yo hago y ya está, ahí quedaron mis skills; y la respuesta es sí pero no exactamente así, para los skills se recomienda utilizar una estructura, y seguro te preguntarás, ¿por qué?

Una de las principales razones para utilizar esta estructura es por algo que se conoce como ventana de contexto (context window). La ventana de contexto es la cantidad limitada de información - expresada en tokens - que el modelo puede considerar durante una ejecución. Vamos a hacer una comparación simplificada de lo que sucede, ya que es algo que en cierta forma nos pasa también a nosotros. 

Normalmente cuando tenemos algo que hacer utilizamos nuestra memoria de trabajo, esto es, mientras realizamos una tarea tenemos que acordarnos de cosas mientras la ejecutamos, por ejemplo, imagina una persona trabajando en un almacén, le podrá ser muy sencillo recordar los números del código de barras, tal vez de algunos que acaba de registrar, pero tal vez ya olvidó aquellos no tan comunes del día anterior. Bien, imagina que simplemente le decimos a la persona que tiene que leer todos los números de todos los productos antes de empezar a trabajar y luego empezar a trabajar. Esto aunque es posible, no sería lo más eficiente. Una mejor estrategia es decirle, te doy esta herramienta o documento donde puedes encontrar el número de código de barras de un producto cada vez que lo necesites. De manera muy simplificada, esta es una de las ideas detrás de los skills: en lugar de cargar desde el principio toda la información que el agente podría llegar a necesitar, le proporcionamos una forma organizada de localizarla y consultarla cuando resulte relevante.

Diversas evaluaciones han demostrado que el rendimiento de los modelos puede degradarse a medida que aumenta la cantidad de información en el contexto, incluso antes de alcanzar su límite máximo, especialmente cuando la información es extensa y está mezclada con contenido irrelevante o difícil de localizar. 

Aunque los modelos actuales cada vez pueden manejar ventanas de contexto más grandes, esto no quiere decir que toda la información se vaya a utilizar con la misma eficacia. Cuando el contexto crece demasiado puede aumentar el costo y la latencia, y también puede resultar más difícil localizar o utilizar correctamente la información relevante.

Además de manera análoga a nuestro ejemplo, la ventana de contexto es también limitada. Para trabajar durante periodos prolongados, algunos sistemas eliminan información anterior o utilizan mecanismos de compactación que conservan el estado más relevante utilizando menos tokens. Sin embargo, durante este proceso podrían perderse algunos detalles, por lo que sigue siendo conveniente evitar cargar información innecesaria desde el principio.

Entonces, cuando ponemos un skill a disposición de un agente, es como decirle: "Hey agente, cuando trabajes este tipo de tarea, aquí puedes encontrar instrucciones y recursos que podrían ayudarte". Inicialmente, el agente solo recibe algunos metadatos del skill, esto es básicamente su nombre y descripción. Análogamente a nuestro ejemplo, es como si únicamente supiera que tiene a disposición una guía de productos y sus códigos de barras. No necesita leer toda la lista desde el principio; solo sabe que existe y que puede consultarla. Si detecta que el skill puede ser relevante para la tarea, carga las instrucciones de su archivo SKILL.md y posteriormente consulta documentos de referencia, scripts o utiliza otros recursos conforme los necesite. Este proceso se conoce como divulgación progresiva (progressive disclosure).

Estructura de un skill


La estructura de un skill es la siguiente:

nombre-del-skill/
├── SKILL.md              # Obligatorio
├── references/           # Documentación de apoyo, opcional
├── scripts/              # Código ejecutable, opcional
└── assets/               # Plantillas y otros recursos, opcional



SKILL.md

Vamos que lleva esto, el primero de ellos es el archivo SKILL.md:  

______________________________________________________________________
---
name: validating-evidences
description: Validates evidence and generates a report. Use when reviewing evidence packages.
---

# Instructions 

When you use this skill:
1. Review the input entry
2. Follow this procedure
3. Validate the result
4. Show the output in this format

For more detail rules, review:
- `references/rules.md`

For validation, execute:
- `scripts/validation.py`
______________________________________________________________________


El nombre solo puede contener letras minúsculas, números y guiones; no puede empezar o terminar con un guión ni contener guiones consecutivos. Además, debe coincidir con el nombre de la carpeta, máximo 64 caracteres, y aunque no es un requisito en algunas guías se recomienda utilizar gerundio (por ejemplo, processing-pdfs).

En el caso de la descripción, contiene la explicación de que hace el skill y cuándo conviene utilizarlo. Normalmente se recomienda redactar en tercera persona, contener términos clave y contextos de activación, máximo 1024 caracteres.

De manera general, se recomienda que el archivo no pase de las 500 líneas. No es obligatorio escribirlo en inglés; sin embargo, hacerlo puede facilitar su reutilización y colaboración entre equipos internacionales. Además, algunas evaluaciones multilingües han encontrado diferencias de rendimiento entre idiomas, particularmente entre el inglés y los idiomas con menos datos disponibles. Esto depende del modelo, el idioma y el tipo de tarea, por lo que escribir un skill en inglés no es una restricción ni un requisito técnico.


references/

Esta carpeta es opcional y aquí podríamos tener información de apoyo:

references/
├── rules.md
├── api-specification.yaml
└── evidence-schema.json


scripts/

En esta carpeta se pueden encontrar scripts que puedan ser de utilidad para realizar la tarea, por ejemplo:

scripts/
├── validation.py
├── check_evidence.js
└── generate_report.sh

No necesariamente deben estar en un lenguaje específico (como Python por ejemplo), tampoco todos en el mismo lenguaje, pero sí conviene incluir en el SKILL.md las instrucciones para que el agente sepa cómo utilizarlos.

Esta carpeta es opcional; no todos los skill necesitan tener scripts. 


assets/

La idea es que esta carpeta contenga archivos que se utilizan para generar el resultado, como formatos, plantillas, imágenes, etc.

assets/ ├── report-template.docx ├── results-template.xlsx └── logo.png



¿Y quién o quienes los hacen?


Ok, aquí viene lo más interesante de todo esto: podemos pedirle a un agente de IA que nos ayude a construir el skill. Podemos darle los lineamientos generales, el objetivo y algunos ejemplos, y este lo va a generar con la estructura recomendada. Esto no quiere decir que lo creará 100% como lo necesitamos. Si llegaste hasta aquí ahora ya conoces la estructura de un skill, por lo que podemos revisar el contenido, instrucciones, scripts y demás recursos, para validar que cumplan con lo que necesitamos.

Pero espera, esto no termina aquí. Una estrategia interesante consiste en separar la creación y la prueba del skill entre dos agentes. Por ejemplo, un agente A construye el skill, y otro agente B lo utiliza. Si en los resultados encontramos errores o cosas por mejorar, esto se documenta y se lo pasamos al agente A para que ajuste el Skill. Posteriormente se lo damos de nuevo al B y, como puedes ver aquí tenemos ese ciclo de mejora para nuestros skills.


Elaboración propia basada en el ciclo de creación, evaluación y mejora de skills.


¿Dónde puedo compartir mis skills?


Bueno, lo simple es crear un repositorio, por ejemplo en GitHub, y compartirlos desde ahí. Sin embargo, uno de los directorios más populares es https://www.skills.sh/ operado por Vercel. Este sitio permite explorar skills para diferentes agentes, como Claude Code, Codex y Gemini, y también consultar cuáles son los más utilizados, cuáles provienen de organizaciones reconocidas y cuáles cuentan con alguna auditoría de seguridad.

Los skills alojados en GitHub pueden aparecer automáticamente en este directorio cuando los usuarios los instalan mediante el comando:

$ npx skills add <owner/repo>

ejemplo:
$ npx skills add omaryahir/el-skill


⚠ Importante - Nota de Seguridad: Como te puedes dar cuenta podemos consumir skills creados por otras personas u organizaciones. Antes de utilizar cualquier skill, es importante revisar sus instrucciones, scripts y demás recursos, ya que podrían indicarle al agente que ejecute código o acceda a archivos del entorno para realizar acciones no deseadas o incluso inseguras.


Por el momento, hasta aquí llegamos, espero te sea de utilidad!



Referencias:

Lost in the Middle: How Language Models Use Long Contexts
Degradación del rendimiento con entradas de contexto extensas.


miércoles, 6 de abril de 2022

Problemas con virtualenvwrapper en Python 3.8 +

Ok estuve teniendo unos problemillas tratando de instalar virtualenvwrapper con Python 3.8, si ya se que esta versión trae un manejo de ambientes incluido, pero a poco no es cómodo utilizar un simple $ workon myenv y listo ahi esta tu ambiente sin necesidad de estar buscando la carpeta del proyecto, bueno entonces me puse manos a la obra e hice mi propio virtualenvwrapper es super sencillo y solo tiene los comandos más básicos pero funciona aquí te dejo un link para que lo pruebes:

https://github.com/omaryahir/virtualenvwrapper
(echa un lente ^)

Espero te sea de utilidad !

viernes, 23 de julio de 2021

Intro al Tipado de Python

Listado de Tipos:

from typing import (
    Dict,
    List,
    Tuple,
    Set,
    Deque,
    NamedTuple,
    IO,
    Pattern,
    Match,
    Text,
    Optional,
    Sequence,
    Iterable,
    Mapping,
    MutableMapping,
    Any,
)


Ejemplo(s):


### Clases

from typing import ClassVar, Dict, List

class Foo:

    x: int = 1  # instance variable. default = 1
    y: ClassVar[str] = "class var"  # class variable

    def __init__(self) -> None:
        self.i: List[int] = [0]

    def foo(self, a: int, b: str) -> Dict[int, str]:
        return {a: b}

foo = Foo()
foo.x = 123


### ContextManager

from typing import ContextManager, Generator, IO
from contextlib import contextmanager

@contextmanager
def open_file(name: str) -> Generator:
    f = open(name)
    yield f
    f.close()

cm: ContextManager[IO] = open_file(__file__)
with cm as f:
    print(f.read())


Referencias:

https://www.pythonsheets.com/notes/python-typing.html


sábado, 3 de julio de 2021

Git Cherry Pick / git-cherry-pick

 Saludos Estimados !!

Hace mucho tiempo que no escribo aquí, y hoy me tope con algo que ya había realizado muchas veces en el pasado pero me enrede y ya no me salía, por lo que les compartó y/o me autocomparto por si lo vuelvo a necesitar el buen git-cherry-pick.

No es muy recomendable ya que un abuso de este comando puede dejarte una buena enredadera que después es difícil encontrarle forma, pero si que es útil como en el siguiente caso.

Necesitamos pasar un commit de un branch a otro, esto por que el branch original quedo muy desactualizado y por error se utilizó, es verdad que el rebase es una opción pero será un largo camino que recorrer además de que puede prestarse a errores de dedo en el camino, so el cherry pick en este caso nos resulta más económico además que no son muchos cambios que pueden revisarse fácilmente aquí los pasos:


1. Nos movemos a la branch donde tenemos nuestro commit: 

    git checkout MiBranchConCommit

2. Ahora vamos a revisar cuál es el hash de nuestro commit:

    git log --one line

    La salida de este comando será algo como:

    86f82f9 (HEAD -> SSCI-101-cherry-pick, origin/SSCI-101-cherry-pick) BRANCH-01test 1

    90805b1 (origin/master, origin/SSCI-85, origin/HEAD, master) BRANCH-02 test 2

    c3451b8 BRANCH test 3

    Vamos a tomar el último de este commit por lo que el número será: 86f82f9

3. Ahora vamos al branch de destino:

    git checkout BranchDestino

4. Una vez que nos encontremos ahí entonces aplicaremos el siguiente comando:

    git cherry-pick 86f82f9


Con este último comando se aplicará el mismo commit a este branch. Una opción interesante (que usualmente utilizo) solo en caso de que tuviéramos la misma base (o HEAD) en las ramas seria utilizar:

    git cherry-pick 86f82f9 --ff

Esta opción --ff hace referencia a fast forward existen más opciones por acá https://git-scm.com/docs/git-cherry-pick sin embargo este nos colocará el commit hacia adelante o por arriba de todos los previous commits.

¿Cómo ves?, si consideras que puede haber otros caminos, te agradezco me los compartas en los comentarios.


Espero te sea de utilidad !


Referencias:

https://git-scm.com/docs/git-cherry-pick


martes, 25 de octubre de 2016

Detalle con Google Chrome Free 3 of 9 Extended

El día de hoy me tope con un detalle con Google Chrome y la fuente Free 3 of 9 Extended usualmente la fuente funcionaba correctamente en una aplicación me toco desarrollar alguna vez pero derepente empezó a fallar, buscando en línea me encontre con que había al parecer un detalle con la forma en que renderiza las fuentes, y bueno finalmente con el link que agrego a las referencias una forma de como solucionarlo, lo que me funciono a mí fue en el código html colocar la fuente directamente en el tag usando el atributo style y sin colocar la palabra Extended en la fuente de la siguiente forma:

<font style="font-family:'Free 3 of 9'">*123*</font>

NOTA: Observen las comillas simples ' para la fuente.

De esta forma el problema se soluciono.


Espero te sea de utilidad !


Referencias
https://productforums.google.com/forum/#!topic/chrome/_KLiTgccPLA
https://productforums.google.com/forum/#!topic/chrome/Vd5abMVzKFI

Detalle con Google Chrome Free 3 of 9 Extended

El día de hoy me tope con un detalle con Google Chrome y la fuente Free 3 of 9 Extended usualmente la fuente funcionaba correctamente en una aplicación me toco desarrollar alguna vez pero derepente empezó a fallar, buscando en línea me encontre con que había al parecer un detalle con la forma en que renderiza las fuentes, y bueno finalmente con el link que agrego a las referencias una forma de como solucionarlo, lo que me funciono a mí fue en el código html colocar la fuente directamente en el tag usando el atributo style y sin colocar la palabra Extended en la fuente de la siguiente forma:

<font style="font-family:'Free 3 of 9'">*123*</font>

NOTA: Observen las comillas simples ' para la fuente.

De esta forma el problema se soluciono.


Espero te sea de utilidad !


Referencias
https://productforums.google.com/forum/#!topic/chrome/_KLiTgccPLA
https://productforums.google.com/forum/#!topic/chrome/Vd5abMVzKFI

miércoles, 16 de septiembre de 2015

Colocar un mensaje prelogin en Linux Ubuntu Server

Este es un tema que cada vez que lo tengo que hacer olvido cuál es exactamente el archivo, debido a que puede hacerse de diferentes formas pero la que mejor me ha funcionado es la siguiente:

$ sudo vi /etc/issue

NOTA: Con \n obtienes el nombre de la maquina, y con \l la terminal que se esta utilizando.


Espero te sea de utilidad !


Referencias:


martes, 1 de septiembre de 2015

Conectarse a una base de datos remota de firebird con isql

Realmente es muy simple pero necesito dejar la nota por que de manera recurrente lo he necesitado:

$ isql
SQL> CONNECT "[IP_SERVER]/[PUERTO]:[DATABASE_PATH]" user 'USER' password 'PASS';

Ejemplo:


CONNECT "10.10.1.2/3050:C:\bds\mibase.gdb" user 'SYSDBA' password '1234';


Espero te sea de utilidad !



Referencias:
http://wiki.metawerx.net/wiki/HowToSetUpARemoteFireBirdConnection

viernes, 28 de agosto de 2015

Ubuntu crontab: agregando una tarea para purgar django_session

Como de costumbre necesito agregar un cronjob para limpiar la tabla de sesiones de django y aquí dejaré documentado el proceso, un proceso cron es aquel que puede repetirse dependiendo de la configuración.

Dentro del sistema operativo podemos ejecutar

$ sudo crontab -e

Posteriormente el sistema preguntará por el editor en mi caso muy particular me gusta utilizar vim (opción 3), sin embargo da opciones a varios editores.

Ahora bien nos vamos al final del archivo la forma es estructurar el contenido de acuerdo a como se nos explica en la siguiente imagen:


Cada línea del archivo crontab esta compuesta por estos componentes, aquí un ejemplo:

#crontab
#------------

1 * * * * touch /webapps/hola.txt

#------------

OJO: Si estas editando con vim necesitas dar ESC y luego :wq!  así es con el signo de exclamación para que así instale el crontab.

En el crontab anterior estamos configurando que cada vez que el minutero del reloj marque 1, se va crear un archivo que dice hola.txt.

Ahora bien para el motivo que necesito hice un archivo con extensión .sh y lo coloque en mi directorio de /home/my_user/cron_django_session.sh con el siguiente contenido:

/webapps/mi_proyecto/venv/bin/python /webapps/mi_proyecto/django_app/manage.py clearsessions
strFecha=$(date)
echo $strFecha > /home/administrador/cron_django_session.log

NOTA: Revisar rutas de archivos

Posteriormente le damos permisos usando el comando:
$ chmod +x cron_django_session.sh

Posteriormente vamos al crontab para añadir la ejecución de este archivo:

0 1 * * * /home/my_user/cron_django_session.sh >/dev/null 2>&1

De esta forma el script se va ejecutar todos los días a la 1 a.m. al final se agrega >/dev/null 2>&1 para que no todo el tiempo el sistema operativo intente enviar un correo al usuario root, en caso de que se necesite se debe quitar esa parte.


Espero te sea de utilidad !

Referencias:
http://www.debian-tutorials.com/crontab-tutorial-cron-howto
http://www.guatewireless.org/os/linux/como-agregar-tareas-al-cron-de-linux.html
https://docs.djangoproject.com/en/1.8/topics/http/sessions/#clearing-the-session-store
http://www.opencsw.org/community/questions/289/how-to-clear-the-django-session-cache
https://vinta.ws/code/clear-session-in-django.html
http://stackoverflow.com/questions/10289970/add-10-minute-cron-job-to-ubuntu-package


ACTUALIZACIÓN 2015-10-20

Si quieres verificar como se ejecuta el cronjob puedes ver varios archivos a mi me funciono:
$ sudo vi /var/log/syslog

Referencias:
http://unix.stackexchange.com/questions/207/where-are-cron-errors-logged




miércoles, 29 de julio de 2015

git: mostrar la lista de archivos de un commit

Para mostrar la lista de archivos de un commit necesitamos primero utilizar el comando:

$ git log

Se abrirá pantalla con less y de ahí copiaremos el commit id y una vez que se copie, ejecutamos el siguiente comando pegandolo al final:

$ git diff-tree --name-only -r dfaja8asas5dasasas440asasas93213af4053da07b7f8


Espero te sea de utilidad !



Referencias:
http://stackoverflow.com/questions/424071/list-all-the-files-for-a-commit-in-git

lunes, 13 de julio de 2015

Include como php en Python + Django

En uno de los proyectos que estoy trabajando me tope con este detalle después de buscar en varios foros y demás encontre la siguiente forma, nada más cuidado por que baja el rendimiento, y hay que revisar las cuestiones de seguridad (http://lucumr.pocoo.org/2011/2/1/exec-in-python/); pero eso si funciona perfectamente y puede servir dependiendo de la aplicación; esto se lográ utilizando la instrucción exec.

El proyecto completo lo pueden descargar de: https://github.com/omaryahir/django_doing_includes

Aquí comento la parte importante dentro del archivo models.py estoy agregando un fragmento de código que manda llamar el archivo prueba.py :


db/models.py:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(verbose_name=u'Nombre', max_length=50)
    last_name = models.CharField(verbose_name=u'Apellido', max_length=50)
    initials = models.CharField(verbose_name=u'Iniciales', max_length=10)

    def save(self, *args, **kwargs):
        prueba_py = open('db/prueba.py','r')
        super(Person, self).save(*args, **kwargs)
        exec(prueba_py)
        print self.initials

    def __unicode__(self):
        return "%s %s" % (self.first_name, self.last_name)


class Otro(models.Model):
    otrocampo = models.CharField("otro campo", max_length=50)
    person = models.ForeignKey(Person)

    class Meta:
        verbose_name = "Otro"
        verbose_name_plural = "Otros"

db/prueba.py:

self.initials = "Esta es la prueba"
x = Otro()
x.otrocampo = "Prueba otro campo"
x.person = self
x.save()
print "Saliendo"

Como pueden observar en el código la línea - prueba_py = open('db/prueba.py','r')- de la clase Person se abre el archivo prueba.py y posteriormente en la línea - exec(prueba_py) - ejecutamos su contenido; lo interesante aquí de python es que carga todo el contexto, algo similar a lo que se hacia con php haciendo un include.

Podemos observar en el archivo prueba.py que dentro del archivo usamos las variables como si estas se encontrarán ahí, bien sin embargo en python una de las cualidades que tenemos el rendimiento, por lo que este tipo de usos puede afectarlo, se debe analizar en donde se requerirá su uso.

Si encuentras otra forma no dudes en compartirla ...

Saludos espero te sea de utilidad !


Referencias:
https://docs.python.org/3/library/functions.html?highlight=exec#exec
http://lucumr.pocoo.org/2011/2/1/exec-in-python/
https://github.com/omaryahir/django_doing_includes

domingo, 12 de julio de 2015

Nginx bloquear el acceso a un directorio estático

En uno de los sitios que me toco configurar necesite bloquear el acceso a un subdirectorio de un directorio de contenido estático, mientras que el acceso al contenido de los demás subdirectorios debe permanecer disponible, encontre la siguiente forma de hacerlo:

En el archivo de configuración del sitio agregue las líneas en negritas:

server {
    listen   80;
    ...
    location ~/static/carpetabloquear/ {
        alias /webapps/ruta/al/contenido/static/carpetabloquear/;
    }

    location /static/ {

        alias /webapps/ruta/al/contenido/static/;
    }
    ...
}


De esta forma aunque el usuario tiene acceso para algunos archivos del media dentro del directorio de la carpeta a bloquear no tiene acceso. Fue la forma como encontre hacerlo si has encontrado otra, te agradezco compartirlo.


Espero te sea de utilidad !


Referencias:
http://www.nginxtips.com/nginx-location-directive/

Django: ubuntu + nginx + gunicorn + supervisor + mysql

Tengo que instalar en una maquina virtual con virtualbox un deployment de un proyecto que debo entregar dejaré aqui los pasos que me funcionaron, ya tenía un post de deployment con uwsgi, pero ha quedado un poco desactualizado.

Bien voy colocando cada uno de los comandos:

$ sudo apt-get install python-virtualenv

Hay algunas otras herramientas que necesitamos instalar para el uso de django en ubuntu:

$ sudo apt-get install mysql-server
$ sudo apt-get install libmysql++-dev
$ sudo apt-get install python-dev
$ sudo apt-get install python-mysqldb
$ sudo apt-get install build-essential python

Crear una carpeta donde tendremos nuestras aplicaciones web:

$ sudo mkdir -p /webapps/carpeta_proyecto
$ sudo chown administrador /webapps/carpeta_proyecto

Creamos nuestro directorio virtual:

$ cd /webapps/carpeta_proyecto
$ virtualenv venv
$ source venv/bin/activate

Cargamos en ese directorio una carpeta con el código de nuestro proyecto, en mi caso lo tengo en bitbucket por lo que usando este comando descargo el código.

(venv)$ git clone http://bitbucket.org/tu_usuario/miproyecto.git

De esta forma tendremos dos directorios uno con el nombre de nuestro proyecto <miproyecto> y por otro lado tendremos un directorio con el entorno virtual <venv>.

Ahora instalamos el entorno en mi proyecto tengo un archivo requirements.txt, pero igual mínimo necesitamos instalar django y la librería de mysql, lo instalamos usando pip.

(venv)$ pip install django
(venv)$ pip install python-mysql

Es probable que para el proyecto tengan que correr un python manage.py syncdb o migrate para que puedan cargar la base de datos del proyecto, hasta este punto debemos poder probar el proyecto y ver que se encuentre funcionando correctamente usando un runserver.

Una vez que lo anterior se encuentre funcionando vamos ahora a realizar directamente el deployment.

Primero iniciamos instalando gunicorn, para eso utilizamos:

(venv)$ pip install gunicorn

Podemos probar el funcionamiento de gunicorn utilizando:

(venv)$ cd miproyecto
(venv)$ gunicorn miproyecto.wsgi:application --bind 0.0.0.0:8080

NOTA: La carpeta miproyecto, es el directorio que django crea cuando ejecutamos un startproject.

Al ejecutar el comando anterior gunicorn inicia un servidor en el puerto 8080 para ejecutar nuestro proyecto, sin embargo puede ser que el contenido estático no funcione correctamente.

Ahora para hacerlo más dinámico realizamos lo siguiente, creamos un archivo en mi caso yo lo deje en carpeta_proyecto/deployment/gunicorn_run y le copiamos dentro el siguiente contenido:

#!/bin/bash

NAME="miproyecto_app"                                        # Nombre de la app
DJANGODIR=/webapps/carpeta_proyecto/miproyecto               # directorio del proyecto de Django
SOCKFILE=/webapps/carpeta_proyecto/deployment/gunicorn.sock  # Nos comunicaremos utilizando este unix socket
USER=miusuario                                               # Correr con el usuario
GROUP=grupousuario                                           # Correr como el grupo 
NUM_WORKERS=3                                                # Cuantos - worker processes - de Gunicorn 
DJANGO_SETTINGS_MODULE=miproyecto.settings                   # Archivo settings de Django
DJANGO_WSGI_MODULE=miproyecto.wsgi                           # Archivo WSGI del proyecto

echo "Starting $NAME as `whoami`"

# Activando el entorno
cd $DJANGODIR
source ../venv/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Crear el directorio para correrlo en caso de no existir
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Iniciando Django Gunicorn
exec ../venv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=debug \
  --log-file=-


Posteriormente convertimos el archivo como ejecutable usando el comando:

(venv)$ sudo chmod u+x gunicorn_run

Para probar el gunicorn podemos ejecutar el archivo de esta forma hacemos lo siguiente:

(venv)$ ./gunicorn_run

Una vez que se haya logrado ejecutar sin problemas, ahora, instalamos supervisor.

(venv)$ sudo apt-get install supervisor

Después de instalar supervisor vamos a crear el archivo /etc/supervisor/conf.d/miproyecto.conf con el siguiente contenido:

[program:miproyecto]
command = /webapps/carpeta_proyecto/deployment/gunicorn_run               ; Comando para iniciar la app
user = miusuario                                                          ; Usuario que lo va ejecutar
stdout_logfile = /webapps/carpeta_proyecto/logs/gunicorn_supervisor.log   ; Ruta del archivo log
redirect_stderr = true                                                    ; Alamcenar stderr en el mismo log
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8                           ; Establecer UTF-8 por default

Creamos el directorio logs y el archivo para almacenar el gunicorn_supervisor.log dentro del directorio de carpeta_proyecto.

(venv)$ mkdir /webapps/carpeta_proyecto/logs
(venv)$ touch /webapps/carpeta_proyecto/logs/gunicorn_supervisor.log

Posteriormente utilizamos para cargar el supervisor:

(venv)$ sudo supervisorctl reread
miproyecto: available
(venv)$ sudo supervisorctl update
miproyecto: added process group

Ahora para revisar el estatus del proyecto podemos utilizar:

(venv)$ sudo supervisorctl status miproyecto
miproyecto                            RUNNING    pid 2277, uptime 0:01:40

Podemos iniciar, parar o reiniciar el proyecto utilizando:

(venv)$ sudo supervisorctl stop miproyecto
miproyecto: stopped
(venv)$ sudo supervisorctl start miproyecto
miproyecto: started
(venv)$ sudo supervisorctl restart miproyecto
miproyecto: stopped
miproyecto: started

Ahora vamos con Nginx, para instalarlo utilizamos:
(venv)$ sudo apt-get install nginx

Para iniciar el servicio podemos utilizar:
$ sudo service nginx start

Con esto el servidor de nginx se activará, puede probarse, por omisión el puerto es el 80. Ahora bien lo que haremos es crear el archivo /etc/nginx/sites-available/miproyecto con el siguiente contenido:

upstream miproyecto_app_server {
  # fail_timeout=0 means we always retry an upstream even if it failed
  # to return a good HTTP response (in case the Unicorn master nukes a
  # single worker for timing out).

  server unix:/webapps/carpeta_proyecto/deployment/gunicorn.sock fail_timeout=0;
}

server {

    listen   80;
    server_name example.com;

    client_max_body_size 4G;

    access_log /webapps/carpeta_proyecto/logs/nginx-access.log;
    error_log /webapps/carpeta_proyecto/logs/nginx-error.log;

    location /static/ {
        # path to static folder         alias   /webapps/carpeta_proyecto/miproyecto/static/; 
    }
    
    location /media/ {
        # path to media folder
        alias   /webapps/carpeta_proyecto/miproyecto/media/;
    }

    location / {
        # an HTTP header important enough to have its own Wikipedia entry:
        #   http://en.wikipedia.org/wiki/X-Forwarded-For
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # enable this if and only if you use HTTPS, this helps Rack
        # set the proper protocol for doing redirects:
        # proxy_set_header X-Forwarded-Proto https;

        # pass the Host: header from the client right along so redirects
        # can be set properly within the Rack application
        proxy_set_header Host $http_host;

        # we don't want nginx trying to do something clever with
        # redirects, we set the Host: header above already.
        proxy_redirect off;

        # set "proxy_buffering off" *only* for Rainbows! when doing
        # Comet/long-poll stuff.  It's also safe to set if you're
        # using only serving fast clients with Unicorn + nginx.
        # Otherwise you _want_ nginx to buffer responses to slow
        # clients, really.
        # proxy_buffering off;

        # Try to serve static files from nginx, no point in making an
        # *application* server like Unicorn/Rainbows! serve static files.
        if (!-f $request_filename) {
            proxy_pass http://miproyecto_app_server;
            break;
        }
    }

    # Error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /webapps/carpeta_proyecto/miproyecto/static/;
    }
}

De la misma manera que en los archivos anteriores personalizamos el contenido donde el color esta en negritas.

Ahora creamos el symbolic link en la carpeta sites-enabled (Esta carpeta nos permite indicar a nginx cuales sitios están habilitados).

$ sudo ln -s /etc/nginx/sites-available/miproyecto /etc/nginx/sites-enabled/miproyecto

Posteriormente reiniciamos nuestro servidor nginx:

$ sudo service nginx restart

Si hay algún error hay que revisar los directorios de los archivos, por otro lado en caso de que aparezca la pantalla de bienvenida de nginx al momento de volver a probar es debido al archivo default, en caso de que no vayamos a utilizar podemos eliminar su archivo símbolico desde el directorio de sites-enabled, una vez realizado lo anterior reiniciamos de nuevo el servidor de nginx.

$ sudo service nginx restart

Posterior a esto deberá funcionar correctamente el sitio.


Espero te sea de utilidad !



Referencias:
http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/
http://michal.karzynski.pl/blog/2013/10/29/serving-multiple-django-applications-with-nginx-gunicorn-supervisor/

domingo, 11 de enero de 2015

virtualenvwrapper en mac osx

Para instalar virtualenvwrapper se debe hacer con pip, siguiendo estos comandos:

$ sudo easy_install pip
$ sudo pip install virtualenv
$ sudo pip install virtualenvwrapper

Es posible que pip o virtualenv ya los tengas instalados así que si es así puedes omitir esos pasos, ahora bien, aquí viene por que no me funcionaba a mi, debes editar el archivo ~/.bashrc o ~/.zshrc (si estas usando oh my zsh, altamente recomendable) y colocar la siguiente línea:


source /usr/local/bin/virtualenvwrapper.sh

Con lo anterior estará funcionando el virtualenvwrapper, al parecer todo el asunto esta que lo cargue antes, fue una forma que encontre de resolverlo, si encontraste alguna otra no dudes en compartirla.

Espero te sea de utilidad !


Referencias: