lamps — a documentação
Uma lamp é uma pasta com teto: um manifesto (lamp.json) que declara o que o programa pode tocar, e um programa (lamp.syn) que faz um único trabalho. Você a executa no terminal; seu agente a recebe como ferramenta; o runtime faz cumprir o teto. Esta página é tudo, em ordem: instalar, baixar, executar, atualizar, criar, publicar e as regras.
1 · Instale o CLI
curl -fsSL https://lamps.sh/install | sh # macOS, Linux
irm https://lamps.sh/install.ps1 | iex # Windows
O script detecta seu sistema, baixa o binário do lamp da release no GitHub, verifica o sha256, coloca em ~/.lamps/bin e adiciona esse caminho ao seu PATH. São quarenta linhas; leia antes. lamp upgrade avisa se há versão nova e como obtê-la.
2 · Pull (baixar uma 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 busca os arquivos que o manifesto lista, um por um, direto do host git — sem git, sem arquivos compactados, sem etapa de instalação, sem executar nada. Cada arquivo fica com seu sha256 registrado em .pulled ao lado da lamp. Depois roda o linter de promessas: se o código pede algo que o manifesto nunca declarou, você vê BREAKS ITS PROMISE com cada linha, antes de qualquer coisa poder rodar.
lamp list
lamp inspect <lamp>
3 · Executar
lamp run git log '{"n": 5}'
lamp git log '{"n": 5}'
LAMP_TIMEOUT=60 lamp run ...
Cada execução é um processo filho sob o teto efetivo — manifesto ∩ projeto ∩ sessão. A lamp imprime um único valor JSON. Uma recusa da política da própria lamp volta como dados; uma recusa do runtime volta como entradas DENIED estruturadas com o motivo. Isso é o sistema funcionando — nunca tente de novo com um teto mais largo. Cada checagem, concedida ou negada, fica em lamp audit.
4 · Atualizar
lamp update <ref>
update é pull da última tag. Os hashes decidem: se nenhum arquivo mudou, nada é escrito e nada conta duas vezes no hub — uma máquina conta uma vez por lamp por dia, faça o que fizer.
5 · Crie uma lamp
Uma lamp é uma pasta com dois arquivos. Crie, verifique e execute localmente — sem registro, sem conta, sem mais ferramentas que o CLI e o runtime do 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 — o teto, na sintaxe --cap-set: família ou família=escopo, separados por vírgulas. stdout · env=LAMP_* · net=host · file.read={root}/* · exec=git · db={root}/* · secret=APP_*. Peça com precisão: o runtime nega, não apara.
- profile — pure: sem sistema de arquivos, sem processos, sem drivers de banco em runtime (duas paredes). native: eles existem; o teto é a parede. exec exige native.
- name — DEVE ser igual ao nome do repositório, ou ao da pasta em um repositório com várias lamps. A identidade é o endereço, nunca o que o json declarar.
- tools — nome, descrição, parâmetros com JSON Schema. Exatamente o que um cliente MCP recebe e o que um humano digita.
- files — o que o pull baixa e hasheia. Somente caminhos dentro da pasta.
- {root} e {dir} — substituídos na execução, em caps e no código: o diretório do projeto e a pasta da própria lamp.
O programa lê quatro variáveis de ambiente e imprime um único 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)
Verifique antes que alguém a baixe:
synsema test lamp.syn
lamp inspect ./my-lamp
lamp run ./my-lamp fetch '{"id": 5}'
6 · Publicar (aparecer no hub)
Publicar é subir para um repositório público. Não há conta nem login — sua identidade no host git é a sua identidade. A identidade é o endereço, no estilo GitHub: ninguém pode publicar como vercel/… sem controlar github.com/vercel, e o name do manifesto deve ser igual ao nome do repositório (ou da pasta em um repositório com várias lamps) — uma divergência é recusada no pull e nunca é listada. O hub lista uma lamp automaticamente na primeira vez que alguém a baixa: busca o manifesto e o programa, valida, roda o linter de promessas e a coloca no catálogo com rótulos honestos — community, e BREAKS ITS PROMISE quando o código pede mais do que o teto 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

A identidade no hub é owner/name, primeiro a chegar por nome e sempre exibida com seu owner — o owner na frente de cada nome é o sinal de confiança. Versões são tags do git; sem tags usa-se o branch padrão. O namespace oficial (lamp pull git) é o monorepo curado; todo o resto é o ecossistema aberto.
7 · As regras
- Um manifesto DEVE declarar caps. Sem caps → não carrega e nunca é listado.
- O name do manifesto DEVE ser igual ao nome do repositório (ou da pasta em um monorepo). A identidade é onde a lamp vive, nunca o que o json declarar.
- exec DEVE nomear seus binários (exec=git,exec=ls). exec puro ou exec=* nunca carrega e nunca é listado — o buraco nunca foi a execução, foi a execução sem nada a limitá-la.
- exec exige profile native; o perfil pure não tem processos para executar.
- O que roda é sempre efetivo = require ∩ manifesto ∩ projeto ∩ sessão. Cada camada só pode estreitar. Sob um teto, o runtime nega, não apara.
- pull baixa somente os arquivos que o manifesto lista; um caminho que escape da pasta é recusado. Sem arquivos compactados, sem scripts de pós-instalação, nada é executado no pull.
- O programa imprime exatamente um valor JSON. Recusas são dados, ficam registradas, no audit.
- Habilitar uma lamp para agentes é um ato humano — editar um arquivo ou commitar uma pasta. Nunca é uma ferramenta que um agente possa chamar.
- O linter é um lint, não uma prova: compara o texto antes de habilitar; o runtime é quem decide na chamada. Os dois estão do seu lado.
8 · Para agentes (MCP + skill)
lamp mcp
As ferramentas de cada lamp habilitada aparecem como lamp_<name>_<tool> com o teto efetivo em cada descrição, para o modelo conhecer seus próprios limites. lamps_list e lamps_audit estão sempre lá; lamps_eval existe apenas quando um humano escreveu ~/.lamps/session.json com "eval": true. Ele parte do diretório de trabalho, então as ferramentas mudam com o projeto e a configuração do agente não. Uma lamp instalada mas não habilitada é invisível para o modelo.
lamp skill # writes ./.agents/skills: the lamps skill, plus one SKILL.md per lamp you pulled
9 · Onde tudo vive e os tetos que você define
<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
Precedência: projeto sobre usuário, como toda ferramenta com configuração de projeto. lamp init escreve um ./.lamps/config.json inicial; ajuste e commite — um teto mais estreito custa menos confirmações, não mais.
10 · Confiança, com honestidade
- Sob o perfil pure não há para onde escapar: não existem sistema de arquivos, processos nem drivers. Duas paredes.
- Sob o perfil native o teto é a única parede e a lamp é um processo comum do sistema. Um bug do runtime é um bug do sandbox. Prefira pure quando puder.
- O hub não faz de porteiro do ecossistema aberto; ele rotula. Leia o teto e a promessa antes de habilitar qualquer coisa.
- Assinatura e endereçamento por conteúdo estão no roadmap; hoje o pull registra um sha256 por arquivo e o update nota qualquer mudança.