¿Qué hace Legwork?
Para qué sirve
Investigación de decisiones. No investigación académica. La pregunta siempre es alguna versión de "¿qué deberíamos hacer sobre X?", y el resultado se juzga por su utilidad, no por su exhaustividad.
Eso da forma a todo lo siguiente. Una afirmación se juzga por si su fuente es el tipo adecuado de cosa para esa afirmación, no por si su dominio es respetable. Tres fuentes que coinciden solo cuentan si podrían haber discrepado. Y una ejecución que no puede responder la pregunta lo dice en lugar de producir una extensión llena de matices.
Principio de autonomía. Infiera lo que necesite del contexto, elija un nivel y comience. Anuncie el nivel en una línea y proceda; no le pida al usuario que elija. Pueden redirigir a media ejecución, lo que cuesta mucho menos que una pregunta bloqueante en cada solicitud. Deténgase solo ante un error crítico o una consulta incomprensible.
Niveles
La profundidad aumenta el rigor. Nunca aumenta la extensión.
| rápido | estándar | profundo | |
|---|---|---|---|
| Enmarcar | Decisión más 2-3 subpreguntas | Más falsadores nombrados | Más ángulos de segundo orden |
| Recopilar | Fragmentos de SERP; recuperar solo para fijar una cifra | Recuperación directa de las fuentes principales por hallazgo | Una fuente primaria para cada hallazgo |
| Desafiar | Solo agrupación por independencia | Una búsqueda de confirmación negativa por hallazgo | Pasada de confirmación negativa por hallazgo más una auditoría de origen |
| Formato | breve | breve o informe | informe |
| Nivel de puerta | --level quick | --level standard | --level deep |
| Tiempo aproximado | 3-5 min | 8-12 min | 20-40 min |
El valor predeterminado es estándar. Use el nivel que el usuario nombre (quick,
standard, deep, o un equivalente como "escaneo rápido" o "ir a fondo"), si no
$LEGWORK_DEFAULT_MODE, si no estándar. "Investigación profunda" por sí solo es una
frase de invocación para esta habilidad, no una solicitud del nivel profundo - continúe
hasta el valor predeterminado.
Escale silenciosamente un nivel si el alcance revela que la pregunta es materialmente de mayor importancia de lo que implicaba la solicitud, y dígalo en la misma línea de apertura.
Línea de apertura, luego directamente a la Fase 1:
Ejecutando estándar (~8-12 min). Diga "profundo" para fuentes primarias y una pasada de confirmación negativa.
Canalización
Cuatro fases. Instrucciones completas en methodology.md.
- Enmarcar - nombre la decisión, las subpreguntas que la resolverían y qué evidencia cambiaría la respuesta.
- Recopilar - recupere para cada subpregunta, registrando cada recuperación.
- Desafiar - busque el caso de confirmación negativa; agrupe las fuentes por independencia.
- Escribir - ensamble el resultado, luego aplique la puerta.
Las fases 2 y 3 se intercalan por hallazgo en lugar de ejecutarse como puertas estrictas.
Antes de comenzar
Fije la fecha. Ejecute date -u +%Y-%m-%d y use esa cadena para la ejecución, en
el nombre de la carpeta de salida, y en cada consulta de búsqueda que pueda devolver material
fechado. Nunca confíe en su propio sentido del año actual, y nunca deje que un
subagente lo resuelva por sí mismo.
Verifique si esta ejecución ya se ha realizado. Lea el índice primero. Es un despachador: una fila por ejecución pasada, y la columna de resumen existe para que pueda decidir si abrir un informe sin pagar por abrirlo.
python3 ${CLAUDE_SKILL_DIR}/scripts/index.py list --base "$OUTPUT_BASE"
Luego elija uno de cuatro caminos, y diga cuál en su línea de apertura:
| El índice dice | Haga esto |
|---|---|
| Una ejecución cubre esto y no está desactualizada | Responda a partir de ella. Lea ese informe, no la web. |
| Una ejecución cubre esto pero está marcada como desactualizada | Actualícela |
| Una ejecución es cercana pero responde una pregunta diferente | Nueva ejecución, y haga referencia cruzada |
| No coincide nada | Nueva ejecución |
Responder a partir de una ejecución anterior es un éxito, no un atajo. Abra el informe, lea los hallazgos que se relacionan con la pregunta, y responda con sus bandas de confianza intactas. Diga claramente que proviene de una ejecución de una fecha determinada. Volver a ejecutar una investigación que ya se realizó y aún se mantiene es el desperdicio que este índice existe para prevenir.
Actualizar en lugar de volver a ejecutar
Una actualización actualiza el informe existente en el mismo lugar - misma carpeta, mismo archivo. No cree una segunda carpeta: dos carpetas que describen una pregunta es cómo un lector termina actuando según la que le tocó abrir.
-
Reanude el registro de recuperación en lugar de comenzar uno nuevo. Todo lo que contiene ya está pagado.
python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py resume --tsv "$OUT/$BASE.tsv"Eso imprime los ángulos ya trabajados, las páginas ya recuperadas y cuáles de ellas aún no tienen una cita. Trabaje los ángulos descubiertos y vuelva a verificar las afirmaciones que deciden la respuesta; no vuelva a recuperar lo que ya está registrado y actual.
-
Mueva cada afirmación que ahora sea incorrecta a
## Reemplazadocon la fecha y el motivo. Nunca elimine una afirmación en silencio. Alguien puede haber actuado sobre ella, y una ejecución futura necesita saber que este terreno ya se ha cubierto. Si la misma respuesta ha sido ahora anulada dos veces, dígalo en voz alta: esa es la señal más fuerte en el documento de que la pregunta es inestable. -
Agregue una línea
## Línea de tiempoque indique qué cambió. -
Actualice la fila del índice.
Archivar la ejecución
Cada ejecución termina en el índice, incluida una que no pudo responder - "miramos y no encontramos nada" es exactamente lo que una sesión futura necesita para no volver a mirar.
python3 ${CLAUDE_SKILL_DIR}/scripts/index.py add --base "$OUTPUT_BASE" \
--folder "$BASE" --topic "Triage de Outlook para pequeñas consultas" --level deep \
--one-liner "No hay triage nativo por debajo de E5; la brecha es real pero estrecha"
El resumen dice lo que la ejecución concluyó, no de qué se trataba. "Notas sobre la galería de complementos" es inútil dentro de seis meses; "No existe ruta de envío, la instalación es mediante URL o no es posible" responde la pregunta por sí sola. La puerta advierte cuando una ejecución falta en un índice que existe.
Política de recuperación
Dos escaleras, primeros peldaños gratuitos. Suba solo hasta donde necesite.
Para buscar:
| Peldaño | Llamada | Cuándo |
|---|---|---|
| 1 | WebSearch | Siempre. Tres variantes de consulta por ángulo. |
| 2 | platforms.py search --on ... | La respuesta es un registro que una plataforma posee: un hilo, un paquete, un repositorio, un elemento de noticias fechado, el registro de cambios de un proveedor. Gratuito, sin clave, y devuelve el registro en lugar de una página sobre él. |
| 3 | bd_search.py -m general --engine bing --country XX --language yy | Escaso después de tres variantes, o la pregunta es geo-específica. Un segundo motor es la razón para pagar. |
| 4 | bd_search.py -m discover --intent "..." | Dos motores aún escasos. |
Para abrir una página:
| Peldaño | Llamada | Cuándo |
|---|---|---|
| 1 | fetch.py "<url>" --find "término" | Siempre primero. Gratuito, y el único transporte gratuito que produce texto de página, por lo que las cifras se pueden rastrear y las citas se pueden verificar. |
| 2 | WebFetch | fetch.py salió con código 3 y la página no vale la pena pagar por ella. |
| 3 | bd_search.py "<url>" -m scrape | Bloqueada: protección contra bots, muro de pago, 403. |
| 4 | bd_search.py "<url>" -m render | Un shell renderizado por el cliente. |
| 5 | bd_search.py "<url>" -m pipeline --pipeline NOMBRE | Una plataforma que bloquea todo lo anterior. Se factura por registro; -m reddit es donde es la única ruta, no un último recurso. |
Ejecute platforms.py list para las diez plataformas gratuitas, y bd_search.py --help
para los modos de pago. En caso de código de salida 2 (autenticación o cuota), dígale al usuario que ejecute
brightdata login. No lo reintente.
Un resultado de búsqueda es una pista, no una página que se lee. En estándar y profundo, abra
lo que cita: la puerta trata una cita que se basa solo en filas de websearch como
no abierta, una advertencia en estándar y un error en profundo. Rápido está diseñado para ser solo fragmentos y no se le
pide.
Registre el fallo antes de la alternativa. Una página que no se abre es evidencia
sobre la ejecución - --status blocked - y el recibo lo cuenta.
Limite lo que recupera. --max-chars 8000 en llamadas de scrape, y prefiera
--find a un límite ciego: en una página larga, los primeros ocho mil caracteres suelen ser
la navegación.
Qué fuentes puede usar
La investigación es lo que un externo podría establecer. Ese límite importa en ambas direcciones.
Nunca presente los propios registros del usuario como un hallazgo. Si la pregunta trata sobre la propia empresa, producto o posición de mercado del usuario, no acceda a sus cuentas privadas - su registrador, su facturación, su bandeja de entrada, sus archivos internos - e informe lo que encontró allí como si hubiera sido descubierto. Ellos ya lo saben. Es circular, infla la evidencia aparente y disfraza cuán poco puede ver realmente un externo. Busque el equivalente público e informe lo que un externo encontraría, incluido nada.
Sí use el acceso exclusivo que el usuario le ha dado, sobre terceros. Una suscripción pagada, un conjunto de datos privado o una base de datos interna que el usuario ha ofrecido explícitamente es una ventaja genuina al investigar competidores, proveedores o un mercado. Úselo, regístrelo como una fuente como cualquier otra, y anote en Limitaciones que el hallazgo se basa en un acceso que el lector puede no tener.
Cuando una entidad resulta no tener ningún rastro público en absoluto, esa es la respuesta. Enumere lo que verificó, diga que la existencia o escala no se pudo verificar desde fuera, y no llene el vacío con acceso privilegiado. Es la forma de "no pudo responder" aplicada a una entidad en lugar de a toda la pregunta.
El registro de recuperación
Cada recuperación, en cada nivel, agrega una fila:
python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py log \
--tsv "$OUT/$BASE.tsv" \
--url "https://acme.example/precios" \
--kind precios_proveedor \
--angle "¿cuánto cobra el actual titular?" \
--via webfetch \
--date 2026-07-01 \
--title "Precios" \
--quote "Plan Team: 30 dólares estadounidenses por usuario por mes, facturado anualmente." \
--text-file /tmp/pagina.txt
Dos campos tienen el peso, y ninguno puede ser verificado por nada aguas abajo.
--angle es la subpregunta que esta recuperación estaba respondiendo. La
corroboración se cuenta por ángulos en lugar de por fuentes porque la propia dispersión de legwork infla los
recuentos de fuentes. Registre el ángulo honestamente - reutilizar una cadena en una ejecución
destruye silenciosamente la verificación, y ningún script puede detectar que lo hizo.
--quote es la oración textual que hizo que la fuente valiera la pena citarse. Registre
una para cada fuente que tenga la intención de citar, a medida que la lee. Alrededor de la mitad de todos los
hallazgos no llevan cifra, por lo que para esos, la cita es la única evidencia que existe,
y es la única parte que sobrevive a que la página cambie. Cuando el texto de la página está en
disco - cualquier cosa abierta con fetch.py, o un -m scrape con --out - la
cita se verifica contra él y quote_verified: false significa que ha
citado mal la página.
--from-fetch completa la URL, el título, la fecha y el texto de la página a partir del sidecar que esos
dos escriben, por lo que no es necesario volver a escribir nada:
python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py log --tsv "$OUT/$BASE.tsv" \
--from-fetch /tmp/legwork/ab12cd34ef56.json \
--angle "¿cuánto cobra el actual titular?" --kind precios_proveedor \
--query "site:acme.example pricing" --quote "Team plan: 30 US dollars ..."
sources.py log --help cubre el resto: --via transportes (incluyendo api,
local y mcp), --text-file extracción numérica, --kind. Registre el transporte
que realmente utilizó - volver a recuperar una página a través de uno diferente para hacerla
registrable distorsiona el rastro en lugar de registrarlo. sources.py kinds imprime
qué tipos de fuente se adaptan a qué afirmaciones.
Subagentes
La recuperación es la única fase que vale la pena paralelizar, un subagente por ángulo. Bríndeles instrucciones desde subagent-brief.md, que lleva la plantilla textual, la forma de retorno requerida y la razón de por qué cada línea está en ella. Un subagente tiene contexto cero, por lo que todo lo que necesita va en las instrucciones.
Tres cosas se quedan con usted en lugar de las instrucciones:
- Combine el modelo con la forma del ángulo. La recopilación de fragmentos y la fijación de una cifra conocida funcionan bien en un modelo económico - pase la anulación explícitamente, nunca deje que uno herede el modelo de la sesión por accidente. Pero el trabajo de fuente primaria de nivel profundo, y cualquier cosa que reconstruya una enumeración, se queda en el modelo del orquestador. Medido: en una comparación, los orquestadores abrieron 3, 8 y 32 páginas de proveedores en el rango de económico a capaz, y solo el más débil llenó cada celda de la cuadrícula desde un solo agregador mientras informaba éxito.
- Nunca pegue la transcripción de un subagente en su síntesis. Tome la estructura de retorno, verifique que la cadena del ángulo haya vuelto sin cambios, registre cada fila, trabaje a partir del registro.
- El alcance, el desafío y la síntesis son juicio. Se quedan en el modelo principal.
Scripts
Todos solo con la biblioteca estándar. Sin virtualenv. Cualquier python3 >= 3.9.
| Script | Propósito |
|---|---|
fetch.py "<url>" --find TÉRMINO | Abrir una página gratis y mantener su texto; sale con código 3 en un bloqueo o un shell |
platforms.py list | search --on X | Diez fuentes nativas de plataforma gratuitas, que devuelven registros en lugar de páginas |
sources.py kinds | log | score | Vocabulario de tipos de fuente, el registro de recuperación, puntuación de idoneidad por tipo de afirmación |
sources.py receipt | Los recuentos de recuperación para la línea de recibo, tomados del registro |
sources.py stale --claim-kind K | Qué fuentes registradas han caducado, según la vida media de ese tipo de afirmación |
sources.py resume | Lo que una ejecución anterior ya recuperó, para que una re-ejecución lo omita |
independence.py groups | check | Colapsar fuentes en voces independientes; contar corroboración consciente del ángulo |
independence.py portfolio | Concentración de fuentes en toda la ejecución, no dentro de un hallazgo |
index.py add | list | El índice de investigación - archivar una ejecución, encontrar una pasada, detectar las desactualizadas |
matrix.py check --report RUTA | Integridad de una matriz de comparación |
check.py --report RUTA --level NIVEL | La puerta de capacidad de envío |
finish.py --report RUTA --level NIVEL | Puerta, barrido de desactualización y archivo en una sola llamada |
| `bd_search.py "<consulta | url>" -m MODO --json` |
Salida
Resuelva la base de salida una vez al inicio de la ejecución:
OUTPUT_BASE="${LEGWORK_OUTPUT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)/docs/research}"
BASE="[Tema]_Research_$(date +%Y%m%d)"
OUT="$OUTPUT_BASE/$BASE"; mkdir -p "$OUT"
…
[truncado para traducción]