CommunityProgramación y desarrollogithub.com

aipoch/remote-compute-ssh

Evalúa y usa cómputo remoto SSH antes de decidir dónde ejecutar GPU, alta memoria, trabajos paralelos, por lotes, inferencia de modelos, bioinformática u otros trabajos científicos de larga duración; admite comandos remotos cortos y trabajos asíncronos con recolección y análisis automáticos.

¿Qué es remote-compute-ssh?

Este skill permite a agentes de IA evaluar y ejecutar cómputo remoto a través de SSH, incluyendo la ejecución directa de comandos y la presentación de trabajos en sistemas Slurm. Proporciona una API completa que cubre desde el listado de hosts y creación de identificadores, hasta la ejecución de comandos remotos cortos (`callCommand`) y el ciclo de vida completo de trabajos asíncronos: envío (`submitJob`), guardado del `job_id`, lectura de instantáneas no bloqueantes, recolección, análisis y publicación de artefactos. Es útil para desarrolladores y científicos que necesitan distribuir cargas de trabajo intensivas (GPU, alta memoria, paralelismo, bioinformática) en clústeres o servidores remotos, con soporte para Slurm y recolección automática de resultados. El skill está diseñado para plataformas que implementan `host.compute` en el kernel de control REPL (como Open-Science o entornos similares), y no debe ser usado desde kernels de datos (Python/R). Se basa en la documentación SKILL.md y en la API de Remote Compute SSH.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/aipoch/open-science/tree/HEAD/resources/skills/remote-compute-ssh

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Este skill cubre cómputo remoto sobre SSH, incluyendo ejecución directa y envío a Slurm: listado de hosts, creación de identificadores, ejecución de comandos remotos cortos (callCommand), lectura/escritura de documentos de conocimiento del host, y el ciclo de vida completo de trabajos asíncronos — enviar → guardar job_id → leer instantáneas no bloqueantes por ese ID → recolectar → turno de análisis → publicar artefactos.

Dónde se ejecuta host.compute: host.compute vive SOLO en el kernel REPL del plano de control — ejecute cada ejemplo a continuación con la herramienta repl_execute (JavaScript), el mismo kernel que aloja host.mcp. Los kernels de datos python/r NO tienen host.compute (SSH y aprobaciones permanecen fuera del espacio de trabajo tipo sandbox); llamarlo desde una celda python/r fallará con host.compute is undefined.

Elegir una ubicación de ejecución

Solo los Hosts de Cómputo habilitados para esta Sesión son visibles o invocables. Descúbralos en un único catálogo; cada entrada tiene un rol selected o available. Un grupo seleccionado no vacío es una instrucción de ejecución: ejecute el trabajo respaldado por herramientas en uno o más hosts seleccionados según lo requiera la tarea. El grupo no tiene prioridad y no implica programación automática en múltiples hosts. Si ningún host está seleccionado, elija entre las entradas disponibles. Lea details() solo para candidatos que necesiten una evaluación más detallada.

Nunca adivine ni reutilice un id de proveedor ausente del catálogo. Que un usuario nombre un host deshabilitado no lo hace invocable; explique que primero debe ser habilitado para esta Sesión. Si ningún host elegible es utilizable, explique el bloqueo y pregunte al usuario cómo proceder.

const hosts = await host.compute.listHosts()
const selectedHosts = hosts.filter((host) => host.role === 'selected')
const candidates = selectedHosts.length > 0 ? selectedHosts : hosts

Cada elemento de la lista es un resumen compacto con provider_id, display_name, shape, execution_mode, status y role (last_probe_ok, probe_failed o not_probed). last_probe_ok significa que la sonda persistida más reciente tuvo éxito; no afirma conectividad en vivo. Los documentos de conocimiento y las instantáneas de sonda de recursos se excluyen deliberadamente de los resultados de descubrimiento.

Referencia de la API

// Listar los hosts habilitados de esta Sesión como un catálogo compacto con roles
const hosts = await host.compute.listHosts()

// Los nombres de descubrimiento por compatibilidad siguen disponibles; ambos siguen ocultando hosts deshabilitados.
const visibleHosts = await host.compute.listRegistered()
const selectedHosts = await host.compute.listPreferred()

// Crear un identificador para un host específico (sin llamada de red)
const c = host.compute.create('ssh:<alias>')

// Ejecutar un comando remoto corto (lanza error en caso de approval_denied / host_unreachable / timeout)
const result = await c.callCommand('<comando shell>', '<intención de una línea para la tarjeta de aprobación>', {
  loginShell: true, // predeterminado: true — ejecuta perfiles de inicio de sesión, luego ~/.bashrc legible, antes de este comando
  timeoutSeconds: 60 // opcional — el host aplica su propio valor predeterminado (60s) si se omite
})
// result → { exit_code, stdout, stderr, truncated }

// Leer las instrucciones de operación persistidas y la instantánea independiente de la sonda de recursos.
// doc es siempre el texto exacto guardado (incluyendo '' antes de que se guarden las instrucciones).
// probe es explícitamente null si este host nunca ha sido sondado.
const info = await host.compute.details('ssh:<alias>', { mode: 'read' })

// Añadir una nota al documento de conocimiento del host persistido (escritura del agente; límite de 32 KB).
// Append cambia solo doc; nunca copia ni cambia las observaciones de la sonda.
await host.compute.details('ssh:<alias>', {
  mode: 'append',
  text: '\n## Nota\naprendido X el <fecha>'
})

// Alternativamente, reemplazar todo el documento de conocimiento del host. Lea de nuevo antes de reemplazar,
// especialmente si añadió arriba: oldText debe coincidir exactamente con el documento persistido.
const latest = await host.compute.details('ssh:<alias>', { mode: 'read' })
await host.compute.details('ssh:<alias>', {
  mode: 'replace',
  text: '<nuevo documento completo>',
  oldText: latest.doc
})

Trate doc como instrucciones de operación y conocimiento duradero del host. Trate probe como una observación con fecha: los valores de recursos pueden cambiar, y detectar un planificador no autoriza a enviar un trabajo ni seleccionar una cuenta, partición o cola. En caso de un error de desajuste de documento o details_conflict, lea de nuevo y combine su borrador con el documento más reciente antes de reintentar. Una actualización de sonda solo de recursos no cambia doc ni causa un conflicto de reemplazo. Después de escribir, lea de nuevo para verificar los contenidos guardados. Un resultado exitoso de append o replace es solo { ok: true }. El resultado de escritura no contiene doc ni probe; siempre lea de nuevo para verificar el doc persistido exacto en lugar de leer campos del resultado de escritura.

Con loginShell: true, los perfiles de inicio de sesión Bash remotos se ejecutan primero y luego Open-Science intenta obtener ~/.bashrc cuando es legible. Un .bashrc puede deliberadamente retornar temprano para shells no interactivas, por lo que las variables declaradas después de tal guardia no están disponibles. Un .bashrc faltante no tiene efecto. Establezca loginShell: false para ejecutar el comando sin ninguno de los pasos de inicialización. Las fallas de inicialización se reportan a través del comportamiento normal de resultado/error del comando.

Referencia de la API (trabajos asíncronos)

Use submitJob para cómputos de larga duración (minutos a horas). Retorna inmediatamente con un job_id; el trabajo se ejecuta en el host remoto en segundo plano. Cuando el trabajo finaliza, la aplicación recolecta automáticamente las salidas e inicia un nuevo turno de análisis si aún no ha leído el resultado terminal. Guarde el job_id exacto del resultado del envío en su contexto de trabajo; intencionalmente no hay un escaneo histórico de Trabajos para redescubrirlo. Las lecturas de estado y resultado usan solo ese ID guardado y retornan instantáneas locales no bloqueantes.

Para una entrada local, src es relativo al espacio de trabajo de la Sesión del Agente—el mismo espacio de trabajo usado por herramientas de escritura de archivos. Escriba un script o una entrada pequeña generada allí, luego pase su ruta relativa. Open-Science captura las entradas aceptadas antes de la aprobación y el envío. No pase rutas absolutas locales arbitrarias ni copie archivos en directorios notebooks/... administrados por la aplicación. Una src absoluta es válida solo cuando es la ruta exacta retornada por host.artifactPath(versionId) o una ruta de entrada de Sesión registrada ya proporcionada en el contexto del Notebook.

// Reutilice los `candidates` seleccionados arriba del catálogo de la Sesión.

// Enviar un trabajo no bloqueante — retorna inmediatamente después de que el usuario aprueba.
// El modo de ejecución configurado del Host de Cómputo selecciona SSH directo o Slurm.
const c = host.compute.create('ssh:<alias>')
const job = await c.submitJob(
  '<intención de una línea para la tarjeta de aprobación>', // mostrado en la tarjeta de aprobación
  '<comando shell>', // comando a ejecutar remotamente
  {
    environment: 'protein-gpu', // opcional nombre lógico; ver Activación de entorno abajo
    timeoutSeconds: 3600, // opcional; predeterminado 24 h, máximo 7 días
    inputs: [
      { src: 'in.dat', dstFilename: 'in.dat' }, // preparar un archivo del espacio de trabajo de la Sesión del Agente
      { remotePath: 'ssh:<alias>/<ruta_abs>' } // enlazar un archivo remoto (sin transferencia)
    ],
    outputs: [
      '*.result', // destacado (visibilidad predeterminada)
      { glob: '*.json', visibility: 'featured' }, // explícitamente destacado
      { glob: '*.log', visibility: 'hidden' }, // oculto (diagnóstico, no mostrado en la tarjeta)
      { glob: 'checkpoints/**', residency: 'remote' } // dejar en remoto — registrado en left_on_remote
    ],
    harvest: {
      exclude: ['work/**'], // nunca recolectar estas rutas
      maxFileMb: 100, // máximo duro por archivo (100 MiB)
      maxTotalMb: 500 // máximo duro por trabajo, incluyendo stdout/stderr (500 MiB)
    }
  }
)
// job → { job_id, provider_id, status: 'submitted' | 'queued', remote_workdir }
const savedJobId = job.job_id // retener este id exacto para el paso dependiente posterior
return { ...job, job_id: savedJobId }

Leer una instantánea de Trabajo guardada

Use el ID guardado cuando el estado o resultado del Trabajo sea relevante. .status() y .result() son lecturas locales no bloqueantes en cualquier estado; ninguna espera a que se complete, desencadena SSH o inicia otra recolección. .result() también incluye listas de archivos recolectados. Ambas llamadas reportan follow_up_delivery. Una lectura final de .result() retorna suppressed cuando previene la entrega de respaldo, o committed cuando ese respaldo ya cruzó su umbral de envío. Una instantánea .status() permanece pending porque omite las listas de archivos recolectados. Use el ID exacto del envío en lugar de buscar trabajos antiguos.

const snapshot = await c.attachJob(savedJobId).result()
if (!snapshot.result_final) {
  return {
    job_id: savedJobId,
    status: snapshot.status,
    result_final: false,
    follow_up_delivery: snapshot.follow_up_delivery
  }
}
return snapshot

Trate solo result_final: true como el resultado final. Significa que la respuesta automática está lista: success, failed y timeout aún pueden estar esperando la recolección local, mientras que cancelled y error son finales sin esperar la recolección parcial de salidas. output_files contiene solo archivos realmente disponibles localmente; una lista vacía no prueba que no haya salidas remotas. La aplicación es propietaria del sondeo del proveedor y la recolección en segundo plano. Un resultado final no leído se entrega en un Turno de Agente posterior. Una instantánea final de .result() reporta follow_up_delivery: 'suppressed' cuando suprime ese respaldo, o committed si la entrega automática ya ganó la carrera y sigue siendo autoritativa. .status() nunca consume el resultado completo.

SSH directo o Slurm

El modo de ejecución configurado del Host de Cómputo selecciona cómo se lanza cada trabajo. direct_ssh ejecuta el comando como un proceso desvinculado en el destino SSH. slurm lo envía con sbatch; ponga las directivas #SBATCH requeridas por el clúster al inicio de command. Open-Science es propietario del envío, sondeo de estado del planificador, cancelación y recolección. No llame a sbatch, squeue o scancel alrededor de submitJob usted mismo.

Para un error de estado de Slurm o cancelación fallida, lea Solucion de problemas de Slurm. En ese camino excepcional, compute.callCommand puede inspeccionar el mismo trabajo y sus salidas y realizar la recuperación dentro de la autorización de tarea existente del usuario. Mantenga los envíos ordinarios en la API de Cómputo.

Lea listHosts() para el modo configurado y details() para directivas específicas del proveedor; no intente anular el modo por trabajo ni inferirlo solo de la carga de trabajo. Si Slurm no está disponible o rechaza el script, reporte el error retornado y ej paso concreto siguiente (por ejemplo, añadir una directiva de cuenta o partición). No vuelva a ejecutar silenciosamente la carga de trabajo directamente en un nodo de inicio de sesión.

Open-Science acepta directivas ordinarias de un solo trabajo como partición, cuenta, CPUs, memoria y GPUs. Establezca timeoutSeconds para el tiempo de ejecución de la carga de trabajo. Puede establecer el límite de asignación del planificador con una directiva #SBATCH --time=valor; cuando está ausente, Open-Science deriva un límite de asignación predeterminado de timeoutSeconds. Open-Science es propietario del nombre del trabajo, directorio de trabajo, stdout y stderr. Evite los arreglos de trabajos porque un trabajo de Open-Science rastrea un trabajo del planificador y una recolección de salidas. Envíe trabajos independientes como trabajos separados y use el límite de concurrencia de la Sesión cuando sea necesario.

Para Slurm, solicite recursos con una directiva #SBATCH --opcion=valor por línea (o una bandera sin valor como #SBATCH --exclusive). La opción heredada resources es metadatos descriptivos; no asigna CPUs, memoria o GPUs. timeoutSeconds limita el tiempo de ejecución de la carga de trabajo, no la espera en cola; #SBATCH --time establece el límite de asignación del planificador. Ninguno es una promesa de tiempo de inicio en cola.

Las instantáneas no bloqueantes de status() y result() del trabajo incluyen scheduler_job_id cuando se conoce, error: { code, message } en un error a nivel de trabajo, y last_poll_error cuando la observación o la recuperación del envío necesita atención. Una razón pendiente o una fila de contabilidad retrasada no significa que la carga de trabajo haya fallado. Si un envío no está confirmado, use la identidad del trabajo reportada y los diagnósticos del proveedor antes de decidir si enviar de nuevo; Open-Science no envía automáticamente un duplicado.

Activación de entorno

El valor opcional environment es un nombre lógico, no un comando shell. Open-Science obtiene ~/.open-science/environments/<nombre>.sh antes de la carga de trabajo para trabajos directos y de Slurm. Los nombres son de 1 a 64 letras, números, puntos, guiones bajos o guiones y deben comenzar con una letra o número. El archivo y cada ruta de software/caché que referencia deben ser visibles en el nodo de ejecución.

Si un envío reporta que este archivo de activación falta, cargue el Skill de Configuración de Entorno de Cómputo para preparar instrucciones exactas de configuración, reparación y eliminación para que el usuario o el administrador del host las ejecuten fuera de Open-Science. Valide la activación gestionada por el usuario después de que apliquen el plan, luego reintente. No adivine un nombre de conda, añada una instalación en línea al trabajo científico ni oculte la activación en .bashrc. Omita environment cuando el comando use deliberadamente el entorno predeterminado del host.

Límites de seguridad de recolección

  • Los archivos de salida declarados se seleccionan antes de stdout y stderr; los registros usan el presupuesto restante por trabajo.
  • La aplicación rechaza límites proporcionados por el modelo por encima de 100 MiB por archivo o 500 MiB por trabajo.
  • La recolección también preserva un espacio fijo de 2 GiB de disco local libre. Los archivos que no caben permanecen remotos.

Límites de comportamiento

  • Mientras el trabajo se ejecuta: la conversación está abierta. El usuario puede enviar mensajes; usted puede manejar otras tareas. Cada consulta de estado/resultado retorna inmediatamente con la instantánea local actual.
  • Cuando el trabajo finaliza: si no leyó activamente su resultado terminal, la aplicación inicia un nuevo turno de análisis automáticamente. Usted no desencadena este respaldo.

Verificar estado del trabajo (lectura no bloqueante, para uso informativo)

// Lectura no bloqueante de BD — sin SSH. Úselo si necesita una instantánea de estado a mitad de conversación.
const handle = c.attachJob(job.job_id)
const s = await handle.status()
// s → {
//   job_id, scheduler_job_id?, status, result_final, cancellation?, exit_code,
//   error?, last
// ...

[truncated for translation]

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills relacionados