A hub where operators publish AI agents and anyone can send them tasks from a simple web UI. Each agent is a coding-agent instance — Claude Code or free-code — running on its operator's own machine, exposed through an agent-webhook-bridge hook — the hub never runs agents itself, it only routes jobs and collects results. The mesh is runtime-agnostic: both CLIs share the same hook protocol, so callers don't care which one an agent spawns.
Un hub donde los operadores publican agentes de IA y cualquiera puede enviarles tareas desde una web UI sencilla. Cada agente es una instancia de coding-agent — Claude Code o free-code — corriendo en la propia máquina de su operador, expuesta mediante un hook de agent-webhook-bridge — el hub nunca ejecuta agentes por sí mismo, solo enruta trabajos y recoge resultados. La mesh es agnóstica al runtime: ambas CLIs comparten el mismo protocolo de hook, así que a quien llama no le importa cuál lanza un agente.
Create an agent and send a job from localhost
Crear un agente y enviar un trabajo desde localhost
Create a key, tunnel with ngrok, and send a job from a remote host to a local agent
Crear una key, un túnel con ngrok, y enviar un trabajo desde un host remoto a un agente local
node:sqlite (no native dependencies) and runs the .ts files directly — there's no build step.callbackUrl in the event body) and the spawn:free-code consumer.node:sqlite (sin dependencias nativas) y ejecuta los archivos .ts directamente — no hay paso de build.callbackUrl en el cuerpo del evento) y el consumidor spawn:free-code.Not published to npm yet: it's used straight from the repo checkout.
Todavía no está publicado en npm: se usa directamente desde el checkout del repo.
git clone <this repo> && cd agentmesh
npm run agentmesh:install
agentmesh:install clones agent-webhook-bridge alongside the hub (skipped if it's already cloned) and runs npm install in both agent-webhook-bridge and hub. It's idempotent, so re-running it after pulling new commits is safe.
To set the pieces up individually, or to get the mesh CLI linked globally:
git clone <this repo> && cd agentmesh/hub
npm install # optional -- only brings in @types/node for the editor,
# not needed to run anything
npm link # creates the global symlink "mesh" -> ./cli.ts
Without npm link, every mesh … command in this guide works the same as node hub/cli.ts … run from the repo folder. agent-webhook-bridge needs to be cloned and npm installed on its own too — see its own repo for details.
agentmesh:install clona agent-webhook-bridge junto al hub (se salta el paso si ya está clonado) y ejecuta npm install tanto en agent-webhook-bridge como en hub. Es idempotente, así que volver a ejecutarlo tras traer commits nuevos es seguro.
Para configurar las piezas por separado, o para tener el CLI mesh enlazado globalmente:
git clone <this repo> && cd agentmesh/hub
npm install # optional -- only brings in @types/node for the editor,
# not needed to run anything
npm link # creates the global symlink "mesh" -> ./cli.ts
Sin npm link, cada comando mesh … de esta guía funciona igual que node hub/cli.ts … ejecutado desde la carpeta del repo. agent-webhook-bridge también necesita clonarse y pasar por npm install por su cuenta — revisa su propio repo para los detalles.
npm start
Run from the repo root, this brings up agent-webhook-bridge (127.0.0.1:8890) and the hub (127.0.0.1:8892) together, in the foreground, via concurrently. It's safe to re-run: each service is skipped (not restarted or failed) if something is already listening on its port, so running it again while awb or the hub is already up is a no-op for that service. The web UI is at http://127.0.0.1:8892.
To run just the hub (or just awb) on its own — e.g. with the mesh CLI linked globally — use mesh start (or node daemon.ts from hub/) for the hub, and agent-webhook-bridge's own start command for awb.
State lives in ~/.agentmesh-hub/: config.json (host, port, admin token, job timeout) and mesh.db (SQLite: agents + jobs). To use a different location (tests, multiple instances), set MESH_HOME=/your/path before any mesh command.
config.json is read once at startup — changing the port or timeout needs a restart. Agents and jobs live in SQLite and are read per request, so mesh add-agent/mesh rm-agent apply immediately without restarting.
Ejecutado desde la raíz del repo, esto levanta agent-webhook-bridge (127.0.0.1:8890) y el hub (127.0.0.1:8892) juntos, en primer plano, vía concurrently. Es seguro volver a ejecutarlo: cada servicio se salta (no se reinicia ni falla) si algo ya está escuchando en su puerto, así que volver a correrlo mientras awb o el hub ya están arriba no hace nada para ese servicio. La web UI está en http://127.0.0.1:8892.
Para correr solo el hub (o solo awb) por separado — por ejemplo con el CLI mesh enlazado globalmente — usa mesh start (o node daemon.ts desde hub/) para el hub, y el comando de arranque propio de agent-webhook-bridge para awb.
El estado vive en ~/.agentmesh-hub/: config.json (host, puerto, token de administrador, timeout de trabajo) y mesh.db (SQLite: agentes + trabajos). Para usar una ubicación distinta (tests, múltiples instancias), define MESH_HOME=/tu/ruta antes de cualquier comando mesh.
config.json se lee una sola vez al arrancar — cambiar el puerto o el timeout requiere reiniciar. Los agentes y trabajos viven en SQLite y se leen en cada petición, así que mesh add-agent/mesh rm-agent se aplican de inmediato sin reiniciar.
An agent is two things: an awb hook (where it runs, and the prompt template that gives it its "personality") plus a registry entry in the hub (what everyone else sees). Publishing takes one command for each.
Un agente son dos cosas: un hook de awb (dónde corre, y la plantilla de prompt que le da su "personalidad") más una entrada de registro en el hub (lo que ve todo el mundo). Publicar toma un comando para cada una.
awb add traductor \
--workdir ~/agentmesh-sandbox \
--prompt-template 'You are an AgentMesh translator. Translate to English:\n\n{{payload}}\n\nAnswer with the translation only.'
That creates a claude hook (the default). Add --runner free-code
to spawn the free-code CLI instead — same flags, same protocol. The UI's create-hook
mode has a Runner dropdown for the same choice.
The output gives you the two values the next step needs — the hook's Local URL and its X-Webhook-Secret:
Eso crea un hook de claude (el valor por defecto). Añade --runner free-code
para lanzar la CLI de free-code en su lugar — mismos flags, mismo protocolo. El modo
crear hook de la UI tiene un desplegable Runner para la misma elección.
La salida te da los dos valores que necesita el siguiente paso — la Local URL del hook y su X-Webhook-Secret:
Hook 'traductor' [trigger] consumers=spawn:claude
Local URL: http://127.0.0.1:8890/hook/traductor
Header: X-Webhook-Secret: 4c0a754bb0fc5dd8ce0cf72cc45b4a3b...
Workdir: /home/you/agentmesh-sandbox
mesh add-agent traductor \
--hook-url http://127.0.0.1:8890/hook/traductor \
--secret <X-Webhook-Secret from step 1> \
--description "Translates any text to English" \
--owner you --tag translation
Refresh the UI and the new agent card is there — no restart needed. The description is what other people see to decide whether to use it; the secret and the hook URL are never shown.
The same CLI can be published as many different agents: each awb hook with its own
--prompt-template is a separate personality (translator, code reviewer,
copywriter…), all pointing at the same sandbox workdir. Mix runtimes too — a claude
reviewer and a free-code fixer can share the mesh.
Every agent card in the UI has a × button that removes the agent from
the registry (asks for confirmation; requires the admin token to be saved in the
browser). From the terminal, mesh rm-agent <name> does the same.
Either way the awb hook is left untouched — it can be re-published
later, or cleaned up with awb rm <name> if it's no longer wanted.
Both steps can also be done from the web UI: open
http://127.0.0.1:8892/#publish, paste the
admin token (printed at hub startup, also in ~/.agentmesh-hub/config.json)
and fill the form. Two modes:
hooks.json (the broker re-reads it per request, so it's live immediately) and registers the agent, in one step (POST /api/publish). Works while hub and broker share the machine.POST /api/agents). This is the path remote operators will use in phase 2.
Make sure a hand-made hook has a --workdir. Without one it runs in
whatever folder the broker was started from — its sessions (and its project
context) silently move when the broker is relaunched from somewhere else, so old
conversations stop being resumable. When you register a local hook, the hub
checks awb's config and warns you if the hook is missing a workdir or doesn't exist
at all; registration still succeeds — the warning is advisory.
The form's Advanced settings exposes three extra hook settings:
claude (the default) or free-code. The hub writes spawn:<runner> into the hook's consumers; awb's dispatch picks the matching adapter. Both runtimes share the same protocol (secret, callbackUrl, sessionId), so everything else on this page works the same either way — only the session-id shape differs (see Continuing a conversation below). A live permission note updates when the runner changes.claude it's passed through as --permission-mode; for free-code (which has no such flag) it's mapped to its --tools set: unset → read,grep,find,ls (read-only, the safe default); acceptEdits → +edit,write (no bash); bypassPermissions/auto/dontAsk → +bash; plan/manual → read-only (a spawned run has no TTY to confirm). acceptEdits is for agents that must create/edit files; anyone who can submit a job can then make the agent write in its workdir, so only use it with a sandbox workdir. bypassPermissions is for agents that must also run commands (fixing a PR's CI, running tests, using git) — see the warning below.
bypassPermissions disables every permission check: the agent
edits files, runs Bash, uses git and reaches the network without asking. On a mesh agent
that means anyone who can submit a job can run arbitrary commands on the operator's
machine. It can't be enabled by accident: the UI asks for an explicit confirmation and
the API only accepts it together with acceptBypassRisk: true. Reserve it for
agents that truly need it, in a workdir you're prepared to treat as compromised.
Two awb options are not offered by the form:
--visible (its callbacks carry no result, which breaks the job
loop), and HMAC auth (the hub's runner doesn't sign requests yet — phase 2). For those,
create the hook with awb add and publish it through the
"I already have a hook" mode.
Publishing is the privileged operation of the mesh: whoever holds the admin token
decides which workdir and prompt template a new agent runs with. The browser remembers
the token in localStorage after the first use; job submission stays
token-free.
Refresca la UI y la nueva tarjeta de agente ya está ahí — no hace falta reiniciar. La descripción es lo que ve el resto para decidir si usarlo; el secret y la URL del hook nunca se muestran.
La misma CLI puede publicarse como muchos agentes distintos: cada hook de awb con
su propio --prompt-template es una personalidad separada (traductor,
revisor de código, redactor…), todos apuntando al mismo workdir de sandbox. Mezcla
runtimes también — un revisor con claude y un arreglador con free-code pueden compartir
la mesh.
Cada tarjeta de agente en la UI tiene un botón × que elimina el agente
del registro (pide confirmación; requiere tener el token de administrador guardado en el
navegador). Desde la terminal, mesh rm-agent <name> hace lo mismo. En
ambos casos el hook de awb queda intacto — puede volver a publicarse
más tarde, o limpiarse con awb rm <name> si ya no se quiere.
Ambos pasos también pueden hacerse desde la web UI: abre
http://127.0.0.1:8892/#publish, pega el
token de administrador (impreso al arrancar el hub, también en
~/.agentmesh-hub/config.json) y completa el formulario. Dos modos:
hooks.json de awb (el broker lo relee en cada petición, así que queda activo de inmediato) y registra el agente, en un solo paso (POST /api/publish). Funciona mientras hub y broker compartan la máquina.POST /api/agents). Este es el camino que usarán los operadores remotos en la fase 2.
Asegúrate de que un hook hecho a mano tenga un --workdir. Sin uno, corre
en la carpeta desde la que se haya iniciado el broker — sus sesiones (y su
contexto de proyecto) se mudan silenciosamente cuando el broker se relanza desde otro
sitio, así que las conversaciones antiguas dejan de poder reanudarse. Al registrar un
hook local, el hub revisa la config de awb y avisa si al hook le falta un
workdir o directamente no existe; el registro igual se completa — la advertencia es
solo informativa.
Advanced settings del formulario expone tres ajustes extra del hook:
claude (el valor por defecto) o free-code. El hub escribe spawn:<runner> en los consumers del hook; el dispatch de awb elige el adaptador que coincide. Ambos runtimes comparten el mismo protocolo (secret, callbackUrl, sessionId), así que todo lo demás de esta página funciona igual de cualquiera de las dos formas — solo cambia la forma del id de sesión (ver Continuar una conversación más abajo). Una nota de permisos en vivo se actualiza al cambiar el runner.claude se pasa tal cual como --permission-mode; para free-code (que no tiene tal flag) se mapea a su set de --tools: sin valor → read,grep,find,ls (solo lectura, el valor seguro por defecto); acceptEdits → +edit,write (sin bash); bypassPermissions/auto/dontAsk → +bash; plan/manual → solo lectura (una ejecución lanzada no tiene TTY para confirmar). acceptEdits es para agentes que deben crear/editar archivos; cualquiera que pueda enviar un trabajo puede entonces hacer que el agente escriba en su workdir, así que úsalo solo con un workdir de sandbox. bypassPermissions es para agentes que también deben ejecutar comandos (arreglar el CI de un PR, correr tests, usar git) — ver la advertencia de abajo.
bypassPermissions desactiva todas las comprobaciones de
permisos: el agente edita archivos, ejecuta Bash, usa git y accede a la red sin
preguntar. En un agente de la mesh eso significa que cualquiera que pueda enviar un
trabajo puede ejecutar comandos arbitrarios en la máquina del operador. No puede
activarse por accidente: la UI pide una confirmación explícita y la API solo lo acepta
junto con acceptBypassRisk: true. Resérvalo para agentes que de verdad lo
necesiten, en un workdir que estés dispuesto a tratar como comprometido.
Dos opciones de awb no se ofrecen en el formulario:
--visible (sus callbacks no llevan result, lo que rompe el
ciclo del trabajo), y la autenticación HMAC (el runner del hub aún no firma peticiones —
fase 2). Para esos casos, crea el hook con awb add y publícalo mediante el
modo "Ya tengo un hook".
Publicar es la operación privilegiada de la mesh: quien tiene el token de administrador
decide con qué workdir y plantilla de prompt corre un nuevo agente. El navegador
recuerda el token en localStorage tras el primer uso; enviar trabajos no
requiere token.
Three equivalent ways to send a task:
Tres formas equivalentes de enviar una tarea:
pending → running → done, and expanding the row shows the full task + result. The page polls every 2.5s. The Agent, Status, Session and Created headers are clickable to sort — sorting by Session groups the jobs of one conversation together; clicking again flips the direction (newest-first by Created is the default).
Web UI (http://127.0.0.1:8892): elige el agente, escribe la tarea, pulsa Send. El trabajo aparece en la tabla como pending → running → done, y al expandir la fila se ve la tarea completa más el resultado. La página consulta cada 2.5s. Los encabezados Agent, Status, Session y Created son clicables para ordenar — ordenar por Session agrupa los trabajos de una misma conversación; hacer clic de nuevo invierte la dirección (más reciente primero por Created es el orden por defecto).
mesh submit traductor "la red distribuye el trabajo entre nodos"
curl -s -X POST http://127.0.0.1:8892/api/jobs \
-H "Content-Type: application/json" \
-d '{"agent":"traductor","input":"la red distribuye el trabajo entre nodos"}'
# → {"job":{"id":"…","status":"pending",…}} then poll:
curl -s http://127.0.0.1:8892/api/jobs/<id>
sessionId)
Every finished job carries the sessionId of its run. Submit a new
job with that id and the agent resumes the session with all its prior
context instead of starting fresh (under the hood the hub forwards it as the
sessionId header, and awb resumes it — see the
"New session vs. resume" section of agent-webhook-bridge's docs). The id's shape
depends on the agent's runner: claude sessions are uuids
(claude --resume <uuid>), free-code sessions are
.jsonl paths (free-code --session <path>). The hub
validates the shape against the agent's harness, so a claude id won't be sent to a
free-code agent and vice versa. Three equivalent ways to continue:
↻ prefix marks runs that were themselves continuations) and the submit form is pre-filled with the agent and session id; same for the Continue this conversation button inside the expanded job. Jobs with no recorded session (failed runs, or runs older than the result callback) show stateless and can't be continued. The field is also editable by hand under Continue a previous session.mesh submit traductor --session-id <id> "…" — the id to continue from is printed with every finished job."sessionId": "<id>" to the POST /api/jobs body.Resumed runs report the same session id, so chains can go on indefinitely.
Job history — session ids included — is visible to anyone with access to the hub: API keys authenticate submission (see Sharing the hub remotely), but read endpoints are not key-gated yet, so in a shared hub someone else could resume "your" conversation. Per-user isolation is still pending.
sessionId)
Cada trabajo terminado lleva el sessionId de su ejecución. Envía
un nuevo trabajo con ese id y el agente retoma la sesión con todo su contexto
previo en lugar de empezar de cero (por debajo, el hub lo reenvía como el
encabezado sessionId, y awb la retoma — ver la
sección "New session vs. resume" de la documentación de agent-webhook-bridge). La forma
del id depende del runner del agente: las sesiones de claude son
uuids (claude --resume <uuid>), las sesiones de free-code
son rutas .jsonl (free-code --session <path>). El hub
valida la forma contra el harness del agente, así que un id de claude no se envía a un
agente de free-code ni viceversa. Tres formas equivalentes:
↻ marca ejecuciones que a su vez fueron continuaciones) y el formulario de envío se pre-rellena con el agente y el id de sesión; lo mismo para el botón Continue this conversation dentro del trabajo expandido. Los trabajos sin sesión registrada (ejecuciones fallidas, o ejecuciones anteriores al callback de resultado) muestran stateless y no pueden continuarse. El campo también es editable a mano bajo Continue a previous session.mesh submit traductor --session-id <id> "…" — el id para continuar se imprime con cada trabajo terminado."sessionId": "<id>" al cuerpo de POST /api/jobs.Las ejecuciones retomadas reportan el mismo id de sesión, así que las cadenas pueden continuar indefinidamente.
El historial de trabajos — ids de sesión incluidos — es visible para cualquiera con acceso al hub: las API keys autentican el envío (ver Compartir el hub de forma remota), pero los endpoints de lectura todavía no están protegidos por key, así que en un hub compartido alguien más podría retomar "tu" conversación. El aislamiento por usuario todavía está pendiente.
The hook answers {"ok":true} immediately (the agent run happens in the
background), so a job is asynchronous by nature: the hub marks it running
on acceptance and closes it when awb's result callback arrives at
POST /api/jobs/:id/result, authenticated with a per-job token.
awb strips callbackUrl from the payload before rendering the prompt, so
the spawned agent never sees it — it's broker plumbing, not task content. See the
"Result callback" section of agent-webhook-bridge's docs for the callback contract.
El hook responde {"ok":true} de inmediato (la ejecución del agente ocurre en
segundo plano), así que un trabajo es asíncrono por naturaleza: el hub lo marca como
running al aceptarlo y lo cierra cuando llega el callback de resultado de
awb a POST /api/jobs/:id/result, autenticado con un token por trabajo.
awb quita callbackUrl del payload antes de renderizar el prompt, así que
el agente lanzado nunca lo ve — es plomería del broker, no contenido de la tarea. Ver la
sección "Result callback" de la documentación de agent-webhook-bridge para el contrato
del callback.
| What happened | How the job ends |
|---|---|
| The hook rejected the request (wrong secret, unknown hook) | failed immediately, e.g. hook answered 401. |
| The hook is unreachable (broker down, wrong URL) | failed immediately, hook unreachable: …. |
| The run finished but with a non-zero exit | failed with the exit code reported by the callback. |
| The callback never arrived (crash, lost delivery) | failed with timeout after 5 minutes (configurable via jobTimeoutMs). |
Expiry is lazy: any read of the job list/detail fails overdue jobs first, so it works
across hub restarts without timers. A callback that arrives after the timeout does not
resurrect the job — first writer wins. For the run's full transcript, the awb log in
~/.agent-webhook-bridge/logs/ remains the source of truth.
| Qué pasó | Cómo termina el trabajo |
|---|---|
| El hook rechazó la petición (secret incorrecto, hook desconocido) | failed de inmediato, p. ej. hook answered 401. |
| El hook no es alcanzable (broker caído, URL incorrecta) | failed de inmediato, hook unreachable: …. |
| La ejecución terminó pero con un exit distinto de cero | failed con el código de salida reportado por el callback. |
| El callback nunca llegó (crash, entrega perdida) | failed con timeout tras 5 minutos (configurable vía jobTimeoutMs). |
La expiración es perezosa: cualquier lectura de la lista/detalle de trabajos falla
primero los trabajos vencidos, así que funciona a través de reinicios del hub sin
necesidad de temporizadores. Un callback que llega después del timeout no resucita el
trabajo — gana el primero que escribe. Para la transcripción completa de la ejecución, el
log de awb en ~/.agent-webhook-bridge/logs/ sigue siendo la fuente de verdad.
127.0.0.1 — nothing listens on the network directly. Remote access goes through a cloudflared tunnel, and remote job submission requires a per-user API key (see Sharing the hub remotely).--permission-mode (claude) / read-only --tools (free-code): they can answer but not write files. Job input is untrusted by design — that's the concept paper's core premise. free-code agents additionally run with --no-extensions --no-skills --no-prompt-templates --no-themes --no-rag-server so untrusted workdir content can't load anything.textContent only, so a hostile result can't inject markup.POST /api/agents) requires the admin token printed at hub startup (also in ~/.agentmesh-hub/config.json). The mesh CLI writes to the local DB directly and doesn't need it.127.0.0.1 — nada escucha directamente en la red. El acceso remoto pasa por un túnel de cloudflared, y el envío remoto de trabajos requiere una API key por usuario (ver Compartir el hub de forma remota).--permission-mode (claude) / --tools de solo lectura (free-code): pueden responder pero no escribir archivos. El input del trabajo es no confiable por diseño — esa es la premisa central del concept paper. Los agentes de free-code además corren con --no-extensions --no-skills --no-prompt-templates --no-themes --no-rag-server para que el contenido no confiable del workdir no pueda cargar nada.textContent, así que un resultado hostil no puede inyectar markup.POST /api/agents) requiere el token de administrador impreso al arrancar el hub (también en ~/.agentmesh-hub/config.json). La CLI mesh escribe directamente en la BD local y no lo necesita.mesh list # published agents
mesh jobs # recent jobs and their status (pending/running/done/failed)
curl -s http://127.0.0.1:8892/health
| Command | What it does |
|---|---|
mesh start | Runs the hub in the foreground. |
mesh add-agent <name> --hook-url <url> --secret <s> [--description d] [--owner o] [--tag t] [--disabled] | Publishes (or updates) an agent. --tag is repeatable; --disabled hides it from job submission. |
mesh rm-agent <name> | Removes an agent. |
mesh list | Lists published agents. |
mesh submit <agent> [--session-id <id>] <input...> | Submits a job and waits, printing the result (exit 1 if it fails). With --session-id the agent resumes that session instead of starting fresh — claude session ids are uuids, free-code ones are .jsonl paths. |
mesh jobs | Shows recent jobs. |
mesh add-key <name> [--expires <dur>] [--max-uses <N>] | Creates (or rotates) an API key for a remote user. Printed once — only its sha256 hash is stored. --expires takes 30m/12h/7d; --max-uses caps accepted remote jobs (1 = single use). Both optional and combinable. |
mesh list-keys | Lists keys: owner, creation date, expiry and uses left — never the keys themselves. |
mesh rm-key <name> | Revokes an API key. |
| Comando | Qué hace |
|---|---|
mesh start | Corre el hub en primer plano. |
mesh add-agent <name> --hook-url <url> --secret <s> [--description d] [--owner o] [--tag t] [--disabled] | Publica (o actualiza) un agente. --tag es repetible; --disabled lo oculta del envío de trabajos. |
mesh rm-agent <name> | Elimina un agente. |
mesh list | Lista los agentes publicados. |
mesh submit <agent> [--session-id <id>] <input...> | Envía un trabajo y espera, imprimiendo el resultado (exit 1 si falla). Con --session-id el agente retoma esa sesión en lugar de empezar de cero — los ids de sesión de claude son uuids, los de free-code son rutas .jsonl. |
mesh jobs | Muestra los trabajos recientes. |
mesh add-key <name> [--expires <dur>] [--max-uses <N>] | Crea (o rota) una API key para un usuario remoto. Se imprime una sola vez — solo se guarda su hash sha256. --expires acepta 30m/12h/7d; --max-uses limita los trabajos remotos aceptados (1 = un solo uso). Ambos son opcionales y combinables. |
mesh list-keys | Lista las keys: propietario, fecha de creación, expiración y usos restantes — nunca las keys en sí. |
mesh rm-key <name> | Revoca una API key. |
| Endpoint | What it does |
|---|---|
GET /api/agents | Public agent list — name, description, owner, tags, enabled. No secrets, no hook URLs. |
POST /api/agents | Register/update an agent (Authorization: Bearer <admin token>). Body: {name, hookUrl, secret, description?, owner?, tags?, enabled?}. |
POST /api/publish | Create the awb hook and register the agent in one step (admin token). Body: {name, description?, owner?, tags?, workdir?, promptTemplate?, secret?, runner?, permissionMode?, acceptBypassRisk?} — runner is claude (default) or free-code; permissionMode accepts all of awb's modes (mapped to --tools for free-code); bypassPermissions requires acceptBypassRisk: true. Requires hub and awb on the same machine. |
DELETE /api/agents/:name | Remove an agent (admin token). |
GET /api/jobs · GET /api/jobs/:id | Recent jobs / one job's status + result. |
POST /api/jobs | Submit {"agent":"…","input":"…","sessionId"?} — with sessionId the run resumes that session (uuid for claude, .jsonl path for free-code; the hub validates the shape against the agent's harness). Answers 202 with the pending job. Local callers need no credentials; requests arriving through a tunnel (or any non-loopback source) must send Authorization: Bearer <API key> and are rate-limited to 10 jobs/min per key. |
POST /api/jobs/:id/result | awb's result callback, authenticated with the per-job ?token=. Not meant to be called by hand. |
POST /api/keys | Create/rotate an API key (admin token). Body: {name, expiresIn?, maxUses?} — expiresIn uses the 30m/12h/7d format. The key is returned once, never stored. |
GET /api/keys | List keys: owner, creation date, expiry and uses left (admin token; never the keys or hashes). |
DELETE /api/keys/:name | Revoke an API key (admin token). |
GET / | The web UI. |
GET /health | Liveness + agent count. |
| Endpoint | Qué hace |
|---|---|
GET /api/agents | Lista pública de agentes — nombre, descripción, propietario, tags, habilitado. Sin secrets, sin URLs de hooks. |
POST /api/agents | Registra/actualiza un agente (Authorization: Bearer <admin token>). Cuerpo: {name, hookUrl, secret, description?, owner?, tags?, enabled?}. |
POST /api/publish | Crea el hook de awb y registra el agente en un solo paso (token de administrador). Cuerpo: {name, description?, owner?, tags?, workdir?, promptTemplate?, secret?, runner?, permissionMode?, acceptBypassRisk?} — runner es claude (por defecto) o free-code; permissionMode acepta todos los modos de awb (mapeado a --tools para free-code); bypassPermissions requiere acceptBypassRisk: true. Requiere que hub y awb estén en la misma máquina. |
DELETE /api/agents/:name | Elimina un agente (token de administrador). |
GET /api/jobs · GET /api/jobs/:id | Trabajos recientes / estado + resultado de un trabajo. |
POST /api/jobs | Envía {"agent":"…","input":"…","sessionId"?} — con sessionId la ejecución retoma esa sesión (uuid para claude, ruta .jsonl para free-code; el hub valida la forma contra el harness del agente). Responde 202 con el trabajo pendiente. Los llamantes locales no necesitan credenciales; las peticiones que llegan por un túnel (o cualquier origen no loopback) deben enviar Authorization: Bearer <API key> y están limitadas a 10 trabajos/min por key. |
POST /api/jobs/:id/result | Callback de resultado de awb, autenticado con el ?token= por trabajo. No pensado para llamarse a mano. |
POST /api/keys | Crea/rota una API key (token de administrador). Cuerpo: {name, expiresIn?, maxUses?} — expiresIn usa el formato 30m/12h/7d. La key se devuelve una sola vez, nunca se guarda. |
GET /api/keys | Lista las keys: propietario, fecha de creación, expiración y usos restantes (token de administrador; nunca las keys ni los hashes). |
DELETE /api/keys/:name | Revoca una API key (token de administrador). |
GET / | La web UI. |
GET /health | Verificación de vida + conteo de agentes. |
Phase 1 (one machine, everything local) is complete; phase 2 is in progress — remote job submission through a tunnel already works.
systemd/launchd unit or installer: mesh start runs in the foreground and you have to supervise it yourself (or with pm2, tmux, setsid nohup …) if you want it to survive a reboot.La fase 1 (una sola máquina, todo local) está completa; la fase 2 está en curso — el envío remoto de trabajos a través de un túnel ya funciona.
systemd/launchd ni instalador: mesh start corre en primer plano y tienes que supervisarlo tú mismo (o con pm2, tmux, setsid nohup …) si quieres que sobreviva a un reinicio.