Agent Skills › lemma-work/lemma-platform

lemma-work/lemma-platform

GitHub

在lemma-connectors中根据OpenAPI规范生成或重新生成Provider集成包。涵盖生成类型化客户端、Pydantic模型及资源模块,确保操作命名合理、二进制结果正确处理,并验证导入与发现机制的完整性。

6 skills 331

Install All Skills

npx skills add lemma-work/lemma-platform --all -g -y
More Options

List skills in collection

npx skills add lemma-work/lemma-platform --list

Skills in Collection (6)

在lemma-connectors中根据OpenAPI规范生成或重新生成Provider集成包。涵盖生成类型化客户端、Pydantic模型及资源模块,确保操作命名合理、二进制结果正确处理,并验证导入与发现机制的完整性。
添加新的Provider包 改进生成包的质量 使用预期命名和类型重新生成现有应用
lemma-backend/lemma-connectors/skills/integration-creator/SKILL.md
npx skills add lemma-work/lemma-platform --skill integration-creator -g -y
SKILL.md
Frontmatter
{
    "name": "integration-creator",
    "description": "Generate or regenerate a Lemma integration package from an OpenAPI spec inside lemma-connectors. Use this when adding a new provider package, improving generated package quality, or regenerating an existing app with the expected naming, typing, and binary-result behavior."
}

Integration Creator

Use this skill when working inside lemma-connectors to add or regenerate a provider package from an OpenAPI spec.

What this skill is for

  • generating typed transport clients from OpenAPI specs
  • generating canonical provider schema models
  • generating typed tool input/output models
  • generating operation/resource modules
  • keeping operation names logical and agent-friendly
  • preserving typed binary/file results
  • validating that the package imports and discovery surface are solid

Required package shape

Each app package should contain:

  • client.py
  • generated/client/
  • generated/pydantic_models.py
  • generated/pydantic_model_registry.json
  • generated/openapi_metadata.json
  • generated/tool_types.py
  • resources/__init__.py
  • resources/<resource>.py

Operation coverage should be near-full for the in-scope provider API surface.

Generator contract

  • Tool names stay explicit and provider-level.
  • Operation names come from cleaned provider operationId values, not raw path ancestry.
  • Resource files group related operations together.
  • Tool and operation input/output models must be real typed Pydantic models.
  • Binary or file-like endpoints must surface BinaryContentResult, not placeholder dict[str, object] wrappers.
  • Preserve provider wire-format strings when the API uses url-safe/base64-like encodings that should not be eagerly decoded by Pydantic, such as Gmail message body data and raw MIME payloads.
  • Descriptions should help an agent choose and use the operation.

Quality rules

  • Prefer fixing the generator once over hand-editing many generated files.
  • Do not keep awkward names like users_messages_list when the provider intent is clearly messages_list.
  • Do not include low-value text like "backed by this tool".
  • Preserve useful provider field descriptions on generated models.
  • Keep Slack admin endpoints excluded.
  • Expect Jira and similarly large specs to need extra validation and occasional provider-specific post-processing patches.
  • Generated runtime execution must handle reserved-identifier parameters cleanly, for example mapping a public format field onto generated client parameters like format_.

Workflow

Use the exact commands and validation checklist in references/workflow.md.

Done bar

Before considering the work complete:

  • the app package imports successfully
  • info client discovery works
  • operation names are sensible
  • output schemas are real typed schemas
  • binary/file endpoints expose BinaryContentResult
  • tests and compile checks pass
通过 agent-browser CLI 控制 Chromium 浏览器,支持页面交互、表单填写、截图及调试。核心规范为操作前必须重新快照以避免引用失效,强调使用语义化等待和交互式快照命令。
需要打开网页或本地应用 进行 UI 检查与调试 执行登录或表单填写流程 抓取网页内容或截图
lemma-skills/browser/SKILL.md
npx skills add lemma-work/lemma-platform --skill browser -g -y
SKILL.md
Frontmatter
{
    "name": "browser",
    "description": "Use this skill when a task needs a real browser in a Lemma workspace: opening web pages or local dev apps, UI inspection and debugging, screenshots, login flows, form filling, scraping, console\/network logs, or saving web pages — all via the Agent Browser CLI and headful Chromium."
}

Browser

Drive a real Chromium with the agent-browser CLI. Use it for anything a page renders: local dev apps, JS-heavy sites, logins, scraping, screenshots, console/network debugging.

The Core Loop (this is law)

start-browser <url>              # first use only: starts Xvfb + Chromium + dashboard
agent-browser snapshot -i        # interactive elements with @eN refs
agent-browser click @e3          # act via refs
agent-browser wait --url "**/dashboard"   # semantic wait, never bare sleeps
agent-browser snapshot -i        # ALWAYS re-snapshot after the page changes

Refs go stale the moment the page changes (navigation, submit, dialog, re-render). Acting on a stale ref is the #1 failure — re-snapshot first. Always use -i (interactive-only) to keep output small; add -u to include link URLs.

Environment facts:

  • Nothing is running at startup — call start-browser [url] once, then reuse the same session for everything.
  • The session is preconfigured: headed Chromium at /usr/local/bin/workspace-chrome on virtual display, persistent profile at /workspace/.browser-profile (cookies/logins survive across commands and tasks), session name workspace.
  • Dashboard on port 4848 for human observation (signed URL via AgentBox Manager /sandboxes/<id>/browser-url).
  • Local apps: browse http://127.0.0.1:<port> from inside the container, never the public preview URL.
  • Never install Playwright or browser binaries — everything is preinstalled.

Acting On Pages

agent-browser fill @e3 "user@example.com"     # clear + type
agent-browser type @e4 "extra text"           # type without clearing
agent-browser press Enter
agent-browser select @e5 "Option A"
agent-browser check @e6 / uncheck @e6
agent-browser upload @e7 ./file.pdf
agent-browser scroll down 500 ; agent-browser scrollintoview @e9
agent-browser click @e8 --new-tab

No snapshot handy? Semantic locators work without one:

agent-browser find text "Sign In" click
agent-browser find role button click --name "Submit"
agent-browser find label "Email" fill "user@test.com"

Raw CSS selectors (agent-browser click "#submit") are the last resort.

Waiting (pick the right one)

After Wait
Click that navigates wait --url "**/new-page"
Form submit wait --text "Success" or wait --url
SPA update, no URL change wait --load networkidle
Element appears dynamically wait @e3 or wait --text "..."
Custom readiness wait --fn "window.app.ready === true"
Nothing else fits wait 2000 (last resort — slow and flaky)

Reading And Extracting

agent-browser get text @e5 ; agent-browser get attr @e10 href
agent-browser get url ; agent-browser get title
agent-browser --max-output 500000 get html html > page.html   # big output needs --max-output
agent-browser screenshot shot.png ; agent-browser screenshot --full full.png
agent-browser screenshot --annotate map.png                   # numbered labels keyed to @eN refs

# Arbitrary JS — heredoc avoids quote-escaping hell
cat <<'EOF' | agent-browser eval --stdin
Array.from(document.querySelectorAll("table tbody tr")).map(r => ({
  name: r.cells[0].innerText, price: r.cells[1].innerText,
}))
EOF

Save pages for later reading/citation (markdown via Readability+Turndown; pdf/jpeg/png direct):

save-webpage https://example.com/article --formats markdown,pdf --out research

Recipes

Login + persist. Fill the form via refs, wait --url "**/dashboard", done — the persistent profile keeps you logged in for later commands. For repeatable logins without secrets in shell history:

agent-browser auth save my-app --url https://app.example.com/login \
  --username user@example.com --password-stdin     # then: agent-browser auth login my-app
# Or save/reuse cookie state explicitly:
agent-browser state save ./auth.json
agent-browser --state ./auth.json open https://app.example.com

Tabs. agent-browser tab (list), tab new <url>, tab 2, tab close 2. Refs are per-page — re-snapshot after switching.

Parallel isolated sessions. agent-browser --session user-a open ... — own cookies, tabs, refs per session.

Dialogs and iframes. agent-browser dialog accept|dismiss; iframes are auto-inlined in snapshots (refs work through them), or agent-browser frame @e3 / frame main to switch context explicitly.

Local app debugging. curl -fsS http://127.0.0.1:<port> first → start-browser http://127.0.0.1:<port> → reproduce → screenshot + console/network logs — don't stop at the visual failure.

Test a pod app (authenticated)

To exercise a Lemma app in the agent browser as the current agent/user, let the CLI open it authenticated instead of wiring tokens by hand:

lemma apps open support-app                          # a DEPLOYED app, by slug — resolves its served URL + injects the bearer
lemma apps open --url http://localhost:5173 --no-auth # a `npm run dev` app — it already self-authenticates via the dev token

lemma apps open <slug> registers the current access token as an Authorization: Bearer header scoped to the API origin (so the app's cross-origin API calls authenticate), then opens the app — no login UI. A local dev server (npm run dev) seeds the token itself, so pass --url <dev-url> --no-auth. From there it's the normal core loop: snapshot -iclick/fill → re-snapshot, plus screenshot to capture the rendered UI.

See it with your own eyes. Take a screenshot, then use the view-image capability on that PNG to actually view the rendered app (layout, charts, broken styles, error overlays). view-image also reads pod and workspace files directly — a downloaded page render (lemma files child …/pages/page_0001.jpg), an uploaded image, or a local screenshot — so you can confirm a chart or document looks right without a browser. (App design, deploy, and test details: lemma-builder/references/apps.md.)

Troubleshooting

  • Element missing from snapshot → scroll it into view, wait for it, or dismiss the overlay covering it; then re-snapshot.
  • Click does nothing → a modal/banner is intercepting; find and dismiss it.
  • Fill ignored by custom inputs → agent-browser keyboard inserttext "text" bypasses key events.
  • CDP/connection errors or weird state → agent-browser doctor --fix.
  • More guides ship with the CLI: agent-browser skills list, agent-browser skills get <name>; references/agent-browser-core.md has the full core reference.

See also

  • Full core reference (snapshot/ref model, every command) → references/agent-browser-core.md
  • Build, deploy, and design a pod app → lemma-builder/references/apps.md
  • Operate the pod (open apps, mint file URLs) → the lemma-user skill
  • Inline live views over pod data → the lemma-widget skill
用于设计和构建完整的Lemma Pod,涵盖模型、文件、函数、智能体及工作流等资源。支持从问题陈述到本地打包、CLI导入及逐层验证的全流程开发,适用于Pod设计与应用创建,不用于日常运维。
设计或创建新的Lemma Pod 重构现有Pod结构 通过CLI导入导出Pod资源 开发基于Pod的自定义应用
lemma-skills/lemma-builder/SKILL.md
npx skills add lemma-work/lemma-platform --skill lemma-builder -g -y
SKILL.md
Frontmatter
{
    "name": "lemma-builder",
    "description": "Design and build complete Lemma pods: model tables\/files\/functions\/agents\/workflows\/schedules\/connectors\/surfaces\/apps from a problem statement, author a local pod bundle, import progressively with the Lemma CLI, and verify every layer. Use for pod design, creation, restructuring, import\/export, and app development. Do not use for day-to-day operation of an existing pod; use lemma-user instead."
}

Lemma Builder

What Is A Pod

A pod is one team's operating system: a shared workspace inside an organization that holds everything one use case needs — tables and files (data, with documents auto-indexed for built-in RAG), functions, agents, workflows, schedules, and connectors (automation), and apps and surfaces (interfaces) — under one permission boundary. Two rules run through all of it: every workload starts with zero access and is granted resources explicitly by name, and a workload acts under the delegated identity of the user who invoked it (so RLS and the personal /me area resolve to that user). Good pod scope = one team, one operating loop, one coherent data model.

Read references/pod-model.md first. It is the canonical model every other doc grounds in — identity & permissions, the data/automation/interface layers, how the resources interact, and how a pod is authored. This file is the build entry point on top of it.

The Resources

Resource What it is What it solves
Tables Typed-column data store; per-table row-level security (RLS-on by default = each member's own rows; enable_rls: false = shared team data), foreign keys, enums The pod's database: tickets, leads, approvals — durable structured state
Files Document store under shared /… folders (e.g. /knowledge) and personal /me; uploaded documents are auto-indexed and semantically searchable — built-in RAG — with converted-markdown reading The pod's knowledge and artifacts: contracts, manuals, reports, generated deliverables
Functions Typed Python entrypoints run server-side as workload principals Deterministic logic: validation, multi-table writes, external API calls, transforms
Agents LLM workers with instructions, toolsets, and granted resources Judgment: classification, drafting, extraction, research, conversation
Workflows Node graphs of FORM / AGENT / FUNCTION / DECISION / LOOP / WAIT_UNTIL steps with durable runs The process layer — orchestrates functions, agents, and humans (form nodes are assigned to pod members)
Schedules Time-based (TIME cron) or event-based — DATASTORE (table row events) and WEBHOOK (connector events) Starting agents or workflows automatically
Connectors Third-party apps (Gmail, Slack, …) via org auth configs, accounts, and executable operations Acting on external systems
Surfaces A pod agent exposed on Slack/Teams/Telegram/WhatsApp/Gmail/Outlook Meeting users where they already chat
Apps Custom browser apps deployed into the pod — single-file HTML (no build) for one page, or Vite + lemma-sdk for multi-page apps The product UI: dashboards, queues, detail views, workflow inboxes

Choosing among them — six heuristics (full text in references/pod-model.md → "Choosing a primitive"; pod-design.md turns them into decision tables):

  1. One step, one agent. One agent returning rich output_schema beats an agent→agent chain; split only for orthogonal judgments.
  2. Workflow = checkpoints + humans. Reach for a workflow when people approve, are assigned steps, or watch progress — not for a lone call.
  3. Surface = a human is talking. A chat-platform conversation is a surface; a system event driving unattended work is a schedule → workflow/agent.
  4. Events choreograph workloads. A table write or connector trigger starts the next workload (server-side); an app stays live via watchChanges (client-side).
  5. Occam's razor. Build the fewest agents and nodes that satisfy the use case.
  6. Reach for the most direct primitive. A single record write is a direct records-API call, not a function; a bare agent is called directly or granted as a tool — never wrapped. A function earns its place only for deterministic multi-step work (coordinated writes, write + compute, or a connector call).

The Build Loop

Pods are built as local directory bundles and imported with upsert. This is the primary path — inline lemma <resource> create --data ... is only for quick experiments.

Scaffold, don't hand-write. lemma <resource> init writes a near-runnable, commented bundle file (JSONC — // and /* */ comments and trailing commas are allowed) with the right shape, folder==name wiring, and the backend defaults (visibility, RLS, function headers). Edit it, then import.

lemma pod init my-pod                  # whole starter pod on disk (pod.json + table + agent + AGENTS.md)
# or scaffold into an existing bundle (auto-finds pod.json upward):
lemma tables init tickets [--shared]   # tables/tickets/tickets.json  (--shared = enable_rls:false)
lemma functions init score_ticket      # functions/score_ticket/{score_ticket.json,code.py} with headers
lemma agents init triage [--runtime ID] # agents/triage/{triage.json,instruction.md}
lemma workflows init intake            # a valid FORM->END graph to extend
lemma schedules init nightly           # schedules/nightly/nightly.json
lemma surfaces init slack              # surfaces/slack/slack.json

lemma agents grant triage tickets:read,write /knowledge:read app:gmail:use agent:helper:execute function:score_ticket:execute
#   ^ merges into permissions.grants in place (keeps your JSONC comments): name:perms (table) | /path:perms (folder) | app:name:use | agent:name:execute | function:name:execute
lemma agents schema                    # or `lemma schema agent` — print the example/shape for a resource type

lemma pods create my-pod --with-starter   # create the pod AND scaffold+import a starter in one shot

By hand, or after scaffolding — the bundle is always the source of truth:

lemma pods create my-pod --org <org> --description "..."   # import never creates the pod shell

mkdir my-pod && cd my-pod                                  # author the bundle locally
# pod.json + one folder per resource (see layout below)

lemma pods import ./my-pod --dry-run                       # validate, fix errors
lemma pods import ./my-pod                                 # upsert by resource name (default)
lemma pods import ./my-pod/functions/score_ticket          # partial imports work too
lemma pods doctor my-pod                                   # check grants/targets/surfaces wiring

lemma functions run score_ticket --data '{"title":"test"}' # test each layer
lemma workflows run intake --data '{"id":"REQ-1"}'         # waits for completion by default
lemma agents chat triage-agent "Classify this ticket"

# edit files -> re-import -> re-test. Export an existing pod for a baseline (or a template):
lemma pods export ./bundles --force [--as-template]

Bundle layout (folder name must equal the resource's name):

my-pod/
  pod.json
  tables/tickets/tickets.json
  functions/score_ticket/score_ticket.json    + code.py        (JSON carries permissions.grants)
  agents/triage-agent/triage-agent.json       + instruction.md (JSON carries permissions.grants)
  workflows/intake/intake.json
  schedules/nightly/nightly.json
  surfaces/slack/slack.json
  apps/ops-app/ops-app.json                + source/
  files/knowledge/.folder.json
  seed/seed.sh                                 # sample data so the pod demos itself (not imported — run after)
  payloads/                                    # test fixtures, not a pod resource
  README.md                                    # operator setup + verification runbook

Build order follows dependencies: tables → files → functions → agents → workflows → schedules → connectors/surfaces → app → seed. Verify each layer with realistic data before adding the next.

Build for the hero moment, not just for correctness. A pod that imports cleanly and passes its tests can still be plumbing nobody wants to open. Before building, name the one screenshottable "oh" — the agent doing real work on its own, behind an interface someone adopts (see references/pod-design.md). The app (or surface) is usually the product — design it like the thing people live in, not an afterthought tacked on last. And seed the pod so it demos itself: a seed/seed.sh of sample rows, files, and one completed run, so opening the app shows the hero moment immediately instead of an empty state. (Records and file contents don't round-trip through import — the seed script is how they land; record it in the README.)

Three rules that bite everyone:

  1. Zero access by default, and no destructive power without a grant or approval. Agents and functions are created with NO access to anything — not tables, not files/folders, not connectors. Every resource they touch must be granted explicitly, either via permissions.grants in their bundle JSON (exported automatically, replaced on import) or lemma functions|agents permissions replace <name> --file grants.json. A named workload's grant is standalone authority (grant-first). MISSING_WORKLOAD_RESOURCE_GRANT at runtime means a grant is missing; DESTRUCTIVE_ACTION_REQUIRES_APPROVAL means a delete/manage action needs either an explicit destructive grant or a user's session approval. Full 403 decoder + the complete model in references/authorization-model.md.
  2. Not everything bundles. File contents and connectors (auth configs, accounts) are not part of import/export — set those up with CLI commands and record the steps in the pod's README. Surfaces and workload permissions do round-trip in bundles.
  3. Leave a runbook. Every production-quality bundle should include a README with: purpose, required CLI context, non-bundled setup steps, required uploaded files, connector auth configs/accounts, verification payloads, and the final end-to-end smoke test.

References

Read what the task needs:

  • references/pod-model.mdthe canonical model. Read this first. Identity & permissions, the data/automation/interface layers, how the resources interact, how a pod is authored.
  • references/authorization-model.md — the two ledgers, grant-first rule, delegated identity, destructive-action gate + session approvals, the 403-code decoder, agent/function-as-tool grants, connector account modes, import/export grant semantics. Read when a workload hits a 403 or you're wiring grants.
  • references/pod-design.md — problem statement → pod architecture; decision tables; worked example; testing strategy. Start here for new pods.
  • references/cli-and-bundles.md — auth/context, exact bundle format, a minimal quickstart bundle, import/export semantics and limits, command cheatsheet.
  • references/tables.md — column types, schema JSON, records, RLS, design guidance.
  • references/files.md — shared /… vs personal /me, search, converted markdown, file+table patterns.
  • references/functions.md — code contract, in-function SDK (Pod.from_env()), grants, testing.
  • references/agents.md — agent JSON, toolsets, instructions, agents/functions as tools (sub-agents), runtime profiles, testing.
  • references/workflows.md — every node type, expressions, human-in-the-loop patterns, run debugging.
  • references/connectors.md — connectors → auth configs → accounts → operations/triggers; LEMMA vs COMPOSIO providers; delegated execution.
  • references/schedules-and-triggers.md — TIME/DATASTORE/WEBHOOK triggers, event payloads, LLM event filtering.
  • references/surfaces.md — exposing a pod agent on Slack/Teams/Telegram/WhatsApp/Gmail/Outlook.
  • references/apps.md — design-doc-first method, scaffold/dev/deploy, TS SDK, components, UX rules.
  • references/app-recipes/*.md — copy-paste app patterns: agent chat, RLS tables, workflow forms, file viewer, connector actions (load the one you need).
用于在现有Lemma Pod中执行运行时操作,如查询表记录、读取文件、运行函数工作流及与Agent交互。基于用户身份和RLS权限进行资源访问,不涉及Pod设计构建。
需要查询或编辑Pod内的数据表和记录 需要读取Pod中的文件或搜索内容 需要运行函数、工作流或与Pod Agent聊天 需要提交工作流表单或执行连接器操作
lemma-skills/lemma-user/SKILL.md
npx skills add lemma-work/lemma-platform --skill lemma-user -g -y
SKILL.md
Frontmatter
{
    "name": "lemma-user",
    "description": "Operate an existing Lemma pod from the CLI as a human or agent: inspect resources, query tables and records under RLS, search and read pod files (converted markdown, page images), run functions and workflows, submit waiting workflow forms, chat with pod agents, run first-party tools, and execute third-party connector operations. Do not use for designing or building pods; use lemma-builder instead."
}

Lemma User

You are operating inside an existing pod — use its resources (tables, files, functions, agents, workflows, connectors) to get work done for the user. You are not redesigning the pod; that's the lemma-builder skill.

This is the operator companion to lemma-builder: the runtime view of the same model. For the model itself, read lemma-builder/references/pod-model.md — this doc grounds in it and assumes it.

The model, from the operator's seat

(Grounds in pod-model.md.) A pod is one team's workspace under one permission boundary. What that means when you run commands:

  • You act as a specific user. Whether a human at a terminal or an agent on someone's behalf, every call carries your identity. A workload (function or agent) runs under delegated identity — it acts as the user who invoked it, never as a service account. So /me and row visibility always resolve to that user.
  • RLS scopes what you see. On an RLS table (the per-user default) you see and edit only your own rows — another member's row is invisible (a fetch returns 404, a list omits it). On a shared table (enable_rls: false) everyone sees the same rows. This holds for everyone, admins included; reading across all users' rows needs an explicit mode=ADMIN opt-in (admin-gated, not the default flow). The read-only query API enforces RLS the same way.
  • /me is your private tree. /me/... resolves to your own file subtree (owner-only). Every other path is pod-shared — top-level folders like /knowledge, /contracts. There is no /pod prefix: a path is shared unless it's under /me. Folder grants cascade to everything beneath them.
  • Missing access has two shapes. A human without the pod role gets a permission error; a workload missing a grant gets MISSING_WORKLOAD_RESOURCE_GRANT (naming the resource a builder must grant).

Put user-facing deliverables in /me (or the appropriate shared folder) — never leave the only copy in a local temp path.

Orient first

lemma pods list            # marks the currently active pod
lemma pods describe        # full inventory: tables, agents, functions, workflows, schedules, apps

Workspace sessions inject LEMMA_TOKEN, LEMMA_BASE_URL, LEMMA_ORG_ID, LEMMA_POD_ID (and LEMMA_WORKSPACE_URL) — use them; never invent bootstrap config. (Outside an injected workspace — e.g. running the CLI on a laptop — project-root .lemma.<server>.env files supply the same LEMMA_* values per server for that folder; injected/real env always takes precedence.) Default output is a compact, complete table/detail view (schemas included) — prefer it; it costs far fewer tokens than JSON. Use --output json only to pipe/save, and --full to expand folded fields. Pass payloads with --data '<json>' (-d) or --file path.json (-f); target another pod with --pod <id-or-slug>; add --yes for destructive commands in automation. CLI groups are plural (lemma files, lemma tables, lemma records, …); the singular alias (lemma file, lemma table) is the same command.

For multi-step scripting prefer the Python SDK over chained CLI calls:

from lemma_sdk import Pod
pod = Pod.from_env()       # auth + pod from the environment

Files — the pod is a searchable knowledge base

This is the area you'll lean on most. Uploaded documents are auto-indexed — the pod is the RAG system. PDF/DOC/DOCX/ODT/RTF/Markdown/text/HTML/EPUB are extracted, chunked, embedded, and converted to page-marked markdown on upload. Data/binary (CSV, JSON, XLSX, images, email) are stored but never indexed — they won't appear in search. So: search to find, cat to read, child + view-image to see.

Because the pod auto-produces a document's markdown, page images, and figures, read those first (the commands below) — never re-parse a pod file. Reach for the liteparse-documents skill (lit) only for a document from outside the pod (e.g. a PDF an agent fetched from the web) or as a fallback when a pod file's derived artifact is missing or insufficient (scanned/OCR, bounding boxes).

Search — find the relevant passages

lemma files search "refund policy" --scope /knowledge                 # HYBRID, folder + all subfolders
lemma files search "termination clause" --scope /contracts --method VECTOR   # semantic only
lemma files search "invoice 4471" --scope /inbox --method TEXT --direct      # keyword, immediate children only

Results are ranked passages with page numbers, so you can jump straight to cat … --pages N. --scope + the default SUBTREE (folder and everything beneath) is your retrieval lever — scope a search to one knowledge folder to keep it tight. --method is HYBRID (default), VECTOR (semantic), or TEXT (keyword); --direct limits to a folder's immediate children. Reach for search before reading whole files or guessing.

Read — cat is page- and mode-aware

lemma files cat /knowledge/handbook.pdf                 # auto: raw text for .md/.txt, converted markdown for PDF/DOCX/…
lemma files cat /knowledge/handbook.pdf --pages 3-7     # 1-based page slice over the converted markdown (great for long books)
lemma files cat /me/notes/log.md --lines 10-50          # 1-based line slice over raw text
lemma files cat /knowledge/handbook.pdf --mode markdown # force converted markdown (errors if not a document)
lemma files cat /scratch/data.csv --mode text           # raw bytes (binary → flagged, not dumped)

--mode is auto (default) / text / markdown. Output is capped at ~50,000 chars by default (matching the in-process agent tool); widen with --max-chars 0 (unlimited), --max-lines N, --max-tokens N, or --full, or narrow with --pages / --lines. The payload reports page_count, the returned range, and a truncated flag so you know when to page — page-range slicing is how you read a long document without blowing the budget.

lemma files download /knowledge/handbook.pdf ./handbook.md --markdown   # save converted markdown
lemma files download /knowledge/handbook.pdf ./handbook.pdf             # exact original bytes

See — child page images + view-image

A processed document exposes hidden child artifacts at <file-path>/<artifact>:

lemma files children /knowledge/handbook.pdf                          # list them
lemma files child /knowledge/handbook.pdf/document.md --pages 3-7     # page-marked markdown range
lemma files child /knowledge/handbook.pdf/pages/page_0003.jpg ./p3.jpg  # fetch a rendered page image
  • …/document.md — page-marked converted markdown (<!-- PAGE n -->)
  • …/pages/page_0001.jpg … — rendered page images (1-based)
  • …/images/image_0.png … — extracted figures

Use view-image to actually see a pod file. Those rendered page JPEGs (and any uploaded image) are exactly what the view-image capability reads — fetch one with files child (or a URL with files url) and view it to see a chart, a signature, a scanned form, a layout. This also works on workspace files directly. So: "what does page 3 look like?" → files child …/pages/page_0003.jpg → view-image; "what does it say?" → files cat … --pages 3.

Write & transfer

lemma files mkdir /knowledge
lemma files upload ./report.md /me/reports/report.md          # documents auto-index
lemma files upload ./data.csv /scratch/data.csv --no-search   # skip indexing
lemma files write /me/notes/draft.md "first line"             # create/overwrite (or pipe via stdin)
lemma files append /me/notes/draft.md "next line"             # append (read-modify-write, last writer wins)
lemma files ls /knowledge ; lemma files tree /
lemma files stat /knowledge/handbook.pdf                      # metadata incl. indexing status
lemma files mv /me/notes/draft.md /me/notes/final.md
lemma files rm /scratch/data.csv

Indexing lags briefly after upload — stat shows status (COMPLETED = searchable, NOT_REQUIRED = stored but not an indexed document, PENDING/PROCESSING/FAILED).

Link to a file — pick by who opens it

lemma files url /reports/summary.pdf                           # app_url (in-app, signed-in member) + short-lived download url
lemma files share /reports/summary.pdf --ttl 3h --max-hits 50  # public, no-login, expiring + hit-capped

url returns an app_url deep-link for pod members (must be logged in) plus a short-lived raw download url. share mints a public link anyone can open without logging in — it expires (--ttl = 30m/3h/24h; default 3h, max 24h) and stops serving after --max-hits downloads (default 50, max 100), bounding egress if it leaks. Emailing/messaging someone outside the pod → share; pointing a member at a file in the app → url. (In a function or agent, the same via the SDK: pod.files.get_url(path) / pod.files.create_signed_url(path, …).)

Tables, records, query

lemma tables list
lemma tables get tickets                              # schema: columns, types, enums
lemma records list tickets --limit 20
lemma records get tickets <record-id>
lemma records create tickets --data '{"title":"New item","status":"new"}'
lemma records update tickets <record-id> --data '{"status":"done"}'
lemma query run "select status, count(*) as total from tickets group by status"

Read the table schema before writing — ENUM columns reject values outside options. Prefer query run (a read-only SELECT subset — one SELECT, no writes) for aggregates and joins instead of paging records; it reads across any tables, including RLS tables, where it returns only your own rows (RLS scopes every caller the same way). To read across all users' rows on an RLS table you'd pass mode=ADMIN — admin-gated, not the default, and agents never use it.

Functions, workflows, schedules

lemma functions list
lemma functions run score_ticket --data '{"ticket_id":"..."}'   # check output_data / status / logs
lemma functions runs list score_ticket                          # past runs (debug); runs get <id> for one

lemma workflows list
lemma workflows run intake --data '{"title":"..."}'             # creates the run; --data is submitted to the entry form
lemma workflows runs list intake
lemma workflows runs get <run-id>                               # status, current node, active_wait, step_history, errors
lemma workflows runs waiting                                    # form waits assigned to you (your approval queue)
lemma workflows runs submit-form <run-id> --data '{"approved": true}'  # complete the form the run is waiting on
lemma workflows runs cancel <run-id>                            # cancel a running/waiting run

lemma schedules list
lemma schedules pause <id> ; lemma schedules resume <id>

A run in WAITING is paused on a human form, an agent conversation, an async function, or a timer — runs get shows which via active_wait (wait_type, node_id, assignee, external reference, and the form schema for human waits). If a form wait is assigned to you (runs waiting lists them), runs submit-form --data with the form's fields completes it and advances the run. This is how you participate in human-agent workflows.

Agents and chat

lemma agents list
lemma agents chat triage-agent "Summarize today's urgent tickets"   # interactive or one-shot
lemma agents run triage-agent "Classify this: ..."                  # waits + streams the result (--no-wait to detach)
lemma conversations list --agent triage-agent                       # an agent's runs (each run is a conversation)
lemma conversations messages <conversation-id>
lemma conversations send <conversation-id> "Continue with the next batch"

An agent acts under your delegated identity — it sees exactly what you'd see (your RLS rows, your /me, your connected accounts), plus only the resource grants its builder gave it.

First-party tools and connectors

First-party tools (no third-party account needed):

lemma tools list
lemma tools web-search "latest API docs" --limit 5
lemma tools connector-helper-agent "send tomorrow's calendar summary by email" --app googlecalendar --app gmail

Third-party connector operations — always check what's connected, then overview → search → details → execute. Never guess operation names or payloads:

lemma connectors overview                            # every configured app: auth-config NAME, provider, connected accounts
lemma connectors status                              # installed apps + your connected accounts
lemma connectors describe gmail                      # per-app usage guide (provider-aware)
lemma connectors operations search workspace-gmail "send email" --limit 5
lemma connectors operations details workspace-gmail GMAIL_SEND_EMAIL
lemma connectors operations execute workspace-gmail GMAIL_SEND_EMAIL \
  --data '{"payload": {"recipient_email": "a@b.com", "subject": "Hi", "body": "..."}}'

Operations are addressed by the auth-config name (the first column of connectors overview / auth-configs list), not the app id — and names differ per provider (LEMMA vs COMPOSIO), so overview is the one place to find the exact one to pass. Workloads execute operations via the invoking user's connected account (delegated) — they never touch raw credentials. If no account is connected, create a connect request and hand the link to the user: lemma connectors connect-requests create gmail --auth-config-id <id>. If the goal is clear but the operation isn't, ask connector-helper-agent first.

Workspace execution notes

  • Long-running processes (dev servers, watchers, REPLs): keep one persistent interactive session and reuse it; one-shot shell commands for everything else.
  • Local services are http://127.0.0.1:<port> inside the container; the shareable preview URL is https://port-<port>-${LEMMA_WORKSPACE_URL#https://} (workspace https://abc.lemma.work + port 3000 → https://port-3000-abc.lemma.work). Confirm the port is listening before sharing.
  • To keep web sources, use the browser skill's save-webpage <url> --formats markdown,pdf; upload durable artifacts to /me or a shared folder.
  • Network errors (Could not resolve host, ENOTFOUND, TLS timeouts): check curl -sS "$LEMMA_BASE_URL" once, retry once, then report — don't loop.

Troubleshooting

  • Row not visible / empty list / 404 on an RLS table. You only ever see your own rows — an absent row usually belongs to another member, not a missing record. Confirm with the owner or, if you have the admin role and the feature warrants it, the mode=ADMIN read path. Don't assume data loss.
  • Permission denied / resource not visible. As a human you may lack the pod role — they ladder up: POD_VIEWER reads; POD_USER also writes records and runs agents/functions/workflows; POD_EDITOR also creates/updates tables and writes files; POD_ADMIN also deletes and manages members. As an agent, MISSING_WORKLOAD_RESOURCE_GRANT names a missing workload grant — a builder must add it (it never silently grants itself).
  • Resource not found. Confirm the active pod (lemma pods list) and exact names (lemma pods describe).
  • ENUM rejected on a record write. Read lemma tables get <table> and use one of the listed options.
  • Fresh upload not in search. Indexing lag — files stat for status, retry shortly. NOT_REQUIRED means it isn't an indexed document (CSV/JSON/XLSX/images/ email are stored but never searchable).
  • Workflow stuck. runs get <run-id>active_wait shows what it's blocked on; step_history shows the failing node, its input, and error. A human wait needs runs submit-form.

See also

  • The model → lemma-builder/references/pod-model.md
  • Build/restructure a pod → the lemma-builder skill
  • Inline live views over pod data → the lemma-widget skill
  • Drive a browser / test a pod app → the browser skill
  • Local parsing/OCR of ad-hoc files → the liteparse-documents skill
用于创建轻量级内联 Lemma 小部件,展示结构化数据如指标、列表、图表等。通过 display_resource(type='WIDGET') 调用,支持纯 HTML/CSS/JS/SVG,避免使用 React 等重型框架,确保快速渲染与紧凑布局。
需要展示结构化或视觉层级丰富的答案(如多个值、记录、状态、时间线、图表) 需要将 Pod 数据以可视化形式嵌入对话,且不需要复杂交互或路由
lemma-skills/lemma-widget/SKILL.md
npx skills add lemma-work/lemma-platform --skill lemma-widget -g -y
SKILL.md
Frontmatter
{
    "name": "lemma-widget",
    "description": "Create lightweight inline Lemma widgets for conversations via display_resource(type=\"WIDGET\"): self-contained HTML\/CSS\/JS or SVG for metrics, lists, comparisons, timelines, record details, previews, and charts, optionally powered by live pod data through the browser Lemma SDK. Use an app, not a widget, when the UI needs React, routing, or substantial application state."
}

Lemma Widget

A widget is the default way to show an answer that is more than short prose. Use display_resource(type="WIDGET") whenever the useful result has structure or visual hierarchy: several values, records, statuses, steps, comparisons, a timeline, a compact table, a preview, or a chart.

Use plain text only for a single fact, a short explanation, or narration around the widget. If an existing FILE, TABLE, APP, or other pod resource already represents the answer, display that resource directly instead of recreating it as a widget.

Widget or app?

  • Widget: one compact inline view; plain HTML/CSS/JS or SVG; quick to render in the conversation; little local state.
  • Vite app: React, routing, multiple screens, reusable components, substantial interaction/state, or a UI people will return to as a product.

Do not load React, ReactDOM, Tailwind, or the agent web-component bundle inside a widget. Lemma already has full Vite app support for that class of UI. A widget may be saved as an HTML app later, but it should remain lightweight.

Widgets are display surfaces. They do not submit values into the conversation. Use ask_user for fixed choices or ask for free-form input in prose.

Build one

  1. If the widget uses pod data, inspect the real table and column names first:

    lemma pods describe
    lemma tables list
    lemma query run "select * from <table> limit 5"
    
  2. Load the closest maintained starter with load_skill, using name="lemma-widget" and one of these resource_path values:

    Answer shape Starter
    Metrics grouped by one field assets/widget-starter-v1.html
    Compact record list assets/widget-list-v1.html
    Bar chart grouped by one field assets/widget-chart-v1.html
    One record with selected fields assets/widget-detail-v1.html
  3. Replace every uppercase __PLACEHOLDER__ with inspected names and useful labels. For __FIELD_CONFIG__, insert a JSON array such as [{"label":"Owner","field":"owner"}].

  4. Adapt the content and styling, then call display_resource with type="WIDGET". Do not rebuild the SDK loader or loading/empty/error scaffolding from scratch.

The backend rejects unresolved placeholders and broken SDK loaders before display.

Fixed contract

  • Send an HTML/SVG fragment, never <!doctype>, <html>, <head>, or <body>.
  • Keep all CSS local. The widget runs in its own iframe and inherits no frontend CSS.
  • Use plain browser JavaScript. No build step, JSX, React, or framework runtime.
  • Never put secrets, credentials, a pod id, or an environment hostname in the HTML.
  • Show deliberate loading, empty, error, and narrow-screen states.
  • Escape values before inserting them with innerHTML; prefer textContent.
  • Keep the view compact: no fixed positioning or nested scrolling.

The starters are platform-themed and system-aware by default. Preserve their prefers-color-scheme: dark rules and semantic fallbacks. They consume the small public token layer --lemma-widget-bg, surface, subtle, text, muted, border, accent, danger, radius, font, and color-scheme (each with the full --lemma-widget- prefix). Chart starters also expose chart-1 through chart-5. Use only the tokens the widget needs; do not copy Lemma's full frontend token file. Never reference frontend-only variables such as --text-primary directly.

For a data-backed widget, preserve the starter's browser SDK loader:

  • Build the SDK URL from window.__LEMMA_CONFIG__.apiUrl.
  • Load /public/sdk/lemma-client.js dynamically and start in sdk.onload.
  • Construct new window.LemmaClient.LemmaClient() with no arguments.
  • Call client.initialize() and handle a non-authenticated state.
  • SDK calls run as the signed-in user under normal RLS and grants.
  • Shared files use /…; personal files use /me; never use /pod/....

Common calls:

await client.records.list("tickets", { limit: 50 });
await client.records.get("tickets", "record-id");
await client.datastore.query(
  "select status, count(*) as total from tickets group by status"
);
await client.files.search("quarterly planning", { limit: 10 });
await client.files.children.markdown("/knowledge/report.pdf");
await client.files.children.content(
  "/knowledge/report.pdf/pages/page_0001.jpg"
);

Prefer datastore.query for aggregates. Never poll with setInterval; if a widget must stay live, use client.datastore.watchChanges.

Visual standard

  • Lead with the answer, not a title-heavy dashboard shell.
  • Follow Lemma's neutral surfaces, near-black/near-white text, indigo action color, restrained borders, and compact radii unless the content needs a distinct visual language.
  • For a very small widget, the token-light set is just surface, text, muted, border, and accent.
  • Format numbers and dates for humans.
  • Use a list for repeated records, cards for a handful of metrics, a detail layout for one record, and a chart only when shape or comparison matters.
  • For Chart.js, give the canvas wrapper an explicit height and read chart/text/grid colors from the starter's semantic variables.
  • Keep explanation outside the widget in the assistant response.

Before display

  • The chosen view is genuinely more useful than short prose.
  • The closest versioned starter was used and all placeholders were replaced.
  • The fragment contains no full-document tags, secrets, hardcoded hosts, or pod ids.
  • SDK code uses injected config and boots from the script load handler.
  • Loading, empty, error, and mobile states are present.

For React or a full product UI, load lemma-builder and follow references/apps.md. For interaction-tool behavior, see lemma-builder/references/agent-tools.md.

使用LiteParse解析非Pod文件(如网页PDF、本地临时文件)或作为Pod文件转换失败的备用方案。支持提取文本、布局、OCR及截图,适用于PDF、Office文档等格式,用于在上传至Pod前的内容检查与结构化提取。
需要解析位于Pod外部的文档 Pod内文件的自动转换结果缺失或不完整 需要从扫描版PDF中提取OCR文字或布局信息 需要获取文档页面的截图进行视觉检查
lemma-skills/liteparse-documents/SKILL.md
npx skills add lemma-work/lemma-platform --skill liteparse-documents -g -y
SKILL.md
Frontmatter
{
    "name": "liteparse-documents",
    "description": "Use this skill to parse documents that live OUTSIDE the pod's file system — a PDF an agent fetched from the web, a local one-off, or any file you won't upload — or as a fallback when a pod file lacks its auto-produced markdown\/page-images. Extracts text, layout, bounding boxes, OCR, page screenshots, or structured output from PDF, DOCX, PPTX, XLSX, CSV, TSV, images, and other LiteParse formats. For documents that live in the pod, prefer the pod's built-in conversion\/search instead."
}

LiteParse Documents

Use LiteParse (lit) to parse documents that aren't in the pod — a PDF an agent pulled from the web, a local scratch file, anything you won't upload — when you need text, spatial layout, OCR, bounding boxes, or page screenshots. It's also the fallback for a pod file whose auto-produced markdown/page-images are missing or insufficient (scanned/OCR, bounding boxes). For a document that lives in (or is going into) the pod, prefer the pod's built-in conversion and search — see below.

When lit vs. the pod's built-in processing

Decide by where the document lives — that's the first question, not an afterthought:

  • It's a pod file (or going into the pod) → use the pod, not lit. lemma files upload <file> /knowledge/<name> and the pod auto-converts and indexes it: semantic+keyword search (lemma files search), page-marked markdown (lemma files cat --pages), rendered page images and figures (lemma files child …/pages/page_0001.jpg) — no local parsing. The pod is the RAG system; don't re-implement extraction for documents you're putting there. (See lemma-builder/references/files.md and the lemma-user skill.)
  • It's outside the pod, or the pod artifact is missing/insufficient → use lit. A PDF fetched from the web, a local file you won't upload, a scanned PDF needing OCR, bounding-box/layout extraction, or screenshotting pages to decide what's worth keeping — and the fallback when a pod file lacks its derived markdown/images. That's LiteParse's lane.

Common flow: lit screenshot or lit parse an outside file to inspect it, then lemma files upload the ones worth keeping so the pod converts and indexes them.

Tooling

The workspace image should provide:

  • lit from @llamaindex/liteparse
  • LibreOffice for Office document conversion
  • ImageMagick for image conversion
  • English Tesseract trained data at $TESSDATA_PREFIX

Check availability with:

lit --help

Workflow

  1. Identify the file type and the desired output: plain text, JSON with bounding boxes, or page screenshots.
  2. For searchable text or layout extraction, run lit parse.
  3. For visual inspection, charts, scans, handwriting, dense tables, or agent vision workflows, run lit screenshot.
  4. Save generated outputs beside the source file or in a clearly named working directory, then inspect the result before relying on it.
  5. When a file is scanned or image-heavy, keep OCR enabled. Use --no-ocr only when the user wants embedded text only or speed matters more than recall.

Common Commands

Parse to text:

lit parse input.pdf -o output.txt

Parse to JSON with bounding boxes:

lit parse input.pdf --format json -o output.json

Parse selected pages:

lit parse input.pdf --target-pages "1-5,10" --format json -o output.json

Parse Office documents or images:

lit parse input.docx --format json -o output.json
lit parse input.png --format json -o output.json

Generate screenshots:

lit screenshot input.pdf --target-pages "1-3" --dpi 200 -o screenshots

Batch parse a directory:

lit batch-parse input-directory output-directory --recursive --format json

Output Guidance

  • Use text output for quick reading, summarization, search, or simple extraction.
  • Use JSON when downstream code needs bounding boxes, page numbers, or structured blocks.
  • Use screenshots when text extraction may miss visual relationships, tables, signatures, charts, diagrams, or scanned content.
  • For large documents, start with --target-pages or --max-pages to avoid unnecessary processing.
  • Do not claim perfect table, handwriting, or chart extraction from LiteParse alone. For complex visual documents, combine screenshots with model vision or tell the user that a heavier parser may be needed.

Troubleshooting

  • If Office files fail to parse, verify LibreOffice is installed with libreoffice --version.
  • If image inputs fail, verify ImageMagick is installed with magick --version or convert --version.
  • If OCR needs another language, pass --ocr-language <lang> and ensure the matching .traineddata file exists in $TESSDATA_PREFIX.
  • If the document is password protected, use --password <password> only when the user has provided the password.

See also

  • Upload + the pod's auto-index/search/markdown/page-images → lemma-builder/references/files.md
  • Operate pod files from the CLI (search, cat, child, view-image) → the lemma-user skill

Home - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-22 00:25
浙ICP备14020137号-1 $Map of visitor$