Contribuir
import { Aside } from ‘@astrojs/starlight/components’;
Formas de contribuir
- Nueva herramienta OSINT: integrar un nuevo servicio como funcion async
- Bug fix: corregir comportamiento incorrecto
- Mejora de documentacion: clarificar, completar, traducir
- Tests: aumentar la cobertura de tests
- Nuevo tipo de entidad: extender la ontologia FTM
- Traduccion de skills: adaptar para nuevos idiomas
Flujo de trabajo
# 1. Fork del repositorio en GitHub
# 2. Clona tu forkgit clone https://github.com/tu-usuario/osint-ai-one.gitcd osint-ai-one
# 3. Crea una rama para tu cambiogit checkout -b feature/mi-nueva-herramienta
# 4. Instala en modo desarrollopython -m venv .venv && source .venv/bin/activatepip install -e ".[dev]"pre-commit install
# 5. Haz tus cambios# ...
# 6. Ejecuta los testspytest tests/ -vruff check src/ tests/mypy src/
# 7. Commit y pushgit add .git commit -m "feat: añade herramienta X para consultar Y"git push origin feature/mi-nueva-herramienta
# 8. Abre un Pull Request en GitHubAñadir una nueva herramienta OSINT
Estructura de la funcion
Todas las herramientas siguen el mismo patron:
import osimport httpxfrom src.cache import cached
@cached(ttl_seconds=86400)async def mi_servicio_lookup(target: str) -> dict: """ Consulta Mi Servicio para obtener informacion sobre target.
Args: target: IP, dominio u otro identificador
Returns: dict con campos normalizados del servicio """ api_key = os.getenv("MI_SERVICIO_API_KEY") if not api_key: return {"error": "MI_SERVICIO_API_KEY no configurada"}
async with httpx.AsyncClient(timeout=30) as client: response = await client.get( f"https://api.miservicio.com/v1/lookup/{target}", headers={"Authorization": f"Bearer {api_key}"} ) response.raise_for_status() data = response.json()
return { "source": "miservicio", "target": target, "result_field": data.get("field"), # ... normaliza los campos relevantes }Registrar en el agente
En src/agent/__init__.py, añade la herramienta a la lista de tools del agente ReAct.
Registrar en el MCP Server
En src/mcp_server/server.py, añade un endpoint MCP para la herramienta.
Tests obligatorios
import pytestimport respxfrom httpx import Responsefrom src.tools.mi_servicio import mi_servicio_lookup
@pytest.mark.asyncio@respx.mockasync def test_mi_servicio_lookup_success(): respx.get("https://api.miservicio.com/v1/lookup/8.8.8.8").mock( return_value=Response(200, json={"field": "value"}) ) result = await mi_servicio_lookup("8.8.8.8") assert result["result_field"] == "value" assert result["source"] == "miservicio"
@pytest.mark.asyncio@respx.mockasync def test_mi_servicio_lookup_error(): respx.get("https://api.miservicio.com/v1/lookup/8.8.8.8").mock( return_value=Response(404) ) result = await mi_servicio_lookup("8.8.8.8") assert "error" in resultDocumentar en .env.example
# Mi Servicio — https://miservicio.com/registerMI_SERVICIO_API_KEY=Convenciones de codigo
| Elemento | Convencion |
|---|---|
| Funciones de herramienta | nombre_servicio_tipo_lookup |
| Variables env | SERVICIO_API_KEY en mayusculas |
| Importaciones | Ordenadas: stdlib → third-party → local |
| Formato | ruff format (line length: 88) |
| Type hints | Obligatorios en funciones publicas |
| Docstrings | Google style, en ingles |
Convenciones de commits
feat: nueva herramienta para Xfix: corrige error en Y cuando Zdocs: añade documentacion de Wtest: tests para herramienta Vrefactor: extrae logica compartida de cachechore: actualiza dependenciasCodigo de conducta
Contribuciones respetuosas y constructivas. Critica el codigo, no a las personas.