Inkscape

Un modelo maneja Inkscape 1.4 a través del Hub para componer una tarjeta de visita en dos capas. Inkscape es la única aplicación de aquí en la que no hay nada que iniciar: el Hub ejecuta un proceso de Python por cada script. Esta página da el texto, el script, las respuestas del Hub y la captura.

La ventana de Inkscape: un dibujo oscuro de dos órbitas alrededor de un círculo, cinco módulos con etiqueta sobre las órbitas y el editor XML abierto en los nodos que escribió el script.
Un dibujo hecho por un script y abierto en Inkscape: es un SVG corriente cuyos nodos XML se editan a mano.

Activar Inkscape

No hay puente ni ventana. El Hub busca /usr/bin/python3, /usr/bin/inkscape y las extensiones de Inkscape en /usr/share/inkscape/extensions. Toda la preparación es una entrada en ~/.config/libremodular-mcp/config.toml, después de libremodular-mcp init:

[apps.inkscape]
enabled = true

En un Debian 13 recién instalado, import inkex necesita además python3-tinycss2, que el paquete inkscape no instala: sudo apt install inkscape python3-tinycss2.

get_state sobre hub enumeró Inkscape como conectado en el modo cli, con la versión que informó Inkscape:

Respuesta del Hub
{
  "app": "hub",
  "app_version": "0.1.0",
  "bridge_version": null,
  "captured_at": "2026-10-21T12:47:13.608Z",
  "connected": true,
  "content_origin": "hub",
  "screenshot": null,
  "state": {
    "modules": [
      {
        "app_version": "1.4",
        "bridge_version": null,
        "connected": true,
        "mode": "cli",
        "name": "inkscape"
      }
    ]
  },
  "warnings": []
}

Texto dado al modelo

Texto dado al modelo
In Inkscape, lay out a name card, A6 landscape (148 by 105 mm). Dark blue background (#1c385c), a copper circle (#c25438) in the top-left corner, the name “Alice Martin” in white and large, a thin amber line (#f2b344) under it, then the role “Sound engineer” in light grey and smaller. Put the background shapes on a layer named “Background” and the text on a layer named “Text”.

Antes de escribir, el modelo llamó a get_state sobre inkscape. El state estaba vacío y una advertencia decía no document yet: the working document is created by the first script.

Script escrito

Un modelo, Claude Sonnet 5.5, escribió este script a partir de la guía y de ese estado. No es un script tomado de las pruebas del proyecto. Dos líneas vienen de la guía: el script elimina primero los hijos de la raíz, porque el documento se conserva de un script al siguiente, y fija cx, cy y r del círculo uno por uno, porque, como advierte la guía, los dos argumentos de inkex.Circle.new no forman un centro.

python · Script escrito
import json
import os

import inkex

document = inkex.load_svg(os.environ["LMM_DOCUMENT"])
svg = document.getroot()
for child in list(svg):
    svg.remove(child)
svg.set("width", "148mm")
svg.set("height", "105mm")
svg.set("viewBox", "0 0 148 105")

background = svg.add(inkex.Layer.new("Background"))
panel = inkex.Rectangle.new(0, 0, 148, 105)
panel.style = {"fill": "#1c385c"}
background.add(panel)
disc = inkex.Circle()
disc.set("cx", "20")
disc.set("cy", "20")
disc.set("r", "9")
disc.style = {"fill": "#c25438"}
background.add(disc)
rule = inkex.Rectangle.new(20, 62, 108, 0.8)
rule.style = {"fill": "#f2b344"}
background.add(rule)

texts = svg.add(inkex.Layer.new("Text"))
for content, y, size, colour, weight in [("Alice Martin", 56, 12, "#ffffff", "bold"), ("Sound engineer", 76, 6, "#cfd4da", "normal")]:
    line = inkex.TextElement()
    line.text = content
    line.set("x", "20")
    line.set("y", str(y))
    line.style = {"fill": colour, "font-size": f"{size}px", "font-family": "sans-serif", "font-weight": weight}
    texts.add(line)

document.write(os.environ["LMM_DOCUMENT"])
print("LMM_RESULT: " + json.dumps({"layers": [layer.label for layer in svg.descendants().filter(inkex.Layer)], "elements": len(list(svg.descendants()))}))

Respuesta del Hub

Respuesta del Hub
{
  "app": "inkscape",
  "duration_ms": 151,
  "error": null,
  "result": {
    "elements": 8,
    "layers": [
      "Background",
      "Text"
    ]
  },
  "status": "ok",
  "stderr": "",
  "stdout": "",
  "truncated": false
}

El script se ejecutó en 151 ms: se inició y terminó un proceso de Python. El script imprimió su result en la última línea, tras LMM_RESULT: , que es la forma en que un script de Inkscape devuelve un valor. get_state describió entonces el documento de trabajo y devolvió una captura:

Respuesta del Hub
{
  "app": "inkscape",
  "app_version": "1.4",
  "bridge_version": null,
  "captured_at": "2026-10-21T12:47:14.185Z",
  "connected": true,
  "content_origin": "document",
  "screenshot": "$XDG_RUNTIME_DIR/libremodular-mcp/captures/inkscape-20261021T124713832Z.png",
  "state": {
    "element_count": 8,
    "height": "105mm",
    "layers": [
      {
        "id": null,
        "label": "Background"
      },
      {
        "id": null,
        "label": "Text"
      }
    ],
    "width": "148mm"
  },
  "warnings": []
}

La imagen producida

La captura es el documento de trabajo exportado por el propio inkscape, de 559 por 397 píxeles para una tarjeta de 148 por 105 mm. El texto se dibuja con la fuente sans-serif de esta máquina, así que otra máquina lo dibuja con la suya. El píxel de arriba a la izquierda de la captura es #1C385C y el que está dentro del círculo es #C25438.

Una tarjeta azul oscuro con un círculo de cobre arriba a la izquierda, el nombre Alice Martin en blanco, una línea ámbar y el cargo Sound engineer en gris.
La captura del documento de trabajo tras el script, tal como la exportó el Hub.

Guía de referencia en el repositorio →

SiguienteLibreOffice →