lamps — la documentación
Una lamp es una carpeta con techo: un manifiesto (lamp.json) que declara lo que el programa puede tocar, y un programa (lamp.syn) que hace un solo trabajo. La ejecutas desde la terminal; tu agente la recibe como herramienta; el runtime hace cumplir el techo. Esta página es todo, en orden: instalar, descargar, ejecutar, actualizar, crear, publicar y las reglas.
1 · Instala el CLI
curl -fsSL https://lamps.sh/install | sh # macOS, Linux
irm https://lamps.sh/install.ps1 | iex # Windows
El script detecta tu sistema, descarga el binario de lamp desde la release de GitHub, verifica su sha256, lo deja en ~/.lamps/bin y agrega esa ruta a tu PATH. Son cuarenta líneas; léelo primero. lamp upgrade avisa si hay una versión nueva y cómo obtenerla.
2 · Pull (descargar una lamp)
lamp pull git official set (github.com/synsema/lamps)
lamp pull owner/repo one lamp per repo: lamp.json at the repo root
lamp pull owner/repo@v1.2.0 a tag; without @, the latest tag (main if none)
lamp pull owner/repo/name MANY lamps per repo: a folder per lamp
lamp pull github.com/owner/repo full URL, same thing
lamp pull ./my-lamp a local folder
lamp add <ref> alias of pull
pull trae los archivos que el manifiesto lista, uno por uno, directo del host git — sin git, sin archivos comprimidos, sin paso de instalación, sin ejecutar nada. Cada archivo queda con su sha256 registrado en .pulled junto a la lamp. Después corre el linter de promesas: si el código pide algo que el manifiesto nunca declaró, ves BREAKS ITS PROMISE con cada línea, antes de que nada pueda correr.
lamp list
lamp inspect <lamp>
3 · Ejecutar
lamp run git log '{"n": 5}'
lamp git log '{"n": 5}'
LAMP_TIMEOUT=60 lamp run ...
Cada ejecución es un proceso hijo bajo el techo efectivo — manifiesto ∩ proyecto ∩ sesión. La lamp imprime un solo valor JSON. Un rechazo de la política propia de la lamp vuelve como datos; un rechazo del runtime vuelve como entradas DENIED estructuradas con su razón. Eso es el sistema funcionando — nunca reintentes con un techo más amplio. Cada chequeo, concedido o negado, queda en lamp audit.
4 · Actualizar
lamp update <ref>
update es pull del último tag. Deciden los hashes: si ningún archivo cambió, no se escribe nada y nada se cuenta dos veces en el hub — una máquina cuenta una vez por lamp por día, haga lo que haga.
5 · Crea una lamp
Una lamp es una carpeta con dos archivos. Créala, verifícala y ejecútala en local — sin registro, sin cuenta, sin más herramientas que el CLI y el runtime de Synsema.
my-lamp/
├─ lamp.json the manifest
├─ lamp.syn the program (Synsema)
└─ README.md
{
"name": "my-lamp",
"version": "0.1.0",
"description": "One line: what it does and what it refuses.",
"profile": "pure",
"caps": "stdout,env=LAMP_*,net=api.example.com",
"files": ["lamp.syn"],
"tools": [
{ "name": "fetch",
"description": "What an agent reads to decide.",
"parameters": { "type": "object", "properties": { "id": { "type": "integer" } } } }
]
}
- caps — el techo, en sintaxis --cap-set: familia o familia=alcance, separados por comas. stdout · env=LAMP_* · net=host · file.read={root}/* · exec=git · db={root}/* · secret=APP_*. Pide con precisión: el runtime niega, no recorta.
- profile — pure: sin sistema de archivos, sin procesos, sin drivers de base de datos en runtime (dos paredes). native: existen; el techo es la pared. exec exige native.
- name — DEBE ser igual al nombre del repo, o al de la carpeta en un repo con varias lamps. La identidad es la dirección, nunca lo que el json declare.
- tools — nombre, descripción, parámetros con JSON Schema. Exactamente lo que recibe un cliente MCP y lo que escribe un humano.
- files — lo que pull descarga y hashea. Solo rutas dentro de la carpeta.
- {root} y {dir} — se sustituyen al ejecutar, en caps y en el código: el directorio del proyecto y la carpeta de la lamp.
El programa lee cuatro variables de entorno e imprime un solo valor JSON:
LAMP_TOOL "fetch"
LAMP_ARGS {"id": 5}
LAMP_ROOT the project directory
LAMP_DIR the lamp's own folder
intent: "one line, frozen at startup"
require env("LAMP_*")
require net("api.example.com")
task main()
let a be json_decode(env("LAMP_ARGS", "{}"))
let r be http_get("https://api.example.com/item/" + text(floor(number(a["id"]))))
print(json_encode({"ok": r["ok"], "status": r["status"]}))
when env("LAMP_TOOL", "") != ""
main()
test "ids are numbers"
assert_eq(floor(number("5")), 5)
Verifícala antes de que alguien la descargue:
synsema test lamp.syn
lamp inspect ./my-lamp
lamp run ./my-lamp fetch '{"id": 5}'
6 · Publicar (aparecer en el hub)
Publicar es subir a un repo público. No hay cuenta ni login — tu identidad en el host git es tu identidad. La identidad es la dirección, al estilo GitHub: nadie puede publicar como vercel/… sin controlar github.com/vercel, y el name del manifiesto debe ser igual al nombre del repo (o de la carpeta en un repo con varias lamps) — una discrepancia se rechaza en el pull y nunca se lista. El hub lista una lamp automáticamente la primera vez que alguien la descarga: trae el manifiesto y el programa, los valida, corre el linter de promesas y la pone en el catálogo con etiquetas honestas — community, y BREAKS ITS PROMISE cuando el código pide más que su techo declarado.
# one lamp per repo: lamp.json at the root, name == repo
git push
lamp publish owner/repo
# many lamps per repo: a folder per lamp, name == folder
lamp pull owner/repo/name
# the badge for your README

La identidad en el hub es owner/name, primero en llegar por nombre y siempre mostrada con su owner — el owner delante de cada nombre es la señal de confianza. Las versiones son tags de git; sin tags se usa la rama por defecto. El namespace oficial (lamp pull git) es el monorepo curado; todo lo demás es el ecosistema abierto.
7 · Las reglas
- Un manifiesto DEBE declarar caps. Sin caps → no carga y nunca se lista.
- El name del manifiesto DEBE ser igual al nombre del repo (o de la carpeta en un monorepo). La identidad es donde una lamp vive, nunca lo que su json declare.
- exec DEBE nombrar sus binarios (exec=git,exec=ls). exec solo o exec=* nunca carga y nunca se lista — el agujero nunca fue la ejecución, fue la ejecución sin nada que la limite.
- exec exige profile native; el perfil pure no tiene procesos que ejecutar.
- Lo que corre es siempre efectivo = require ∩ manifiesto ∩ proyecto ∩ sesión. Cada capa solo puede estrechar. Bajo un techo, el runtime niega, no recorta.
- pull trae solo los archivos que el manifiesto lista; una ruta que escape de la carpeta se rechaza. Sin archivos comprimidos, sin scripts post-instalación, nada se ejecuta en el pull.
- El programa imprime exactamente un valor JSON. Los rechazos son datos, quedan registrados, en el audit.
- Habilitar una lamp para agentes es un acto humano — editar un archivo o commitear una carpeta. Nunca es una herramienta que un agente pueda llamar.
- El linter es un lint, no una prueba: compara el texto antes de habilitar; el runtime es quien decide en la llamada. Los dos están de tu lado.
8 · Para agentes (MCP + skill)
lamp mcp
Las herramientas de cada lamp habilitada aparecen como lamp_<name>_<tool> con el techo efectivo en cada descripción, para que el modelo conozca sus propios límites. lamps_list y lamps_audit están siempre; lamps_eval existe solo cuando un humano escribió ~/.lamps/session.json con "eval": true. Arranca desde el directorio de trabajo, así que las herramientas cambian con el proyecto y la configuración del agente no. Una lamp instalada pero no habilitada es invisible para el modelo.
lamp skill # writes ./.agents/skills: the lamps skill, plus one SKILL.md per lamp you pulled
9 · Dónde vive todo y los techos que tú fijas
<project>/.lamps/<name>/ committing IS enabling
<project>/.lamps/<name>/policy.json config-only for a global lamp
<project>/.lamps/config.json the project ceiling
~/.lamps/lamps/<owner>/<name>/ pulled lamps
~/.lamps/enabled.json which globals agents may see
~/.lamps/session.json the ceiling over everything
~/.lamps/audit/log.jsonl asked · granted · denied
Precedencia: proyecto sobre usuario, como toda herramienta con configuración de proyecto. lamp init escribe un ./.lamps/config.json inicial; ajústalo y commitéalo — un techo más estrecho cuesta menos confirmaciones, no más.
10 · Confianza, con honestidad
- Bajo el perfil pure no hay hacia dónde escapar: no existen sistema de archivos, procesos ni drivers. Dos paredes.
- Bajo el perfil native el techo es la única pared y la lamp es un proceso común del sistema. Un bug del runtime es un bug del sandbox. Prefiere pure cuando puedas.
- El hub no hace de guardián del ecosistema abierto; lo etiqueta. Lee el techo y la promesa antes de habilitar nada.
- La firma y el direccionamiento por contenido están en el roadmap; hoy pull registra un sha256 por archivo y update nota cualquier cambio.