Documentación

Versión 1.0.3 · actualizado el 12 de agosto de 2026 · en Markdown · la justificación artística

Esto es lo que hay debajo: qué ve tu app, dónde acaba cada dato y qué no se puede hacer. Está escrito para quien va a leer el código que le genere su IA y quiere saber contra qué está programando.

Si eres una IA leyendo esto: hay una versión en Markdown pensada para ti en palet.cloud/docs.md, y un índice en llms.txt.

Qué es Palet

Una mini-app de Palet es un único documento HTML con su CSS y su JavaScript dentro. Nada de dependencias, ni build, ni ficheros sueltos.

Ese documento se ejecuta en el dispositivo de quien la usa, dentro de un sandbox, con un objeto window.palet inyectado. Palet le pone lo que un HTML suelto no tiene: memoria que sobrevive al cierre, sincronización entre dispositivos, notificaciones, la posibilidad de compartirla con otras personas y un widget en la pantalla de inicio.

Lo que no le pone es un servidor. Esa es la decisión de la que cuelga todo lo demás.

Que quepa en un solo documento no es solo una restricción técnica: una app de Palet se lee entera de una sentada, como un boceto en una hoja. Por qué eso importa, y por qué el resto se ve como se ve, en la justificación artística.

Cómo funciona por dentro

El servidor de Palet nunca ejecuta el código de tus apps. No hay funciones, ni contenedores, ni procesos por usuario. El servidor hace tres cosas: guarda la definición de cada app (su HTML), guarda sus datos, y comprueba quién puede leer qué.

1Tu dispositivo

Descarga el HTML y lo ejecuta en un sandbox. Aquí ocurre todo el cálculo: los totales, los filtros, los gráficos.

2El SDK

Cuando la app quiere guardar o leer, llama a window.palet, que habla con el servidor por HTTP.

3El servidor

Recibe claves y valores JSON. Comprueba permisos, aplica límites y escribe. Nunca interpreta lo que hay dentro.

De ahí salen dos consecuencias que conviene tener claras. La primera es de seguridad: una app que se porte mal solo puede hacerle daño a la pestaña donde corre, porque no tiene dónde ejecutarse en el servidor. La segunda es de diseño: si tu app necesita hacer algo mientras está cerrada, no puede. No hay tareas programadas ni procesos de fondo. Lo único que sigue vivo con la app cerrada son las notificaciones que dejes programadas y las cuentas atrás del widget.

El SDK

Todo lo que una app puede hacer pasa por window.palet. No hay más superficie que esta.

QuéPara qué
palet.ready(cb)Espera a tener contexto: quién la usa y qué app es.
palet.storageDatos del grupo: los ve todo el que comparta la app.
palet.meDatos de cada persona, que nadie más ve.
palet.storage.update(clave, fn)Cambiar sin pisar lo que escribió otro a la vez.
palet.onChange(cb)Avisa cuando alguien del grupo toca algo.
palet.widget.set({…})Lo que la app enseña en la pantalla de inicio.
palet.notify(titulo, texto, { to })Avisar a quien la usa o a alguien del núcleo.
palet.connect(nombre).fetch(…)Llamar a una API externa con un secreto que la app nunca ve.
palet.openUrl(url)Abrir un enlace externo (https, mailto, tel, sms, geo).
palet.user · palet.appQuién la está usando y qué app es.

Dónde vive cada dato

Es la decisión que más se equivoca al empezar, y la que peor sienta arreglar después. Hay dos sitios y no se parecen en nada.

Dicho en el idioma del taller: uno es el pocillo común, donde todos mojan el pincel, y el otro es tu cuaderno.

palet.storage — del grupo

Lo que existe una vez para todos: la lista de la compra, los gastos, los restaurantes, el itinerario del viaje. Si compartes la app, todos ven lo mismo y todos pueden escribirlo.

await palet.storage.update('gastos', lista =>
  [...(lista || []), nuevo]
)

Usa siempre update() y no set(): lee, aplica tu cambio y guarda solo si nadie tocó la clave mientras tanto. Con set(), el último en escribir borra lo del anterior.

palet.me — de cada cual

Lo que es de quien lo escribe: su récord en un juego, sus preferencias, su progreso, lo que lleva marcado. Nadie más lo ve, ni siquiera quien creó la app.

await palet.me.set('record', 4820)
const mio = await palet.me.get('record')

El error clásico: guardar el récord de un juego en storage. Al compartirlo, todo el mundo hereda la puntuación de otro.

¿Y si el dato es del grupo pero hay que saber de quién es cada cosa —un marcador, un reparto de gastos—? Entonces va en storage, en un objeto indexado por palet.user.id, con el nombre dentro para poder mostrarlo. Nunca uses el nombre como clave: los nombres se repiten.

Widgets

Una app puede publicar lo que enseña en la pantalla de inicio del móvil. Se ve sin abrir nada, y tocarlo abre esa app directamente.

Un widget es la mancha de color que se reconoce desde el otro lado de la habitación: un dato, grande, y nada más.

palet.widget.set({ title: 'Casa', value: '5 cosas', caption: 'leche, pan, café' })

Lo que depende del reloj se publica como fecha

Si el dato es una cuenta atrás o un tiempo transcurrido, no publiques el número: publica la fecha. El widget la cuenta solo, al segundo, sin que la app se ejecute y sin gastar batería.

palet.widget.set({ title: 'Pomodoro', until: fin })      // 24:59, 24:58…
palet.widget.set({ title: 'Sin fumar', since: inicio })  // lo que llevas

El formato se elige solo: reloj si es cosa de horas, lenguaje llano si son días o semanas. Es la única forma de que el widget vaya al día sin abrir nada, porque la app no se ejecuta mientras está cerrada.

Del grupo, cuando el aviso es para todos

Por defecto el widget es de cada persona. Con { shared: true } es del grupo, y entonces lo que publique uno le llega al resto en segundos, sin que abran nada — la copia de su app no se ejecuta en su móvil, así que no podría enterarse de otra forma.

palet.widget.set({ title: 'Casa', value: '3 tareas' }, { shared: true })

Lo que pongas ahí lo ve todo el grupo en su pantalla de inicio. Nada personal.

Avisos

Una app puede avisar a quien la usa, y también a alguien del núcleo:

palet.notify('Te toca', 'Ana te ha asignado la compra', { to: idDeLeo })
palet.notify('Ya está', 'Lista terminada', { to: '*' })   // a todos menos a ti

Solo llega a gente que participa en esa app. Y el servidor no decide nunca cuándo avisar: lo decide la app, desde el dispositivo de quien la usa. Aquí no hay procesos mirando si algo vence — si tu app necesita avisar de algo, tiene que estar abierta para pedirlo.

Se puede silenciar, y no te vas a enterar

Cualquiera puede silenciar tu app desde su propia bandeja. Cuando lo hace, tus avisos siguen aceptándose sin error, pero no llegan. Es a propósito: la decisión es de quien recibe, y una app no debería poder saber si la han silenciado ni intentar esquivarlo.

Hay un tope diario por persona y por app. Está para que una app en bucle no queme la confianza en las notificaciones de todas las demás.

Avisa solo de lo que interrumpe: te han asignado algo, vence mañana, te toca a ti. Si narras lo que pasa dentro de la app, te silencian — y con ello pierdes también los avisos que sí importaban.

Salir a internet

Por defecto una app no tiene red. Ni puede llamar a ningún sitio, ni cargar recursos externos. Si necesita una API, hay que declarar sus orígenes al crearla, y quien la use los aprueba la primera vez que la abre. La política de seguridad del navegador solo deja pasar esos.

Con dos condiciones: la API tiene que aceptar peticiones desde un navegador (CORS) y no requerir autenticación de servidor.

APIs con secreto

Nunca metas una clave de API en el HTML de una app. Quedaría escrita en la definición de la app y visible en el chat donde la creaste.

Para eso están las integraciones: el secreto se guarda cifrado una vez en Ajustes, y la app lo usa sin verlo nunca.

const r = await palet.connect('notion').fetch('/v1/pages', {
  method: 'POST', body: { … }
})

La petición sale del servidor de Palet, que le añade el secreto. Así funcionan también las APIs que no permiten CORS.

Cuando la app se comparte

La clave es de quien la dio de alta. Si compartes una app que usa una integración, quien la use necesitaría la suya… salvo que declares qué puede hacer la app:

integrations: [
  { name: 'notion', allow: ['GET /v1/pages/*', 'POST /v1/pages'] }
]

Entonces se usa tu clave y la app funciona para todos, pero solo para esas rutas. El límite no es un detalle: quien participa puede abrir la consola del navegador y llamar al SDK a mano, así que sin acotarlo estarías prestando tu clave para cualquier cosa contra ese servicio.

Cada regla es MÉTODO /ruta. El * final abre todo lo que cuelgue de ahí; sin él, la ruta tiene que coincidir entera. Pide lo mínimo que la app necesite.

Límites

Están para que la app de otra persona no pueda estropearte la tuya, y para que ninguna pueda tumbar el servicio. Se aplican en el servidor, que es el único sitio donde tiene sentido aplicarlos: el JavaScript de una app se puede modificar, el servidor no.

BocetoAtelierMaestro
Apps propias11020
Almacenamiento10 MB200 MB2 GB
Tamaño de un valor256 KB1 MB5 MB
Llamadas por minuto y cuenta240 desde las apps · 60 desde tu IA
Personas por app compartida25, contando a quien la creó
Apps que te pueden compartir10
Vigencia de un enlace para unirse3 días

El límite por minuto es un cubo que se rellena solo: no importa el ritmo exacto, importa que no se sostenga por encima del cupo. Una app que intente escribir cien registros por segundo se topa con él en unos segundos, recibe un 429 y avisa a quien la usa de que su app está haciendo el bruto.

Por eso conviene agrupar los datos en pocas claves en vez de una por registro: una lista de la compra es una clave con un array dentro, no cincuenta claves. Va más rápido, gasta menos cupo y ocupa menos.

Lo que Palet no hace

Conviene saberlo antes de pedirle a tu IA algo que no puede salir bien.

  • No ejecuta código en el servidor. Nada de lógica de negocio, ni procesos, ni tareas programadas. Todo el cálculo ocurre en el dispositivo mientras la app está abierta.
  • No hace nada con la app cerrada. No hay «cada noche a las 3 recalcula». Lo único que sobrevive son las notificaciones programadas y las cuentas atrás del widget.
  • No es una base de datos. Es un almacén de claves y valores JSON. No hay consultas, ni índices, ni relaciones: se lee la clave entera y se filtra en el dispositivo.
  • No sirve para muchos usuarios. Está pensado para un grupo con nombres y caras —una pareja, una casa, un grupo de amigos—, no para publicar algo a mil desconocidos.
  • No guarda secretos en la app. Cualquier clave que escribas en el HTML es visible. Para eso están las integraciones.
  • No corre binarios ni instala paquetes. Un HTML, su CSS y su JavaScript. Sin npm, sin build, sin dependencias externas.

Dicho de otra forma: Palet sirve para las utilidades que usa una persona o un grupo pequeño todos los días. Para un producto con miles de usuarios y lógica en servidor, necesitas otra cosa.

Tu primera app, gratis.

Conecta tu IA y pídele lo que necesites.

Crear mi paleta